AOP的实现有三种方式:

l         aop底层将采用代理机制进行实现。

l         接口 + 实现类 :spring采用 jdk 的动态代理Proxy。

l         实现类:spring 采用 cglib字节码增强。

一.手工方式

1.JDK动态代理

JDK动态代理 对“装饰者”设计模式 简化。使用前提:必须有接口

1.目标类:接口 + 实现类

2.切面类:用于存通知 MyAspect

3.工厂类:编写工厂生成代理

4.测试

1.目标类

UserService.java

package com.zk.a_jdk;

public interface UserService {
public void addUser();
public void updateUser();
public void deleteUser();
}

UserServiceImpl.java

package com.zk.a_jdk;

public class UserServiceImpl implements UserService{

	@Override
public void addUser() {
// TODO Auto-generated method stub
System.out.println("proxy addUser");
} @Override
public void updateUser() {
// TODO Auto-generated method stub
System.out.println("proxy updateUser");
} @Override
public void deleteUser() {
// TODO Auto-generated method stub
System.out.println("proxy deleteUser");
} }

2.切面类

MyAspect.java

package com.zk.a_jdk;

public class MyAspect {

	public void before(){
System.out.println("鸡头");
} public void after(){
System.out.println("牛后");
}
}

3.工厂

package com.zk.a_jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class MyBeanFactory {
//手工代理
public static UserService createService(){
//1.目标类
final UserService userservice=new UserServiceImpl();
//2.切面类
final MyAspect myAspect=new MyAspect();
//3.代理类:将目标类(切入点)和切面类(通知)结合-->切面
//Proxy.newProxyInstance
/*
* 参数一:loader类加载器,动态代理类,运行时创建,任何类都需要类加载器将其加载至内存。
* 一般情况下:当前类,class.getClassLoader();
* 目标类实例:getClass().get...
* 参数二:interfaces,代理类需要实现的所有接口
* 方式一:目标类实例.getClass().getInterfaces();注意:只能获得自己的接口,获得不到父元素的接口
* 方式二:new Class[]{UserService.class}
* 例如:jdbc驱动
* 参数三:InvocationHandler 处理类,接口,必须进行实现类,一般采用匿名内部类
* 提供invoke方法,代理类每一个方法执行时,都将去调用invoke
* 参数三.1.Object proxy代理对象
* 参数三.2.Method method 代理对象当前方法的描述对象(反射)
* 执行方法方法名:method.getName();
* 执行方法:method.invoke(对象,实际参数)
* 参数三.3 Object[] args 方法实际参数
*/
UserService proxyService=(UserService)Proxy.newProxyInstance
(MyBeanFactory.class.getClassLoader(),
userservice.getClass().getInterfaces(), new InvocationHandler(){ @Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
// TODO Auto-generated method stub //前执行
myAspect.before();
//执行目标类的方法
Object obj=method.invoke(userservice, args); //后执行
myAspect.after(); return null;
}
});
return proxyService;
}
}

4.测试类

package com.zk.a_jdk;

import org.junit.Test;

public class TestJDK {

	@Test
public void test(){
UserService userservice=MyBeanFactory.createService();
userservice.addUser();
userservice.deleteUser();
userservice.updateUser();
}
}

运行效果:

2.  CGLIB字节码增强

l         没有接口,只有实现类。

l         采用字节码增强框架 cglib,在运行时 创建目标类的子类,从而对目标类进行增强。

l         导入jar包:

1.目标类

UserService.java

package com.zk.a_jdk;

public interface UserService {
public void addUser();
public void updateUser();
public void deleteUser();
}

UserServiceImpl.java

package com.zk.a_jdk;

public class UserServiceImpl implements UserService{

	@Override
public void addUser() {
// TODO Auto-generated method stub
System.out.println("proxy addUser");
} @Override
public void updateUser() {
// TODO Auto-generated method stub
System.out.println("proxy updateUser");
} @Override
public void deleteUser() {
// TODO Auto-generated method stub
System.out.println("proxy deleteUser");
} }

