java的代理模式有两种,一种是jdk自带的动态代理,一种是cglib动态代理。html
一、jdk动态代理:java
/** * 1.建立接口 */ public interface Subject { int sellBook(); String speak(); } /** * 2.建立真实对象 */ public class RealSubject implements Subject { @Override public int sellBook() { System.out.println("卖书"); return 1; } @Override public String speak() { System.out.println("说话"); return "张三"; } } /** * 3.建立真实对象的代理类,代理类要实现InvocationHandler接口,表示使用jdk动态代理 * 代理模式的重要做用是用于在被代理类的方法执行先后切入代码 */ public class JdkProty implements InvocationHandler { /** * 由于须要处理真实对象,因此须要将真实对象传过来,经过构造方法赋值 */ private Subject subject; public JdkProty(Subject subject) { this.subject = subject; } /** * @param proxy 被代理的对象 * @param method 正在调用的方法 * @param args 方法的参数 * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("调用代理类"); if (method.getName().equals("sellBook")) { int invoke = (int) method.invoke(subject, args); System.out.println("调用了卖书的方法"); return invoke; } else if (method.getName().equals("speak")) { String string = (String) method.invoke(subject, args); System.out.println("调用的是说话的方法"); return string; } return null; } }
/**
*测试方法
*/ public class TestDemo { public static void main(String[] args) { Subject subject = new RealSubject(); JdkProty jdkProty = new JdkProty(subject); /** * 代理对象(本方法能够封装入代理类中,被代理类对象做为obj参数传递) *subject.getClass().getClassLoader():被代理类对象的加载器 * subject.getClass().getInterfaces():获得被代理类对象的全部接口 * jdkProty:与被代理类对象相关的代理类对象 */ Subject proxyInstance = (Subject) Proxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), jdkProty); proxyInstance.sellBook(); proxyInstance.speak(); } }
使用jdk动态代理的前提条件:被代理的类必定要有实现的接口node
/**
* java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口用来完成动态代理。
* InvocationHandler接口:
* 当咱们经过代理对象调用一个方法时,这个方法的调用就会被转发为由InvocationHandler这个接口的invoke方法进行调用
* Proxy类
* 该类提供了一个建立动态代理对象的方法
*/
二、cglib动态代理ide
Cglib 动态代理是针对代理的类, 动态生成一个子类, 而后子类覆盖被代理类中的方法, 若是是private或是final类修饰的方法,则不会被重写。性能
CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。一般可使用Java的动态代理建立代理,但当要代理的类没有实现接口或者为了更好的性能,CGLIB是一个好的选择。测试
使用cglib动态代理须要导包:cglib-nodep-2.2.2.jarthis
/** * 1.建立真实类对象 */ public class Ennigeer { //能够被代理的方法 public int eat() { System.out.println("工程师在吃饭"); return 1; } //final修饰的方法不会被cglib生成的子类覆盖,能够经过代理类调用,可是不能执行代理类的方法 public final String work() { System.out.println("工程师在工做"); return "hello"; } //private修饰的方法不会被生成的子类覆盖,不能经过代理类调用 private void play() { System.out.println("工程师在玩"); } } public class CglibProxy implements MethodInterceptor { /** * 该intercept方法相似于jdk的invoke方法发 * @param o 被代理类对象 * @param method 被代理类的方法对象 * @param objects 传进去的参数 * @param methodProxy 代理方法的代理对象 * @return * @throws Throwable */ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("方法调用以前"); Object invoke = methodProxy.invokeSuper(o, objects); System.out.println("方法调用以后"); return invoke; } /** * 获得代理类 * @param obj 被代理类对象 * @return 代理类对象 */ public Object getProxy(Object obj) { //建立增强器,用来建立被代理类的对象 Enhancer enhancer = new Enhancer(); //为增强器指定要代理的业务类(即:为下面生成的代理类指定父类) enhancer.setSuperclass(obj.getClass()); //设置回调,对代理类上全部方法的调用,都会调用CallBack(),而CallBack()方法则须要intercept方法进行拦截 enhancer.setCallback(this); //建立被代理类对象的特殊格式的对象 return enhancer.create(); } } public class TestDemo { public static void main(String[] args) { Ennigeer ennigeer = new Ennigeer(); CglibProxy cglibProxy = new CglibProxy(); Ennigeer proxy = (Ennigeer) cglibProxy.getProxy(ennigeer); int eat = proxy.eat();//能够被代理的方法 String work = proxy.work();//不能被代理的方法,能够调用该方法,可是不能代理 System.out.println(eat); System.out.println(work); } }
/**
* net.sf.cglib.proxy.MethodInterceptor接口:是最通用的回调(callback)类型,
* 它常常被AOP用来实现拦截(intercept)方法的调用。这个接口只定义了一个方法。
* public Object intercept(Object proxy, Method method, Object[] params, MethodProxy methodProxy)
* proxy:代理的对象;
* method:委托类执行的方法;
* params:方法中的参数;
* methodProxy:代理的方法
* 因为性能的缘由,对原始方法的调用咱们使用CGLIB的net.sf.cglib.proxy.MethodProxy对象,而不是反射中通常使用java.lang.reflect.Method对象
*/
两种代理方式的比较:url
CGLib动态代理建立代理实例速度慢,可是运行速度快;JDK动态代理建立实例速度快,可是运行速度慢。若是实例是单例的,推荐使用CGLib方式动态代理,反之则使用JDK方式进行动态代理。Spring的实例默认是单例,因此这时候使用CGLib性能高。 spa
JDK动态代理是经过接口中的方法名,在动态生成的代理类中调用业务实现类的同名方法;.net
CGlib动态代理是经过继承业务类,生成的动态代理类是业务类的子类,经过重写业务方法进行代理;
静态代理是经过在代码中显式定义一个业务实现类一个代理,在代理类中对同名的业务方法进行包装,用户经过代理类调用被包装过的业务方法;