Cglib Dynamic Proxy(Cglib 动态代理)

来源:互联网 发布:淘宝网板鞋后底女鞋 编辑:程序博客网 时间:2024/05/17 23:35

使用JDK创建动态代理只能为接口创建代理实例,这第一点从Proxy的接口签名newProxyInstance(ClassLoader loader,Class[]interfaces,InvocationHandler h)中就可以看的很清楚:第二个入参interfaces就是需要代理实例的接口列表。对于没有接口定义的业务方法的类,则使用Cglib动态代理。

         Cglib采用了非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,并顺势织入横切逻辑。

实例一:使用Cglib动态代理,对方法执行时间进行监控

Computer类

public class Computer {

   public int add(int a,int b){

      System.out.println("perform add method...");

      try {

         Thread.sleep(20);

      }catch(InterruptedException e) {

         e.printStackTrace();

      }

      return a+b;

   }

   public int plus(int a,int b){

      System.out.println("perform plus method...");

      try {

         Thread.sleep(40);

      }catch(InterruptedException e) {

         e.printStackTrace();

      }

      return a-b;

   }

}


监视器类

/**

 * 用于记录性能监视信息

 * method为目标类方法的全限定名

 */

public class MethodPerformance {

   private long begin;

   private long end;

   private String serviceMethod;

   public MethodPerformance(String serviceMethod){

      this.serviceMethod=serviceMethod;

      begin=System.currentTimeMillis();

   }

   public void printPerformance(){

      end=System.currentTimeMillis();

      long elapse=end-begin;

      System.out.println(serviceMethod+" cost "+elapse+" ms");

   }

}

/**

 *性能监视器类

 */

public class PerformanceMonitor {

   /*

    * 通过一个ThreadLocal保存调用线程相关的性能监视信息,ThreadLocal是将非线程安全类改造为线程安全类的法宝

    */

   private static ThreadLocal<MethodPerformance> performanceRecord=newThreadLocal<MethodPerformance>();

   //启动对某一目标方法的性能监视

   public static void begin(String method){

      System.out.println("begin monitor...");

      MethodPerformance mp=new MethodPerformance(method);

      performanceRecord.set(mp);

   }

   public static void end(){

      System.out.println("end monitor...");

      MethodPerformance  mp=performanceRecord.get();

      mp.printPerformance();//打印方法性能监视结果

   }

}


Cglib动态代理类

public class  CglibProxy  implements  MethodInterceptor{

   private Enhancer enhancer=new Enhancer();

   public Object  getProxy(Class<?>  clazz){

      enhancer.setSuperclass(clazz);//设置需要创建子类的类

      enhancer.setCallback(this);

      return enhancer.create(); //通过字节码技术动态创建子类实例

   }

   public Object intercept(Object obj, Method method, Object[] args,//拦截父类所有方法的调用

         MethodProxy  proxy) throwsThrowable {

      PerformanceMonitor.begin(obj.getClass().getName()+"."+method.getName());

      Object  result=proxy.invokeSuper(obj, args); //通过代理类调用父类中的方法

      PerformanceMonitor.end();

      return result;

   }

}

测试类:

public class Test {

   public static void main(String[] args) {

      CglibProxyproxy=new CglibProxy();

      Computer c=(Computer)proxy.getProxy(Computer.class);

      c.add(5,2);

      c.plus(10,3);

   }

}

 

输出结果:

begin monitor...

perform add method...

end monitor...

cglib1.Computer$$EnhancerByCGLIB$$5658ac9d.addcost 38 ms

begin monitor...

perform plus method...

end monitor...

cglib1.Computer$$EnhancerByCGLIB$$5658ac9d.pluscost 40 ms

 

在intercept(Object obj,Method method,Objects[] args,MethodProxy proxy)是CGLIB定义的Interceptor接口的方法,它拦截所有目标类方法的调用,obj标示目标类的实例,method为目标类方法的反射对象;args为方法的动态入参;而proxy为代理类的实例。

 

 

实例二:利用cglib动态代理,对增删改查方法进行权限过滤

BookBean实现了增删改查的业务功能

public class BookBean {

   public void create(){

      System.out.println("create is running");

   }

   public void delete(){

      System.out.println("delete is running");

   }

   public void query(){

      System.out.println("query is running");

   }

   public void update(){

      System.out.println("update is running");

   }

}

动态代理,实现业务逻辑横切面拦截(即权限过滤)

public class CglibProxy implementsMethodInterceptor {

   private Logger  log=Logger.getLogger(CglibProxy.class);

   private String  name;

   private Enhancer   enhancer=new Enhancer();

   public CglibProxy(String  name){

      this.name=name;

   }

   public Object  getBookBeanProxy(Class<?> clazz){

      enhancer.setSuperclass(clazz);

      enhancer.setCallback(this);

      return enhancer.create();

   }

   public Object  intercept(Object  obj, Method method, Object[] args,

         MethodProxy  proxy) throws  Throwable {

      log.info("invoke method is "+method.getName());

      if("zhangsan".equals(name)){

         System.out.println("Permission denied! ");

         return null;

      }

      Object result=proxy.invokeSuper(obj, args);

      return result;

   }

}

 

创建一个获取Bean工厂类

public class BookBeanFactory {

   private static BookBean service=new BookBean();

   public BookBeanFactory(){};

   public static BookBean getInstance(){

      return service;

   }

   /*

    * 用于获取BookBean代理类而特别提供的方法,也可以忽略直接用上面通用的方法

    */

   public static BookBean   getBookBeanProxyInstance(CglibProxy proxy){

      Enhancer  enhancer=new  Enhancer();

      enhancer.setSuperclass(BookBean.class);

      enhancer.setCallback(proxy);

      return (BookBean)enhancer.create();

   }

}

测试类:

public class Client {

   public static void doMethod(BookBean   bean){

      bean.create();

      bean.delete();

      bean.query();

      bean.update();

   }

   public static void main(String[] args) {

      //BookBean bean=BookBeanFactory.getInstance();

      CglibProxyproxy=new   CglibProxy("zhangsan");

//    BookBeanbean=(BookBean)proxy.getBookBeanProxy(BookBean.class);

     

      BookBeanbean =BookBeanFactory.getBookBeanProxyInstance(proxy);

      doMethod(bean);

   }

}

无权限的结果:

Permission denied!

Permission denied!

Permission denied!

Permission denied!

有权限的结果:

create is running

delete is running

query is running

update is running

 

通过动态代理实现对方法权限的使用,如果不用动态代理的话,就需要在每个方法中判断某人是否具有使用自己的权限,这将是很麻烦的。