2.切面类

MyAspect.java

package com.zk.a_jdk;

public class MyAspect {

	public void before(){
System.out.println("鸡头");
} public void after(){
System.out.println("牛后");
}
}

3.MyBeanFactory.java工厂类

package com.zk.b_cglib;

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy; public class MyBeanFactory {
//手工代理
public static UserService createService(){
//1.目标类
final UserServiceImpl userservice=new UserServiceImpl();
//2.切面类
final MyAspect myAspect=new MyAspect();
/*3.代理类
* 采用字节码增强框架-cglib,程序运行时创建目标类的子类,从而对目标类进行增强
* 导入jar包
* intercept等效于jdk中invoke方法
* 参数一二三 与invoke相同
* 参数四方法的代理
*/
Enhancer enhance=new Enhancer();
//确定父类
enhance.setSuperclass(userservice.getClass());
enhance.setCallback(new MethodInterceptor(){
//设置回调函数,MethodInterceptor接口等效 jdk InvocationHandler接口
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodproxy) throws Throwable {
// TODO Auto-generated method stub
//前before
myAspect.before();
//执行目标类的方法
Object obj=method.invoke(userservice, args);
//执行代理类的父类
methodproxy.invokeSuper(proxy, args);
//后after
myAspect.after();
return null;
} });
//创建代理
UserServiceImpl proxyservice=(UserServiceImpl) enhance.create();
return proxyservice;
}
}

4.TestCglib.java测试

package com.zk.b_cglib;

import org.junit.Test;

public class Testcglib {

	@Test
public void test(){
UserService userservice=MyBeanFactory.createService();
userservice.addUser();
userservice.deleteUser();
userservice.updateUser();
}
}

运行效果图:

二.半自动方式

让spring 创建代理对象,从spring容器中手动的获取代理对象。

导入jar包:

AOP:AOP联盟(规范)、spring-aop (实现)

1.目标类

UserService.java

public interface UserService {
public void addUser();
public void updateUser();
public void deleteUser();
}

UserServiceImpl.java

package com.zk.springAop;

public class UserServiceImpl implements UserService{

	@Override
public void addUser() {
// TODO Auto-generated method stub
System.out.println("addUser");
} @Override
public void updateUser() {
// TODO Auto-generated method stub
System.out.println("updateUser");
} @Override
public void deleteUser() {
// TODO Auto-generated method stub
System.out.println("deleteUser");
} }

2.切面类

/**
* 切面类中确定通知,需要实现不同接口,接口就是规范,从而就确定方法名称。
* * 采用“环绕通知” MethodInterceptor
*
*/
public class MyAspect implements MethodInterceptor { @Override
public Object invoke(MethodInvocation mi) throws Throwable { System.out.println("前3"); //手动执行目标方法
Object obj = mi.proceed(); System.out.println("后3");
return obj;
}
}

3.spring配置

<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
">
<!-- 创建目标类 -->
<bean id="userserviceid" class="com.zk.factorybean.UserServiceImpl"></bean> <!-- 创建切面类 -->
<bean id="aspectid" class="com.zk.factorybean.MyAspect"></bean> <!-- 创建代理类
使用工厂bean factorybean,底层调用getObject(), 返回特殊bean
ProxyBeanFactory用于创建代理工厂bean,生成特殊代理对象
interface确定接口
通过Array确定多个值
只有一个值时,value=""
target确定目标类
interceptorNames:通知切面类名称,类型String[],如果设置一个值, value=""
optimize:强制使用cglib
<property name="optimized value="true"></property>
底层机制:
如果目标类有接口,采用jdk代理
如果没有接口,采用cglib代理
如果声明式optimize=true,都使用cglib
-->
<bean id="proxyServiceid" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces" value="com.zk.factorybean.UserService"></property>
<property name="target" ref="userserviceid"></property>
<property name="interceptorNames" value="aspectid"></property>
</bean>
</beans>

  

