1. jdk静态代理
jdk静态代理主要使用硬编码实现.他通过对在代理类中持有委托类的引用,来打到在委托类方法执行前和执行后进行处理,实现简单,容易理解.
代码如下:
1.业务逻辑接口
1 package jdkStaticProxy; 2 3 public interface Service { 4 5 public void doService(); 6 7 }
2.业务逻辑实现类
1 package jdkStaticProxy; 2 3 public class ServiceImpl implements Service { 4 5 @Override 6 public void doService() { 7 System.out.println("this is doService method"); 8 } 9 }
3.代理类
1 package jdkStaticProxy; 2 3 public class ServiceProxy implements Service { 4 5 private Service service; 6 7 public ServiceProxy(Service service) { 8 this.service = service; 9 } 10 11 @Override 12 public void doService() { 13 System.out.println("there is before method");//前置处理方法 14 service.doService();//业务逻辑方法 15 System.out.println("there is after method");//后置处理方法 16 } 17 }
在代理类中持有一个委托类的应用,以达到在代理类中进行相关处理.
4.测试类
1 package jdkStaticProxy; 2 3 public class Main { 4 5 public static void main(String[] args) { 6 Service service=new ServiceImpl(); 7 Service serviceProxy=new ServiceProxy(service); 8 serviceProxy.doService(); 9 } 10 11 }
以上就是jdk静态代理,很容易理解,但是他的问题也显而易见----dk静态代理因为是硬编码实现,所以可能会存在大量的重复代码.加入我们的service有10个方法,那么我们的代理类中就必须有10个对应的代理方法,这样的工作量是非常大.
2. jdk动态代理
jdk动态代理主要使用反射实现.要使用jdk代理必须实现一个接口,原因是jdk代理是用代理类替换委托类进行方法调用,为了让代理能够完成替换,就必须实现一个接口,这样jdk就能生成对应的代理类.代理类的生成主要通过一个Proxy工厂生成,代理类的方法通过调用一个InvocationHandler接口的invoke方法执行.
代码如下:
1.业务逻辑接口
同静态代理
2.业务逻辑实现类
同静态代理
3.InvocationHandler
1 package jdkDynamicProxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 6 public class MyInvocationHandler implements InvocationHandler { 7 8 private Object target; 9 1011 12 public MyInvocationHandler(Object target) { 13 this.target = target; 14 15 } 16 17 @Override 18 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 19 20 System.out.println("there is before method"); 21 22 method.invoke(target,args); 23 24 System.out.println("there is after method"); 25 26 return null; 27 } 28 29 }
从代码里面可以看出来,代理类持有委托类的引用.委托类的方法是通过反射来进行调用的.method是委托类的方法.
4.测试类
package jdkDynamicProxy; import java.lang.reflect.Proxy; public class Main { public static void main(String[] args) { ServiceImpl service=new ServiceImpl(); MyInvocationHandler myInvocationHandler=new MyInvocationHandler(service); Service service1= (Service) Proxy.newProxyInstance( service.getClass().getClassLoader(),//委托类的类加载器 service.getClass().getInterfaces(),//委托类的接口 myInvocationHandler);//InvocationHandler service1.doService(); System.out.println("实际类型:"+service1.getClass()); } }
Proxy是一个工厂类,调用newProxyInstance生成一个代理类,传入委托类加载器和委托类的接口是为了创建一个能够替换委托类的代理类(为什么需要这两个参数请了解JVM如何判断两个类相等),InvocationHandler为代理类的逻辑方法.代码中的service1实际类型是com.sun.proxy.$Proxy0.代理类的创建是通过反射创建,有兴趣的读者可以研究Proxy的源码,也可以看这里
3. cglib动态代理
cglib是一个开源库,他不需要委托类实现一个接口,他是通过创建一个继承委托类的代理类,来进行强化方法,代理类的实现方法通过调用MethodInterceptor的intercept方法.创建代理类主要借助asm这个java字节码生成框架.
代码如下:
1.业务逻辑类
同静态代理
2.intercept
1 package cglibProxy; 2 3 import net.sf.cglib.proxy.MethodInterceptor; 4 import net.sf.cglib.proxy.MethodProxy; 5 6 import java.lang.reflect.Method; 7 8 public class MyInterceptor implements MethodInterceptor { 9 10 @Override 11 public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { 12 System.out.println("-----before"); 13 methodProxy.invokeSuper(o,objects);//调用父类(业务逻辑)方法 14 System.out.println("-----after"); 15 return null; 16 } 17 18 }
其中method是委托类的方法,methodProxy是代理类的代理方法.
3.测试方法
1 package cglibProxy; 2 3 import net.sf.cglib.proxy.Enhancer; 4 5 public class Main { 6 7 public static void main(String[] args) { 8 9 Enhancer enhancer=new Enhancer();//该类是cglib的字节码生成器,能够直接生成对应代理类的字节码 10 enhancer.setSuperclass(Service.class);//继承委托类(final类不可被继承) 11 enhancer.setCallback(new MyInterceptor());//设置回调 12 Service service= (Service) enhancer.create();//生成代理对象 13 14 service.doService(); 15 System.out.println("实际类型:"+service.getClass()); 16 17 } 18 }
代理类对象是由Enhancer类创建的。Enhancer是CGLIB的字节码增强器,可以很方便的对类进行拓展.通过设置回调方法和委托类,生成对应代理类的字节码,然后将代理类加载进来,生成代理对象.
创建代理类的步骤如下:
1.生成代理类的二进制字节码文件
2.加载二进制字节码,生成Class对象( 例如使用Class.forName()方法 )
3.通过反射机制获得实例构造,并创建代理类对象
cglib原理请看这里
4. 各代理对比
1.jdk静态代理:实现简单易懂,但是由于是硬编码实现,所以可能会出现大量重复代码.
2.jdk动态代理:通过反射机制创建代理类以及代理类方法调用,他在创建代理类的效率上会比cglib高,但是在调用方法的效率上比cglib低.
3.cglib动态代理:通过生成字节码的方式创建代理类,他在创建代理类的效率上由于要生成字节码以及加载类所以比jdk代理低,但是方法执行效率上由于是直接执行,不需要进行反射所以效率比jdk代理高.