Spring AOP的动态代理有两种:一是JDK的动态代理;另一个是cglib动态代理(通过修改字节码来实现代理)。
今天主要讨论JDK动态代理的方式。
JDK的代理方式主要就是通过反射跟动态编译来实现的,主要实现InvocationHandler接口和生成Proxy对象。
(1)定义AOP切面,实现InvocationHandler接口
(里面重载invoke方法,虚拟机自动调用此方法)
(2)创建代理类(通过java API)
假设被代理的类为Tagert,则
Target t = (Target)Proxy.newProxyInstance(字节码加载器, 需要代理的接口, 切面Advice);
请看demo:
public interface IBusiness {
public void doBusiness();
}
public class Business implements IBusiness {
public void doBusiness() {
System.out.println("执行业务逻辑");
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxyDemo {
public static void main(String[] args) {
// 需要代理的接口,被代理类实现的多个接口都必须在这里定义
Class[] proxyInterface = new Class[] { IBusiness.class};
// 构建AOP的Advice,这里需要传入业务类的实例
LogInvocationHandler handler = new LogInvocationHandler(new Business());
// 生成代理类的字节码加载器
ClassLoader classLoader = DynamicProxyDemo.class.getClassLoader();
// 织入器,织入代码并生成代理类
IBusiness proxyBusiness = (IBusiness) Proxy.newProxyInstance(
classLoader, proxyInterface, handler);
// 使用代理类的实例来调用方法。
((IBusiness) proxyBusiness).doBusiness();
}
/**
* 打印日志的切面
*/
public static class LogInvocationHandler implements InvocationHandler {
private Object target; // 目标对象
LogInvocationHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 执行原有逻辑
Object rev = method.invoke(target, args);
// 执行织入的日志,你可以控制哪些方法执行切入逻辑
if (method.getName().equals("doBusiness")) {
System.out.println("记录日志");
}
return rev;
}
}
}
输出结果为:
执行业务逻辑
记录日志
可以看出,目标对象作为代理对象的一个属性,具体接口实现中,可以在调用目标对象相应方法前后加上其他业务处理逻辑。
一些知识:
1、静态代理和动态代理代理的区别:
静态代理:事先写好代理对象类,在程序发布前就已经存在了。
动态代理:应用程序发布后,通过动态创建代理对象。
2、JDK动态代理和CGLIB代理生成的区别
JDK动态代理只能对实现了接口的类生成代理。
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 。因为是继承,所以该类或方法最好不要声明成final ,final可以阻止继承和多态。