4.Testfactorybean.java

package com.zk.factorybean;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class Testfactorybean { @Test
public void test(){
String path="com/zk/factorybean/ApplicationContext.xml";
ApplicationContext ac=new ClassPathXmlApplicationContext(path);
UserService userservice=(UserService) ac.getBean("proxyServiceid");
userservice.addUser();
userservice.deleteUser();
userservice.updateUser();
}
}

  

运行效果:

三.spring aop编程:全自动

从spring容器获得目标类,如果配置aop,spring将自动生成代理。

要确定目标类,aspectj 切入点表达式,导入jar包spring-framework-3.0.2.RELEASE-dependencies\org.aspectj\com.springsource.org.aspectj.weaver\1.6.8.RELEASE

1.目标类

UserService.java

public interface UserService {
public void addUser();
public void updateUser();
public void deleteUser();
}

UserServiceImpl.java

package com.zk.springAop;

public class UserServiceImpl implements UserService{

	@Override
public void addUser() {
// TODO Auto-generated method stub
System.out.println("addUser");
} @Override
public void updateUser() {
// TODO Auto-generated method stub
System.out.println("updateUser");
} @Override
public void deleteUser() {
// TODO Auto-generated method stub
System.out.println("deleteUser");
} }

2.切面类

/**
* 切面类中确定通知,需要实现不同接口,接口就是规范,从而就确定方法名称。
* * 采用“环绕通知” MethodInterceptor
*
*/
public class MyAspect implements MethodInterceptor { @Override
public Object invoke(MethodInvocation mi) throws Throwable { System.out.println("前3"); //手动执行目标方法
Object obj = mi.proceed(); System.out.println("后3");
return obj;
}
}

3.spring配置

<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!-- 创建目标类 -->
<bean id="userserviceid" class="com.zk.springAop.UserServiceImpl"></bean> <!-- 创建切面类 -->
<bean id="aspectid" class="com.zk.springAop.MyAspect"></bean> <!-- Aop编程
1.导入命名空间
2.使用<aop:config>进行配置
proxy-target-class="true"声明是使用cglib代理
<aop:pointcut>:切入点,从目标对象上获取具体的方法
<aop:advisor>特殊的切面,只有一个通知和一个切入点
advise-ref 通知引用
pointcut-ref 切入点引用
advisor通知
3.切入点表达式
execution(* com.zk.springAop.*.*(..))
选择方法 *表示返回值任意 包 类名任意. 方法名任意 . 参数任意 .
-->
<aop:config>
<aop:pointcut expression="execution(* com.zk.springAop.*.*(..))" id="myPointCut"/>
<aop:advisor advice-ref="aspectid" pointcut-ref="myPointCut"/>
</aop:config>
</beans>

  

