设计模式-代理模式
学习Spring的AOP原理的时候,应该都会了解到Spring AOP的底层原理其实就是使用动态代理的方式实现业务逻辑的横向切入,本文主要是以代码实现的方式逐步介绍三种代理模式,从而帮助大家更好的理解AOP的实现原理:
静态代理:代理类与被代理类需要实现共同的接口
JDK动态代理:被代理类需要实现接口,动态代理对象需要通过接口使用反射的方式拿到”方法组”
CGLIB动态代理):被代理类不需要实现接口,代理类是通过继承的方式实现代理
一、静态代理
/**
* 代理类与被代理类都实现该接口
*/
public interface A_interface {
public void method1();
}
/** * 被代理类 */ public class B_Source implements A_interface{ @Override public void method1() { System.out.println("原始方法"); } }
/** * 代理类,与被代理类组合关系,并实现共同接口 */ public class C_Proxy implements A_interface { private B_Source source = new B_Source(); @Override public void method1() { System.out.println("静态代理开始前"); source.method1(); System.out.println("静态代理结束后"); } }
结果: 静态代理开始前 原始方法 静态代理结束后
二、JDK动态代理
/** * 被代理类要实现的接口 */ public interface A_interface { public void method1(); }
/** * 被代理类 */ public class B_Source implements A_interface { @Override public void method1() { System.out.println("原始方法"); } }
/** * Handler类,即代理业务逻辑 */ public class C_MyInvocationHandler<T> implements InvocationHandler { //被代理对象 private T object; public C_MyInvocationHandler(T object){ this.object = object; } /** * @param proxy:动态代理对象 * @param method:正在执行的方法 * @param args:调用目标方法时传入的实参 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("jdk动态代理开始前"); Object result = method.invoke(object,args); System.out.println("jdk动态代理结束后"); return result; } }
/** * jdk动态代理测试类,被代理类需要实现接口 * Proxy.newProxyInstance传递的3个参数意义如下 * 参数1:被代理类的类加载器 * 参数2:被代理类实现的接口(目的为拿到所有方法,然后遍历通过反射逐个调用) * 参数3:Handler对象 */ public class D_Test { public static void main(String[] args) { //创建被代理对象 A_interface source = new B_Source(); //创建与代理对象相关的Handler InvocationHandler sourceHandler = new C_MyInvocationHandler<>(source); //创建动态代理对象,被代理对象实现接口的所有方法的执行都会被Handler处理 A_interface proxy = (A_interface) Proxy.newProxyInstance( A_interface.class.getClassLoader(), new Class<?>[]{A_interface.class}, sourceHandler); proxy.method1(); } }
结果: jdk动态代理开始前 原始方法 jdk动态代理结束后
三、CGLIB动态代理
/** * 被代理类 */ public class B_Source { public void method(){ System.out.println("原始方法"); } }
/** * cglib是通过继承方式实现动态代理的,被代理类不需要实现接口 */ public class C_Proxy implements MethodInterceptor { //通过Enhancer创建代理对象 private Enhancer enhancer = new Enhancer(); //通过Class对象获取代理对象 public Object getProxy(Class c){ enhancer.setSuperclass(c); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("cglib动态代理开始前"); Object result = methodProxy.invokeSuper(o,objects); System.out.println("cglib动态代理结束后"); return result; } }
/** * 测试类 */ public class D_Test { public static void main(String[] args) { C_Proxy proxy = new C_Proxy(); B_Source source_proxy = (B_Source) proxy.getProxy(B_Source.class); source_proxy.method(); } }
结果: cglib动态代理开始前 原始方法 cglib动态代理结束后
四、总结
静态代理:实现逻辑简单,这里就不多说了
jdk动态代理:对于JDK实现的动态代理,需要依赖jdk反射包下的接口InvocationHandler以及代理类Proxy,首先自定义一个Handler类实现InvocationHandler接口,完成自定义的代理逻辑,然后在创建动态代理对象的时候将被代理对象的类加载器、被代理对象实现的接口、自定义Handler对象传递进去后从而在程序运行时通过反射动态的创建代理对象而不必像静态代理方式写死代理类(jdk动态代理的模拟)
cglib动态代理:cglib是一个高效、高性能的代码生成类库,可以在程序运行时动态的生成字节码,其实动态代理的大致原理是cglib继承被代理类,重写方法,织入代理逻辑,动态生成字节码并运行,需要注意的是,若一个类被声明为final则无法使用cglib动态代理,原因是final类并不能被继承。