文档章节

JDK动态代理与Cglib动态代理(转载)

思悟修
 思悟修
发布于 2015/08/14 16:30
字数 1785
阅读 622
收藏 19

spring容器通过动态代理再结合java反射思想可以使得方法调用更加简洁

一、动态代理概述:

    与静态代理对照(关于静态代理的介绍 可以阅读上一篇:JAVA设计模式之 代理模式【Proxy Pattern】(博主),

    动态代理类的字节码是在程序运行时由Java反射机制动态生成。

    注意: 
      1、AspectJ是采用编译时生成AOP代理类,具有更好的性能,但是需要使用特定的编译器进行处理

      2、Spring AOP采用运行时生成AOP代理类,无需使用特定编译器进行处理,但是性能相对于AspectJ较差

二、JDK动态代理 [对有实现接口的对象做代理]

    1、JDK动态代理中 需要了解的两个重要的类或接口 [InvocationHandler 和 Proxy]

         ① InvocationHandler接口

public interface InvocationHandler {   
    public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;   
}

参数说明: 
Object proxy:指被代理的对象 
Method method:我们所要调用被代理对象的某个方法的Method对象
Object[] args:被代理对象某个方法调用时所需要的参数 

可以将InvocationHandler接口的子类想象成一个代理的最终操作类。

说明:每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类(Proxy)的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。同时在invoke的方法里 我们可以对被代理对象的方法调用做增强处理(如添加事务、日志、权限验证等操作)。

         ② Proxy类

 Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,该类常用的调用方法如下:

 

newProxyInstance方法参数说明如下:

ClassLoader loader:类加载器,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
Class<?>[] interfaces:得到被代理类全部的接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口,这样我就能调用这组接口中的方法了
InvocationHandler h:得到InvocationHandler接口的子类实例 


    2、JDK动态代理代码示例:

首先我们定义了一个Subject类型的接口:Subject.java

public interface Subject {  
    public void visit();  
}

接着定义一个接口的实现类,这个类就是我们示例中的被代理对象:RealSubject.java

/** 
 * 被代理类 
 * @author lvzb.software@qq.com 
 * 
 */  
public class RealSubject implements Subject {  
  
    @Override  
    public void visit() {  
         System.out.println("I am 'RealSubject',I am the execution method");  
    }  
  
}

第三步 定义一个动态代理类(必须要实现 InvocationHandler 这个接口):DynamicProxy.java

import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;  
/** 
 * JDK动态代理类 
 * @author lvzb.software@qq.com 
 * 
 */  
public class DynamicProxy implements InvocationHandler {  
  
    // 我们要代理的真实对象(委托对象)  
    private Object subject;  
      
    // 构造方法,给我们要代理的真实对象赋初值  
    public DynamicProxy(Object obj){  
        this.subject = obj;  
    }  
      
    @Override  
    public Object invoke(Object object, Method method, Object[] args)  
            throws Throwable {  
        // 在代理真实对象操作前 我们可以添加一些自己的操作  
        System.out.println("before proxy invoke");  
          
        // 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用  
        method.invoke(subject, args);  
          
        // 在代理真实对象操作后 我们也可以添加一些自己的操作  
        System.out.println("after proxy invoke");  
        return null;  
    }  
  
}


最后代理测试类:Client.java

import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Proxy;  
  
public class Client {  
  
    public static void main(String[] args) {  
        // 我们要代理的真实对象  
        Subject realSubject = new RealSubject();  
        // 我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象调用方法的  
        InvocationHandler handler = new DynamicProxy(realSubject);  
        /* 
         * 通过Proxy的newProxyInstance方法来动态创建我们的代理对象,我们来看看其三个参数< 
         * 参数一:我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象 
         * 参数二:我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了 
         * 参数三:我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上 
         */  
        Subject proxyInstance = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(),   
                RealSubject.class.getInterfaces(),   
                handler);  
          
        System.out.println(proxyInstance.getClass().getName());  
        proxyInstance.visit();  
  
    }  
  
}


运行->控制台输出结果如下:

com.sun.proxy.$Proxy0  
before proxy invoke  
I am 'RealSubject',I am the execution method  
after proxy invoke


三、Cglib(Code Generation Library)动态代理 [对没有实现接口的普通类做代理]

     1、概述:

         Cglib是一个优秀的动态代理框架,它的底层使用ASMJAVA字节码处理框架在内存中动态的生成被代理类的子类。使用CGLIB即使被代理类没有实现任何接 也可以实现动态代理功能。但是不能对final修饰的类进行代理。

     2、原理:

         通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用。

         <JDK动态代理与CGLib动态代理均是实现Spring AOP的基础>

     3、使用:

          使用Cglib前需要导入以下两个jar文件:
          asm.jar – Cglib的底层实现。

        【cglib包的底层是使用字节码处理框架ASM来转换字节码并生成新的类,所以cglib包要依赖于asm包】
          cglib.jar - Cglib的核心jar包。


     4、Cglib动态代理代码示例:

首先定义一个没有实现接口的代理委托类:CglibRealSubject.java

/** 
 * 没有实现接口的代理委托类 
 * @author lvzb.software@qq.com 
 * 
 */  
public class CglibRealSubject{  
  
    public void visit() {  
        System.out.println("I am 'RealSubject',I am the execution method");  
    }  
  
}


接着定义一个Cglib动态代理类: CglibDynamicProxy.java

