Java JDK动态代理与Cglib动态代理

来源:互联网 发布:淘宝客单页生成器 编辑:程序博客网 时间:2024/06/05 23:05

动态代理

为什么要使用动态代理?

在静态代理模式时,一个真实角色必须对应一个代理角色,如果大量使用会导致类的急剧膨胀;

1.抽象类或者接口

public interface ISubject {
 public void sayHello();
}

2. 真实类(必须实现接口)

public class RealObject implements ISubject {
 public void sayHello() {

  System.out.println("hello glad to see you");
 }

}

3.动态创建代理对象的类(此时不能出现代理对象)

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DynamicProxy implements InvocationHandler{

 //拿到对真实对象的引用(因为真实对象可能有很多个,因此我们必须定义成Object类型去任意匹配)

//此时实现的是对任意真实兑现给的引用。此处也是固定的写法


  private Object targetObject = null;
  
 //方法--> 用来动态的生成代理对象(通过反射在运行期分析类的能力,然后动态生成)

//注意只要是在运行期分析类的能力,都回去涉及到反射方法。
  /***
  * 1, 通过反射进入类的加载器
  * 2,和真实对象实现相同的接口
  * 3,一个对象,这个对象实现了InvocationHandler这个接口的对象的引用
  */

//这个方法也是固定的写法
 public Object createDynamicProxyObjectMethod(Object targetObject){
  this.targetObject = targetObject;//因为是要真实对象的代理,所以这块必须引入真实对象
  return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), //这个参数是得到类的加载器
           targetObject.getClass().getInterfaces(), 
           this); //此处的this急救等于 new DynaProxyObject()
 }
 
 //被系统自动调用的:只有这个方法时需要自己写的方法
 
 public Object invoke(Object proxy, Method method, Object[] args)

//注意此处的method不能是数组,若有n多接口或方法时只能是用if去判断及if(method 。equals(""));

//参数args表示方法的参数,参数可以位任意的类型,因此用Object[]去匹配
   throws Throwable {
  
  Object resultObj = null;
  
  this.before();
  
  try {
   resultObj = method.invoke(targetObject, args);
  } catch (Exception e) {
   e.printStackTrace();
  }
  
  this.after();
  
  return resultObj;
 }

 public void before(){
  System.out.println("before---------------");
 }
 
 public void after(){
  System.out.println("after---------------");
 }
}

 

4。客户端测试

public class Client {
 
 public static void main(String[] args) {
  DynaProxyObject dpo = new DynaProxyObject();
  ISubject isub = (ISubject)dpo.createDynamicProxyObject(new RealObject());

  isub.sayHello();
 }
}


总结

    JDK动态代理模式通过使用反射,可以在运行期决定加载哪个类,避免了一个类对应一个代理的问题;同时,通过统一的invoke方法,统一了代理类对原函数的处理过程,使用动态代理很大程度上减少了重复的代码,降低了维护的复杂性和成本

Cglib(Code Generation Library)动态代理 
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。 CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
示例 
1、BookFacadeCglib.java 
  1. package net.battier.dao;  
  2.   
  3. public interface BookFacade {  
  4.     public void addBook();  

2、BookCadeImpl1.java 

  1. package net.battier.dao.impl;  
  2.   
  3. /** 
  4.  * 这个是没有实现接口的实现类 
  5.  *  
  6.  * @author student 
  7.  *  
  8.  */  
  9. public class BookFacadeImpl1 {  
  10.     public void addBook() {  
  11.         System.out.println("增加图书的普通方法...");  
  12.     }  
  13. }  


3、BookFacadeProxy.java 

  1. package net.battier.proxy;  
  2.   
  3. import java.lang.reflect.Method;  
  4.   
  5. import net.sf.cglib.proxy.Enhancer;  
  6. import net.sf.cglib.proxy.MethodInterceptor;  
  7. import net.sf.cglib.proxy.MethodProxy;  
  8.   
  9. /** 
  10.  * 使用cglib动态代理 
  11.  *  
  12.  * @author student 
  13.  *  
  14.  */  
  15. public class BookFacadeCglib implements MethodInterceptor {  
  16.     private Object target;  
  17.   
  18.     /** 
  19.      * 创建代理对象 
  20.      *  
  21.      * @param target 
  22.      * @return 
  23.      */  
  24.     public Object getInstance(Object target) {  
  25.         this.target = target;  
  26.         Enhancer enhancer = new Enhancer();  
  27.         enhancer.setSuperclass(this.target.getClass());  
  28.         // 回调方法  
  29.         enhancer.setCallback(this);  
  30.         // 创建代理对象  
  31.         return enhancer.create();  
  32.     }  
  33.   
  34.     @Override  
  35.     // 回调方法  
  36.     public Object intercept(Object obj, Method method, Object[] args,  
  37.             MethodProxy proxy) throws Throwable {  
  38.         System.out.println("事物开始");  
  39.         proxy.invokeSuper(obj, args);  
  40.         System.out.println("事物结束");  
  41.         return null;  
  42.   
  43.   
  44.     }  
  45.   
  46. }  


4、TestCglib.java 

  1. package net.battier.test;  
  2.   
  3. import net.battier.dao.impl.BookFacadeImpl1;  
  4. import net.battier.proxy.BookFacadeCglib;  
  5.   
  6. public class TestCglib {  
  7.       
  8.     public static void main(String[] args) {  
  9.         BookFacadeCglib cglib=new BookFacadeCglib();  
  10.         BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());  
  11.         bookCglib.addBook();  
  12.     }  
  13. }  
CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理

0 0