代理模式是一种使用代理对象来执行目标对象的方法并在代理对象中加强目标对象方法的一种设计模式。html
使用代理模式的缘由有:java
代理能够分为静态代理和动态代理,前者更接近代理模式的本质。程序员
本节根据场景和实现的不一样,依次介绍静态代理、JDK动态代理、Cglib动态代理(也称子类代理)以及Spring AOP代理。spring
静态代理:在程序运行前就已经存在代理类的字节码文件。数据库
示例代码以下:apache
// 共同接口 // public interface ISubject { void doAction(); void byebye(); } // 真实对象(委托类) // public class RealSubject implements ISubject { @Override public void doAction() { System.out.println("Real Action Here!"); } @Override public void byebye() { System.out.println("Wave goodbye!"); } } // 代理对象(代理类) // public class SubjectProxy implements ISubject { private ISubject subject; public SubjectProxy() { // RealSubject实例可根据环境变量、配置等建立不一样类型的实例(多态) subject = new RealSubject(); // 此处仅简单地new实例 } @Override public void doAction() { System.out.println(">> doWhatever start"); // 扩展进行额外的功能操做(如鉴权、计时、日志等) subject.doAction(); System.out.println("doWhatever end <<"); // 扩展进行额外的功能操做(如鉴权、计时、日志等) } @Override public void byebye() { System.out.println("Say goodbye"); // 改变委托类行为(例如实现数据库链接池时避免close关闭链接) } } // 验证代码 // public class StaticProxyDemo { public static void main(String[] args) { SubjectProxy subject = new SubjectProxy(); subject.doAction(); subject.byebye(); } }
执行结果以下:设计模式
>> doWhatever start Real Action Here! doWhatever end << Say goodbye
静态代理的特色以下:缓存
JDK动态代理所用到的代理对象,在程序运行阶段调用到代理类对象时才由JVM真正建立。JVM根据传进来的业务实现类对象及方法名,在内存中动态地建立一个代理类的class文件并被字节码引擎执行,而后经过该代理类对象进行方法调用。具体而言,每一个代理类的对象都会关联一个表示内部处理逻辑的InvocationHandler接口的实现。当使用者调用代理对象所代理的接口中的方法时,这个调用的信息会被传递给InvocationHandler的invoke方法。mybatis
示例代码以下:app
// 业务接口 // public interface ISubject { void doAction(); } // 业务实现类 // public class RealSubject implements ISubject { @Override public void doAction() { System.out.println("Real Action Here!"); } } public class RealSubject2 implements ISubject { @Override public void doAction() { System.out.println("Real Action2 Here!"); } } // 动态代理类 // public class SubjectJdkProxyHandler implements InvocationHandler { private Object realSubject; public SubjectJdkProxyHandler(Object realSubject) { this.realSubject = realSubject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(">> doWhatever start"); // 扩展进行额外的功能操做(如鉴权、计时、日志等) Object result = method.invoke(realSubject, args); // 执行目标对象方法 System.out.println("doWhatever end <<"); // 扩展进行额外的功能操做(如鉴权、计时、日志等) return result; } } // 验证代码 // public class JdkProxyDemo { public static void main(String[] args) { ISubject subject = (ISubject) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[] {ISubject.class}, // 或RealSubject.class.getInterfaces() new SubjectJdkProxyHandler(new RealSubject())); // RealSubject必须实现Subject接口,不然没法强转后调用业务方法 subject.doAction(); // 使用同一个SubjectProxyHandler类,可代理不一样的类型 ISubject subject2 = (ISubject) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[] {ISubject.class}, new SubjectJdkProxyHandler(new RealSubject2())); // 可以使用工厂模式建立代理对象 subject2.doAction(); } }
执行结果以下:
>> doWhatever start Real Action Here! doWhatever end << >> doWhatever start Real Action2 Here! doWhatever end <<
JDK动态代理的特色以下:
Cglib(Code Generation Library)是个功能强大、高性能、开源的代码生成包,它能够为没有实现接口的类提供代理。具体而言,Cglib继承被代理的类,覆写其业务方法来实现代理。由于采用继承机制,因此不能对final修饰的类进行代理。
示例代码以下:
// 业务实现类 // public class RealSubject { public void doAction() { System.out.println("Real Action Here!"); } } // 动态代理类(实现方法拦截器接口) // // MethodInterceptor接口来自net.sf.cglib.proxy.MethodInterceptor或org.springframework.cglib.proxy.MethodInterceptor public class SubjectMethodInterceptor implements MethodInterceptor { public Object createCglibProxy(Class<?> targetClass) { Enhancer enhancer = new Enhancer(); // 建立加强器,用来建立动态代理类 enhancer.setSuperclass(targetClass); // 为加强器指定要代理的业务类,即为生成的代理类指定父类 enhancer.setCallback(this); // 设置回调(对于代理类上全部方法的调用,都会调用CallBack) return enhancer.create(); // 建立动态代理类对象并返回 // 以上语句可简化为:return Enhancer.create(targetClass, this); // } @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println(">> doWhatever start"); // 扩展进行额外的功能操做(如鉴权、计时、日志等) Object result = methodProxy.invokeSuper(proxy, args); System.out.println("doWhatever end <<"); // 扩展进行额外的功能操做(如鉴权、计时、日志等) return result; } } // 验证代码 // public class CglibProxyDemo { // 还可以使用CGLib + JDK InvocationHandler接口实现动态代理 public static Object createCglibProxyWithHandler(Class<?> targetClass) { MethodInterceptor interceptor = null; try { InvocationHandler invocationHandler = new SubjectJdkProxyHandler(targetClass.newInstance()); interceptor = (Object o, Method method, Object[] objects, MethodProxy methodProxy) -> invocationHandler.invoke(o, method, objects); } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } return Enhancer.create(targetClass, interceptor); } public static void main(String[] args) { RealSubject subject = (RealSubject) new SubjectMethodInterceptor().createCglibProxy(RealSubject.class); subject.doAction(); RealSubject subject2 = (RealSubject) createCglibProxyWithHandler(RealSubject.class); subject2.doAction(); } }
执行结果以下:
>> doWhatever start Real Action Here! doWhatever end << >> doWhatever start Real Action Here! doWhatever end <<
Cglib动态代理的特色以下:
示例代码以下:
public interface ISubject { void doAction(); } public class RealSubject implements ISubject { @Override public void doAction() { System.out.println("Real Action Here!"); } } public class SubjectSpringAopInvoker implements MethodInterceptor { // 来自org.aopalliance.intercept.MethodInterceptor private RealSubject target; public SubjectSpringAopInvoker(RealSubject realSubject) { this.target = realSubject; } @Override public Object invoke(MethodInvocation methodInvocation) throws Throwable { System.out.println(">> doWhatever start"); // 扩展进行额外的功能操做(如鉴权、计时、日志等) Object result = methodInvocation.getMethod().invoke(this.target, methodInvocation.getArguments()); System.out.println("doWhatever end <<"); // 扩展进行额外的功能操做(如鉴权、计时、日志等) return result; } } public class SpringAopProxyDemo { public static void main(String[] args) { ISubject proxy = ProxyFactory.getProxy(ISubject.class, new SubjectSpringAopInvoker(new RealSubject())); proxy.doAction(); } }
执行结果以下:
>> doWhatever start Real Action Here! doWhatever end <<
关于Spring实现动态代理的详细介绍,可参考《Spring学习总结(二)——静态代理、JDK与CGLIB动态代理、AOP+IoC》一文。