一、CGlib动态代理

 
 

JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要CGLib了。CGLib采用了非常底层的1:字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用2:方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。

字节码技术:参考:http://note.youdao.com/noteshare?id=13453e8d815d3102938a02881b6f418f&sub=E56D1E6223FC4CA8BF072CD045301EFA

 

CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。

 
 

简单的实现举例:

这是一个需要被代理的类,也就是父类,通过字节码技术创建这个类的子类,实现动态代理。

[java] view plain copy

1.  public class SayHello {  

2.   public void say(){  

3.    System.out.println("hello everyone");  

4.   }  

5.  }  

该类实现了创建子类的方法与代理的方法。getProxy(SuperClass.class)方法通过入参即父类的字节码,通过扩展父类的class来创建代理对象。intercept()方法拦截所有目标类方法的调用,obj表示目标类的实例,method为目标类方法的反射对象,args为方法的动态入参,proxy为代理类实例。proxy.invokeSuper(obj, args)通过代理类调用父类中的方法。

[java] view plain copy

1.  public class CglibProxy implements MethodInterceptor{  

2.   private Enhancer enhancer = new Enhancer();  

3.   public Object getProxy(Class clazz){  

4.    //设置需要创建子类的类  

5.    enhancer.setSuperclass(clazz);  

6.    enhancer.setCallback(this);  

7.    //通过字节码技术动态创建子类实例  

8.    return enhancer.create();  

9.   }  

10.
 //实现MethodInterceptor接口方法  

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

12.
   MethodProxy proxy) throws Throwable {  

13.
  System.out.println("前置代理");  

14.
  //通过代理类调用父类中的方法  

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

16.
  System.out.println("后置代理");  

17.
  return result;  

18.
 }  

19.
}  

具体实现类:

[java] view plain copy

1.  public class DoCGLib {  

2.   public static void main(String[] args) {  

3.    CglibProxy proxy = new CglibProxy();  

4.    //通过生成子类的方式创建代理类  

5.    SayHello proxyImp = (SayHello)proxy.getProxy(SayHello.class);  

6.    proxyImp.say();  

7.   }  

8.  }  

输出结果:

[plain] view plain copy

1.  前置代理  

2.  hello everyone  

3.  后置代理  

    
 

 
 

 
 

 
 

二、JDK动态代理

 

使用动态代理的五大步骤

1.通过实现InvocationHandler接口来自定义自己的InvocationHandler;

 
 

2.通过Proxy.getProxyClass获得动态代理类

 
 

3.通过反射机制获得代理类的构造方法,方法签名为getConstructor(InvocationHandler.class)

 
 

4.通过构造函数,获得代理对象,并将自定义的InvocationHandler实例对象传为参数传入

 
 

5.通过代理对象调用目标方法

 

 

public
class ObjectProxy implements
InvocationHandler {

 
 

    Object target = null;

    List<BeforeAdvice> beforeList = new ArrayList<BeforeAdvice>();

    List<AfterAdvice> afterList = new ArrayList<AfterAdvice>();

   
 

    public ObjectProxy() {

       super();

       // TODO Auto-generated constructor stub

    }

public ObjectProxy(Object target) {

        super();

       this.target = target;

     
 

       try{

//解析advice.xml中所有的前置通知--得到class的值--->通过反射得到类的对象

              DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

              DocumentBuilder db = dbf.newDocumentBuilder();

              Document doc = db.parse("src//advice.xml");

             
 

              //遍历前置通知

              NodeList beforeNodeList = doc.getElementsByTagName("beforeAdvice");

              for(int i=0;i<beforeNodeList.getLength();i++){

                 Element beforeElement =(Element) beforeNodeList.item(i);

                 String classValue = beforeElement.getAttribute("class"); //类的完整路径

                 Class clz = Class.forName(classValue);

                 BeforeAdvice obj = (BeforeAdvice)clz.newInstance();

                 beforeList.add(obj);

              }

             
 

            //遍历后置通知

              NodeList afterNodeList = doc.getElementsByTagName("afterAdvice");

              for(int i=0;i<afterNodeList.getLength();i++){

                 Element afterElement =(Element) afterNodeList.item(i);

                 String classValue = afterElement.getAttribute("class"); //类的完整路径

                 Class clz = Class.forName(classValue);

                 AfterAdvice obj = (AfterAdvice)clz.newInstance();

                 afterList.add(obj);

              }

             
 

          
 

       }catch(Exception e){

         e.printStackTrace();

       }

    }

 
 

 
 

    /**

     * 伪装成目标类之后,要执行的方法

     */

    @Override

    public Object invoke(Object proxy, Method method, Object[] args)

           throws Throwable {

       //短信验证

       for(BeforeAdvice bf:beforeList){

           //对method目标方法进行判断,执行响应的前置切面业务

           bf.Before();

       }

       //目标方法

       Object result = method.invoke(target, args);

       //日志记录

       for(AfterAdvice af:afterList){

           //对method目标方法进行判断,执行响应的后置切面业务

           af.After();

      
 

          
 

       }

       return result;

    }

   
 

    /**

     * 获得代理类的对象

     * @param obj

     * @return

     */

     public
static  Object getProxyBean(Object obj){    

       return Proxy.newProxyInstance(obj.getClass().getClassLoader(),

              obj.getClass().getInterfaces(),new ObjectProxy(obj));

   
 

    }

 
 

}