Spring AOP编程(二)-AOP实现的三种方式的更多相关文章

  1. Spring的依赖注入(DI)三种方式

    Spring依赖注入(DI)的三种方式,分别为: 1.  接口注入 2.  Setter方法注入 3.  构造方法注入 下面介绍一下这三种依赖注入在Spring中是怎么样实现的. 首先我们需要以下几个 ...

  2. spring学习(03)之bean实例化的三种方式

    bean实体例化的三种方式 在spring中有三中实例化bean的方式: 一.使用构造器实例化:(通常使用的一个方法,重点) 二.使用静态工厂方法实例化: 三.使用实例化工厂方法实例化 第一种.使用构 ...

  3. Spring bean管理器 bean实例化的三种方式

    bean实例化的三种方式实现 第一种:使用类的无参数构造方法创建(常用 重要) 第一种实例化方式最常用,实例化类时会通过调用无参构造方法创建.示例代码如下: package spring.com.Us ...

  4. Struts2(二)action的三种方式

    一.普通java类 package com.pb.web.action; /* * 创建普通的java类 */ public class HelloAction1 { public String ex ...

  5. Spring管理的bean初始化方法的三种方式,以及@PostConstruct不起作用的原因

    1:Spring 容器中的 Bean 是有生命周期的,spring 允许 Bean 在初始化完成后以及销毁前执行特定的操作.下面是常用的三种指定特定操作的方法: 通过实现InitializingBea ...

  6. Spring:Spring-IOC实例化bean的常用三种方式

    Spring容器提供了三种对bean的实例化方式: 1)构造器实例化 public class Demo { private String name; //getter和setter方法略 } < ...

  7. 【spring】 SpringMVC返回json数据的三种方式

    配置方法一 **1.导入第三方的jackson包,jackson-mapper-asl-1.9.7.jar和jackson-core-asl-1.9.7.jar. 2.spring配置文件添加** & ...

  8. Spring学习(五)-----注入bean属性的三种方式( 1: 正常的方式 2: 快捷方式 3: “p” 模式)

    在Spring中,有三种方式注入值到 bean 属性. 正常的方式 快捷方式 “p” 模式 看到一个简单的Java类,它包含两个属性 - name 和 type.稍后将使用Spring注入值到这个 b ...

  9. SSH深度历险记(八) 剖析SSH核心原则+Spring依赖注入的三种方式

           于java发育.一类程序猿必须依靠类的其他方法,它是通常new依赖类的方法,然后调用类的实例,这样的发展问题new良好的班统一管理的例子.spring提出了依赖注入的思想,即依赖类不由程 ...

随机推荐

  1. C#调用WSDL接口

    http://www.cnblogs.com/wlming/p/8032782.html

  2. SSM项目集成Lucene+IKAnalyzer在Junit单元测试中执行异常

    个人博客 地址:http://www.wenhaofan.com/article/20181108132519 问题描述 在项目运行以及main方法中能够正常运行,但是使用junit单元测试时却报如下 ...

  3. ROS2GO 与WIN10 双系统安装

    关于ROS2GO的一些心得: 我是一个ROS的探索者,在接触ROS一段时间后,意外发现了一个关于ROS2GO的信息,是天之博特的微信公众号发表的.简单来说ROS2GO就是一个装了ROS的Ubuntu系 ...

  4. pandas处理csv,分组统计

    需求: /tmp/demo/data下有10个csv文件,按col0和col1分组分别统计col2和col3总和并计算col2和col3的商 # encoding:utf-8 import panda ...

  5. Goland安装与配置

    前言 工欲善其事必先利其器,学习Go语言同样如此,一个强大的集成开发环境(IDE)能够大大提高我们的开发效率,目前市面上比较流行的有下面这几种: GoLand:由 JetBrains 公司开发的一个新 ...

  6. js中迭代方法

    基础遍历数组:            for()            for( in )             for(var i = 0;i<arr.length;i++){       ...

  7. cmake编译升级

    cmake的升级依赖于gcc版本,例如cmake 3.15.3依赖与gcc 4.8以上的版本 1)先升级gcc到4.8 参考:https://blog.csdn.net/Kangshuo2471781 ...

  8. [HNOI2017] 礼物 - 多项式乘法FFT

    题意:给定两个 \(n\) 元环,环上每个点有权值,分别为 \(x_i, y_i\).定义两个环的差值为 \[\sum_{i=0}^{n-1}{(x_i-y_i)^2}\] 可以旋转其中的一个环,或者 ...

  9. HTML5使用JavaScript控制<audio>音频的播放

    1.播放音乐最简单的样例 <audio controls> <source src="horse.mp3" type="audio/mpeg" ...

  10. bbs论坛登录相关功能(2)

    昨天把注册功能页面做出来,接下来就是登录页面 登录功能: 1,用户账号,密码后台效验,错误信息在登录按钮右边显示 2.验证码,根据图片生成,点击图片刷新产生新的验证码 修改密码 注册 先把前端页面lo ...