Spring源码阅读(五)—AOP基础
Spring AOP是一种面向切面编程的实现,一般分为静态代理和动态代理.
静态代理是指在虚拟机启动的时候通过改变目标对象字节码的方式来完成对目标对象的增强,它比动态代理效率更高因为动态代理需要在调用的过程中需要动态的创建代理对象用来代替目标对象.
个人主页:tuzhenyu’s page
原文地址:Spring源码阅读(五)—AOP基础
一,AOP实现原理
Spring AOP的核心技术是JDK的动态代理技术。Spring AOP是以动态代理技术为基础,设计出了一系列AOP的横切实现,比如:前置增强、返回增强、异常增强等等。
Spring AOP的具体实现步骤包括:先是生成代理对象,拦截器拦截切点方法,增强与源代码的编织.
Spring AOP的动态代理主要分为JDK动态代理和CGLIB动态代理.
二,代理类型
(1)JDK动态代理
JDK动态代理的步骤:
创建被代理的类以及接口
创建一个实现接口InvocationHandler的类,必须实现invoke方法以实现代理逻辑
通过Proxy的静态方法newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理
通过代理调用方法
JDK动态代理实现的原理是:调用newProxyInstance()会生成一个新的代理类,它继承自Proxy接口并实现了我们定义的接口Subject.在实现Subject接口内部的方法时候通过反射调用了InvocationHandler类的invoke()方法,进而实现JDK动态代理
JDK动态代理只能代理接口,不支持类的代理;原因就是实现的代理类只实现了Subject接口没有继承类没有类的方法,因此只能代理接口不能代理类.
JDK动态代理具体实现
- 代理目标接口
public interface ForumService {
public void addTopic();
public void removeTopic();
}
- 代理目标实现类
public class ForumServiceImpl implements ForumService {
public void addTopic(){
System.out.println("in the addTopic");
}
public void removeTopic(){
System.out.println("in the removeTopic");
}
}
- 代理横切织入代码
public class PerformanceHandler implements InvocationHandler{
private Object target;
public PerformanceHandler(Object target){
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
System.out.println("begin monitor...");
Object obj = method.invoke(target,args);
System.out.println("end monitor...");
return obj;
}
}
- 代理横测试类
public class Main {
public static void main(String[] args) {
ForumService target = new ForumServiceImpl();
PerformanceHandler handler = new PerformanceHandler(target);
ForumService proxy = (ForumService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler
);
proxy.addTopic();
proxy.removeTopic();
}
}
(2)CGLib动态代理
CGlib是一种代码生成包,可以用来在运行期间拓展Java类和实现Java接口
CGLib动态代理的步骤
创建被代理的类以及接口
实现MethodInterceptor接口,定义方法的拦截器
利用Enhancer类生成代理类;
CGLib动态代理实现原理:Enhancer是CGLib的字节码增强器,生成代理类继承被委托类,并且委托类的final方法不能被代理.当执行代理类的方法时候会调用intercept()方法.
CGLib动态代理具体实现
- 代理目标实现类
public class ForumServiceImpl implements ForumService {
public void addTopic(){
System.out.println("in the addTopic");
}
public void removeTopic(){
System.out.println("in the removeTopic");
}
}
- 代理横切织入代码
public class CglibProxy implements MethodInterceptor{
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable{
System.out.println("start monitor...");
Object result = proxy.invokeSuper(obj,args);
System.out.println("end monitor...");
return result;
}
}
- 代理横测试类
public class Main {
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
ForumServiceImpl forumService = (ForumServiceImpl)proxy.getProxy(ForumServiceImpl.class);
forumService.addTopic();
forumService.removeTopic();
}
}
(3) JDK动态代理和CGLIB动态代理的区别
jdk动态代理生成的代理类和委托类实现了相同的接口;
cglib动态代理中生成的字节码更加复杂,生成的代理类是委托类的子类,且不能处理被final关键字修饰的方法;
jdk采用反射机制调用委托类的方法,cglib采用类似索引的方式直接调用委托类方法;
三,AOP增强类型
- 前置增强类:MethodBeforeAdvice
在一个连接点之前执行的增强,但这个增强不能阻止流程继续执行到连接点(除非它抛出一个异常)。
- 后置增强类:AfterReturningAdvice
在连接点正常完成后执行的增强,例如,如果一个正常返回,没有抛出异常。如果抛出异常则不会执行。
- 环绕增强:MethodInterceptor
包围一个连接点的增强,如方法调用,是最强大的增强。在方法调用前后完成自定义的行为。它们负责选择继续执行连接点或直接返回它们自己的返回值或抛出异常来执行。
- 异常抛出增强:ThrowsAdvice
是最常用的增强类型。大部分是基于拦截器框架如Nanning或者JBoss4提供的Around增强。作用是,不管,是否正常执行,都会返回增强中的内容。
- 引介增强:DelegatingIntroductionInterceptor
一种非常特殊的增强。它将新的成员变量、成员方法引入到目标类中。它仅能作用于类层次,而不是方法层次,所以他不能作用于任何切入点。