Spring AOP的实现原理?
动态代理:
1、JDK动态代理(基于接口的动态代理—对对象进行代理)
2、Cglib动态代理(基于子类的动态代理—对类进行代理)
JDK的动态代理机制只能代理实现了接口的类,而没有实现接口的类不能实现JDK的动态代理
1、JDK动态代理
public interface ProducerDao {
//销售
public void saleProduce(int money);
//售后
public void afterService(int money);
}
public class ProducerDaoImpl implements ProducerDao {
@Override
public void saleProduce(int money) {
System.out.println("销售商品,并拿到钱"+money);
}
@Override
public void afterService(int money) {
System.out.println("提供售后服务,并拿到钱"+money);
}
}
public class MyInvocationHandler implements InvocationHandler {
//被代理对象
Object target;
//通过构造方法传入被代理对象
public MyInvocationHandler(Object target) {
this.target = target;
}
/**
* @param proxy 被代理对象
* @param method 目标对象中的方法对象
* @param args 方法对象的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理之前");
代理对象调用哪个方法,method就代表哪个方法对象
Object result = method.invoke(target, args);
System.out.println("代理之后");
return result;
}
}
public class Test {
public static void main(String[] args) {
//被代理对象
ProducerDao producerDao = new ProducerDaoImpl();
//获取代理对象,返回的类型是接口类型
ProducerDao proxy = (ProducerDao)Proxy.newProxyInstance(
ProducerDaoImpl.class.getClassLoader(),
ProducerDaoImpl.class.getInterfaces(),
new MyInvocationHandler(producerDao));
//通过代理对象调用saleProduce()方法
proxy.saleProduce(300);
}
}
结果:
代理之前
销售商品,并拿到钱300
代理之后
2、Cglib动态代理
cglib:code generator library,代码生成库可以动态的生成字节码对象,可以凭空创建一个字节码对象(.class)
CGLib采用了非常底层的字节码技术,其原理是动态生成一个要代理类的子类,子类重写要代理类的所有的不是final类的方法,在子类中采用方法拦截的技术拦截所有父类的方法调用并顺势植入横切逻辑,比使用jdk代理速度要快,性能要高,底层使用了字节码处理框架ASM,转换字节码并生成新的类,对final类和final方法无法代理。
Cglib代理,也称作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展
public class Student {
public void study(){
System.out.println("我还在学习");
}
}
public class CallbackMethod implements MethodInterceptor {
/**
* @param proxy 代理对象
* @param method 目标对象中的方法
* @param args 目标对象方法的参数
* @param methodProxy 代理对象中的代理方法对象
*/
@Override
public Object intercept(Object proxy, Method method,
Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("代理前");
//执行被拦截的方法
Object result = methodProxy.invokeSuper(proxy, args);
System.out.println("代理后");
return result;
}
}
public class Test1 {
public static void main(String[] args) {
//生成字节码对象
Enhancer en = new Enhancer();
//设置父类为Student类
en.setSuperclass(Student.class);
//设置回调函数,在回调函数实现增强
Callback callback = new CallbackMethod();
en.setCallback(callback);
//使用代理类得到代理对象
Student obj = (Student)en.create();
obj.study();
}
}
在Spirng当中动态代理的使用:
Spring AOP部分使用JDK动态代理或者CGLIB来为目标对象创建代理。(建议尽量使用JDK的动态代理),如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理。所有该目标类型实现的接口都将被代理。若该目标对象没有实现任何接口,则创建一个CGLIB代理。如果你希望强制使用CGLIB代理,(例如希望代理目标对象的所有方法,而不只是实现自接口的方法)那也可以。但是需要考虑以下两个问题。
◆ 无法通知(advise)Final方法,因为它们不能被覆写。
◆ 你需要将CGLIB二进制发行包放在classpath下面。