import java.lang.reflect.Method;  
  
import net.sf.cglib.proxy.Enhancer;  
import net.sf.cglib.proxy.MethodInterceptor;  
import net.sf.cglib.proxy.MethodProxy;  
/** 
 * 使用cglib动态代理 
 * @author lvzb.software@qq.com 
 * 
 */  
public class CglibDynamicProxy implements MethodInterceptor {  
  
    private Object target;  
      
    /** 
     * 创建代理对象 
     * @param target 被代理的对象 
     * @return 
     */  
    public Object getProxyInstance(Object target){  
        this.target = target;  
        // 声明增强类实例  
        Enhancer enhancer = new Enhancer();   
        // 设置被代理类字节码,CGLIB根据字节码生成被代理类的子类  
                enhancer.setSuperclass(this.target.getClass());    
                // 设置要代理的拦截器,回调函数,即一个方法拦截   new MethodInterceptor()  
                enhancer.setCallback(this);   
                // 创建代理对象 实例   
                return enhancer.create();    
    }  
      
    @Override  
    public Object intercept(Object obj, Method method, Object[] args,  
            MethodProxy proxy) throws Throwable {  
        // 在代理真实对象操作前 我们可以添加一些自己的操作  
        System.out.println("前置代理,增强处理");  
          
        proxy.invokeSuper(obj, args);  
          
        // 在代理真实对象操作后 我们也可以添加一些自己的操作  
        System.out.println("后置代理,增强处理");  
        return null;  
    }  
  
}

最后测试客户端类:CglibClient.java

public class CglibClient {  
  
    public static void main(String[] args) {  
        CglibDynamicProxy cglib = new CglibDynamicProxy();  
        CglibRealSubject realSubject = (CglibRealSubject) cglib.getProxyInstance(new CglibRealSubject());  
        realSubject.visit();  
    }  
  
}


运行->控制台输出结果如下:

前置代理,增强处理  
I am 'RealSubject',I am the execution method  
后置代理,增强处理



© 著作权归作者所有

思悟修
粉丝 5
博文 59
码字总数 43362
作品 0
杭州
私信 提问
动态代理:JDK动态代理和CGLIB代理的区别

本文转载自:动态代理:JDK动态代理和CGLIB代理的区别 代理模式:代理类和被代理类实现共同的接口(或继承),代理类中存有指向被代理类的索引,实际执行时通过调用代理类的方法、实际执行的是...

淡淡的倔强
2018/09/07
0
0
Spring中JDK动态代理和Cglib代理的区别

Spring的AOP基于代理模式,并且它即使用到了JDK动态代理也使用了Cglib代理。 如下代码是springAOP中默认的代理实现类DefaultAopProxyFactory,其中创建代理的方法createAopProxy,在这个方法...

王子城
2018/08/01
1K
0
Spring Proxy 动态代理(ProxyFactory)

一、动态代理生成技术栈分为两种: 1、JDK动态代理 JDK动态代理只能对实现了接口的类生成代理,而不能针对类 2、Cglib动态代理 CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其...

王微_1986
2018/07/27
0
0
spring基础知识---AOP动态代理原理

Spring Boot实践——Spring AOP实现之动态代理 Spring AOP 介绍   AOP的介绍可以查看 Spring Boot实践——AOP实现   与AspectJ的静态代理不同,Spring AOP使用的动态代理,所谓的动态代理...

spinachgit
02/21
153
0
Sring如何选择JDK动态代理与CGLIB字节码增强

Spring将事务代理工厂TransactionProxyFactoryBean或自动代理拦截器BeanNameAutoProxyCreator的proxyTargetClass属性,设置为true,则使用CGLIB代理,此属性默认为false,使用JDK动态代理。 Spri...

无语年华
2018/09/11
61
0

没有更多内容

加载失败,请刷新页面

加载更多

CC攻击带来的危害我们该如何防御?

随着网络的发展带给我们很多的便利,但是同时也带给我们一些网站安全问题,网络攻击就是常见的网站安全问题。其中作为站长最常见的就是CC攻击,CC攻击是网络攻击方式的一种,是一种比较常见的...

云漫网络Ruan
今天
8
0
实验分析性专业硕士提纲撰写要点

为什么您需要研究论文的提纲? 首先当您进行研究时,您需要聚集许多信息和想法,研究论文提纲可以较好地组织你的想法, 了解您研究资料的流畅度和程度。确保你写作时不会错过任何重要资料以此...

论文辅导员
今天
7
0
作为一个(IT)程序员!聊天没有话题?试试这十二种技巧

首先呢?我是一名程序员,经常性和同事没话题。 因为每天都会有自己的任务要做,程序员对于其他行业来说;是相对来说比较忙的。你会经常看到程序员在发呆、调试密密麻麻代码、红色报错发呆;...

小英子wep
今天
30
0
【SpringBoot】产生背景及简介

一、SpringBoot介绍 Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化新 Spring 应用的初始搭建以及开发过程,该框架使用了特定的方式来进行配置,从而使开发人员不再需要...

zw965
今天
14
0
简述并发编程分为三个核心问题:分工、同步、互斥。

总的来说,并发编程可以总结为三个核心问题:分工、同步、互斥。 所谓分工指的是如何高效地拆解任务并分配给线程,而同步指的是线程之间如何协作,互斥则是保证同一时刻只允许一个线程访问共...

dust8080
今天
11
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部