public
static
void main(String[] args) {

      Idog dog = (Idog)ObjectProxy.getProxyBean(new Dog());

      dog.say();

}

CGlib和JDK动态代理的更多相关文章

  1. 学习CGLIB与JDK动态代理的区别

    动态代理 代理模式是Java中常见的一种模式.代理又分为静态代理和动态代理.静态代理就是显式指定的代理,静态代理的优点是由程序员自行指定代理类并进行编译和运行,缺点是一个代理类只能对一个接口的实现类进 ...

  2. Cglib 与 JDK动态代理的运行性能比较

    都说 Cglib 创建的动态代理的运行性能比 JDK 动态代理能高出大概 10 倍,今日抱着怀疑精神验证了一下,发现情况有所不同,遂贴出实验结果,以供参考和讨论. 代码很简单,首先,定义一个 Test ...

  3. Cglib 与 JDK动态代理

    作者:xiaolyuh 时间:2019/09/20 09:58 AOP 代理的两种实现: jdk是代理接口,私有方法必然不会存在在接口里,所以就不会被拦截到: cglib是子类,private的方法照 ...

  4. 面试造火箭系列,栽在了cglib和jdk动态代理

    "喂,你好,我是XX巴巴公司的技术面试官,请问你是张小帅吗".声音是从电话那头传来的 "是的,你好".小帅暗喜,大厂终于找上我了. "下面我们来进行一 ...

  5. 输出cglib以及jdk动态代理产生的class文件

      --该设置用于输出jdk动态代理产生的类 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles&q ...

  6. spring cglib 与 jdk 动态代理

    1. 概述 JDK动态代理是利用java反射机制 生成一个实现接口的匿名类, 在调用具体方法前调用InvocationHandler来处理 Cglib动态代理是 利用asm开源包 把被代理类的clas ...

  7. 有点深度的聊聊JDK动态代理

    在接触SpringAOP的时候,大家一定会被这神奇的功能所折服,想知道其中的奥秘,底层到底是如何实现的.于是,大家会通过搜索引擎,知道了一个陌生的名词:动态代理,慢慢的又知道了动态代理有多种实现方式, ...

  8. java学习笔记(中级篇)—JDK动态代理

    一.什么是代理模式 相信大家都知道代理商这个概念,在商业中,代理商无处不在.假设你要去买东西,你不可能去找真正的厂家去买,也不可能直接跟厂家提出需求,代理商就是这中间的一桥梁,连接买家和厂商.你要买或 ...

  9. AOP学习心得&jdk动态代理与cglib比较

    什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入 ...

随机推荐

  1. EF 序列化实体为Json时的循环引用问题(不用自己写实体,不用匿名类型,不用EF的上下文属性)

    自己写实体可以完美解决这个问题.(支持时间格式自定义) 用匿名类型也可以. 设置上下文方法如下: (jz为数据库上下文对象) jz.Configuration.ProxyCreationEnabled ...

  2. hdu 2527:Safe Or Unsafe(数据结构,哈夫曼树,求WPL)

    Safe Or Unsafe Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  3. 论坛模块__发帖时使用FCKeditor

    论坛模块__发帖时使用FCKeditor 测试 <html> <head> <meta http-equiv="content-type" conte ...

  4. 编程之美 set 18 拈两堆石子游戏(3)

    题目 假设有两堆石头, 有两个玩家按照如下规则轮流取石头 每个人每次可以从两堆石头中取出数量相等的石头, 或者仅从一堆石头中取出任意数量的石头 最后把剩下的石头依次拿光的人取胜 首先取石头的人能否赢得 ...

  5. python 自己定义异常

    通过创建一个新的异常类,就可以命名自己的异常,异常应该是典型的继承自Exception类 例如: # 定义了一个自己的异常类,可在适当时候通过raise来触发它class ExError(Except ...

  6. jquery将具有相同名称的元素的值提取出来放到一个数组内

    jquery将具有相同名称的元素的值提取出来放到一个数组内 var arrInputValues = new Array();  $("input[name='xxx']").ea ...

  7. string整理

    /* scanf是c语言的,而string是c++的类,所以不能使用scanf直接读入 */ #include<cstdio> #include<string>//注意支持库 ...

  8. python中的coding的格式书写形式

     # -*- coding:utf-8 -*-可以改写成以下各种形式:1,# -*- coding=utf-8 -*-2,# _*_ coding=utf-8 _*_3,# coding:utf-84 ...

  9. 查看环境变量CLASSPATH, PATH ,JAVA_HOME-------->mac

    终端(命令行)操作 推荐两篇博客:http://elf8848.iteye.com/blog/1582137 http://blog.csdn.net/done58/article/details/5 ...

  10. Fully qualified name FQCN

    Fully qualified name - Wikipedia https://en.wikipedia.org/wiki/Fully_qualified_name In computer prog ...