实现原理:
Spring AOP的两种实现方式
关于动态代理和CGLIB这两种方式的简要总结如下:
· JDK动态代理(Dynamic Proxy)
· 基于标准JDK的动态代理功能
· 只针对实现了接口的业务对象
· CGLIB
· 通过动态地对目标对象进行子类化来实现AOP代理,上面截图中的SampleBean$$EnhancerByCGLIB$$1767dd4b即为动态创建的一个子类
· 需要指定@EnableAspectJAutoProxy(proxyTargetClass = true)来强制使用
· 当业务对象没有实现任何接口的时候默认会选择CGLIB
JDKProxy:
如果是面向接口的动态代理的实现,即JDKProxy,其代理对象必须是某个接口的实现,使用java.lang.reflect.Proxy类根据一个被代理对象产生一个代理对象userDAOProxy,通过Proxy类的调用静态方法newProxyInstance,根据要实现的接口来产生(这里为UserDao接口)(也就是说接口里面有哪些方法,我生成的代理里面就有哪些方法);以及实现java.lang.reflect.InvocationHandler接口,实现invoke方法实现方法的截获处理,也就是在方法的前后加上业务逻辑。
当你想在多个方法前后加上业务逻辑的时候,可以使用动态代理,更加灵活方便,代码的可重用性大大的提高。
根据一个被代理对象通过Proxy静态方法newProxyInstance产生代理对象:
newProxyInstance里面的参数解释:
第一个参数是说与被代理对象有同一个ClassLoader,
第二个参数说产生的代理对象实现的那个接口应该与被代理对象实现同一个接口(UserDao),也可以这样写new Class[]{UserDao.class}。
第三个参数:当产生代理之后,调用代理里面的方法后要用哪个Handler进行处理。
LogIntercepter li = new LogIntercepter();
li.setTarget(userDAO);//引入一个被代理的对象userDAO
UserDao userDAOProxy = (UserDao) Proxy.newProxyInstance(userDAO.getClass().getClassLoader(),userDAO.getClass().getInterfaces(), li);
实现InvocationHandler接口 :
public Object invoke(Object proxy, Method m, Object[] args)
throws Throwable {
beforeMethod();//在方法前面添加业务逻辑,也就是日志
m.invoke(target, args);//target Method方法所属的对象,表示被代理对象动态调用invoke()
return null;
}
CGLibProxy:
如果没有实现接口,也没有关系,可以用CGLib(面向Class)实现AOP。
CGLibProxy与JDKProxy的代理机制基本类似,只是其动态代理的代理对象并非某个接口的实现,而是针对目标类扩展的子类。话句话说JDKProxy返回动态代理类,是目标类所实现接口的另一个实现版本,它实现了对目标类的代理(如同UserDAOProxy与UserDAOImp的关系),而CGLibProxy返回的动态代理类,则是目标代理类的一个子类(代理类扩展了UserDaoImpl类)
Enhancer和MethodInterceptor在CGLib中负责完成代理对象创建和方法截获处理。
Enhancer创建代理对象,实现MethodInterceptor接口,实现intercept方法来进行方法截取处理。
(CGLib (Code Generation Library) 字节码类库是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。Hibernate用它来实现PO字节码的动态生成。CGLib 比 Java 的 java.lang.reflect.Proxy 类更强的在于它不仅可以接管接口类的方法,还可以接管普通类的方法。)
JDK动态代理和CGLIB字节码生成的区别:
* JDK动态代理只能对实现了接口的类生成代理,而不能针对类.
* CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
因为是继承,所以该类或方法最好不要声明成final。
JDK代理是不需要以来第三方的库,只要JDK环境就可以进行代理,它有几个要求
* 实现InvocationHandler
* 使用Proxy.newProxyInstance产生代理对象
* 被代理的对象必须要实现接口
CGLib 必须依赖于CGLib的类库,但是它需要类来实现任何接口代理的是指定的类生成一个子类,覆盖其中的方法,是一种继承
AOP的应用:
做权限的检查:设计完备的权限管理组件,完成以往需要大费周折才能完成的权限判定功能。
但是目前还没有一个完善的实现,一方面是因为权限检查过于复杂多变,不同的业务逻辑中的权限判定逻辑可能多种多样;另一方面,就目前的AOP应用的粒度而言,“权限管理”作为一个切面显得过于庞大,需要进一步设计,设计复杂,实现难度大。
,做日志,做审计,做性能,做事务的处理。项目里面主要用在了声明式的事务处理上。
Spring AOP的工作原理: