Java实例讲解动态代理

 更新时间:2022年06月03日 09:29:04   作者:大梦谁先觉i  
动态代理指的是,代理类和目标类的关系在程序运行的时候确定的,客户通过代理类来调用目标对象的方法,是在程序运行时根据需要动态的创建目标类的代理对象。本文将通过案例详细讲解一下动态代理,需要的可以参考一下

JDK动态代理:利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

CGlib动态代理:利用ASM(开源的Java字节码编辑库,操作字节码)开源包,将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

区别:JDK代理只能对实现接口的类生成代理;CGlib是针对类实现代理,对指定的类生成一个子类,并覆盖其中的方法,这种通过继承类的实现方式,不能代理final修饰的类。

强制使用CGlib

<!-- proxy-target-class="false"默认使用JDK动态代理 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<aop-config proxy-target-class="true">

具体代码示例:

/**
 * 目标接口类
 */
public interface UserManager {    
    public void addUser(String id, String password);    
    public void delUser(String id);    
}
/**
 * 接口实现类
 */
public class UserManagerImpl implements UserManager {    
    @Override
    public void addUser(String id, String password) {    
        System.out.println("调用了UserManagerImpl.addUser()方法!");
    }    
    @Override
    public void delUser(String id) {    
        System.out.println("调用了UserManagerImpl.delUser()方法!");
    }    
}
/**
 * JDK动态代理类
 */
public class JDKProxy implements InvocationHandler {    
    // 需要代理的目标对象
    private Object targetObject;    
    public Object newProxy(Object targetObject) {
        // 将目标对象传入进行代理    
        this.targetObject = targetObject;
        // 返回代理对象 
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
    }    
    // invoke方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 进行逻辑处理的函数
        checkPopedom();
        Object ret = null;
        // 调用invoke方法
        ret = method.invoke(targetObject, args);
        return ret;
    }    
    private void checkPopedom() {
        // 模拟检查权限   
        System.out.println("检查权限:checkPopedom()!");    
    }    
} 
/**
 * CGlib动态代理类
 */
 public class CGLibProxy implements MethodInterceptor {    
    // CGlib需要代理的目标对象
    private Object targetObject;
    public Object createProxyObject(Object obj) {
        this.targetObject = obj;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(obj.getClass());
        enhancer.setCallback(this);
        Object proxyObj = enhancer.create();
        return proxyObj;
    }
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object obj = null;
        // 过滤方法
        if ("addUser".equals(method.getName())) {
            // 检查权限
            checkPopedom();
        }
        obj = method.invoke(targetObject, args);
        return obj;
    }    
    private void checkPopedom() {
        System.out.println("检查权限:checkPopedom()!");
    }
}
/**
 * 测试类
 */
public class ProxyTest {
    public static void main(String[] args) {
        UserManager userManager = (UserManager)new CGLibProxy().createProxyObject(new UserManagerImpl());
        System.out.println("CGLibProxy:");
        userManager.addUser("tom", "root");
        System.out.println("JDKProxy:");
        JDKProxy jdkProxy = new JDKProxy();
        UserManager userManagerJDK = (UserManager)jdkProxy.newProxy(new UserManagerImpl());
        userManagerJDK.addUser("tom", "root");
    }
}

// 运行结果
CGLibProxy:
检查权限checkPopedom()!
调用了UserManagerImpl.addUser()方法!
JDKProxy:
检查权限checkPopedom()!
掉用了UserManagerImpl.addUser()方法!

总结:

  • JDK代理使用的是反射机制实现aop的动态代理,CGLIB代理使用字节码处理框架asm,通过修改字节码生成子类。所以jdk动态代理的方式创建代理对象效率较高,执行效率较低,cglib创建效率较低,执行效率高;
  • JDK动态代理机制是委托机制,具体说动态实现接口类,在动态生成的实现类里面委托hanlder去调用原始实现类方法,CGLIB则使用的继承机制,具体说被代理类和代理类是继承关系,所以代理类是可以赋值给被代理类的,如果被代理类有接口,那么代理类也可以赋值给接口。

到此这篇关于Java实例讲解动态代理的文章就介绍到这了,更多相关Java动态代理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring 框架的 MethodInterceptor 简介及示例代码

    Spring 框架的 MethodInterceptor 简介及示例代码

    MethodInterceptor接口定义了一个方法Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) ,该方法在代理对象的方法被调用时被触发,这篇文章主要介绍了Spring 框架的 MethodInterceptor 简介及示例代码,需要的朋友可以参考下
    2023-09-09
  • springboot跨域访问cros与@CrossOrigin注解详析

    springboot跨域访问cros与@CrossOrigin注解详析

    这篇文章主要给大家介绍了关于springboot跨域访问cros与@CrossOrigin注解的相关资料,跨域是指不同域名之间相互访问,它是浏览器的同源策略造成的,是浏览器对JavaScript施加的安全限制,需要的朋友可以参考下
    2023-12-12
  • JAVA IO API使用详解

    JAVA IO API使用详解

    本文通过理论、用法、实例详细说明了JAVA IO的使用,大家参考其中的实例代码实现自己的JAVA IO程序
    2013-11-11
  • springboot整合netty-mqtt-client实现Mqtt消息的订阅和发布示例

    springboot整合netty-mqtt-client实现Mqtt消息的订阅和发布示例

    本文主要介绍了springboot整合netty-mqtt-client实现Mqtt消息的订阅和发布示例,文中根据实例编码详细介绍的十分详尽,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • JVM的常用命令汇总

    JVM的常用命令汇总

    监测java应用,最方便的就是直接使用jdk提供的现成工具,在jdk的安装的bin目录下,已经提供了多种命令行监测工具。本文为大家总结了几个JVM的常用命令,需要的可以参考一下
    2022-10-10
  • Spring通过工具类实现获取容器中的Bean

    Spring通过工具类实现获取容器中的Bean

    在实际开发中,我们往往要用到Spring容器为我们提供的诸多资源,例如想要获取到容器中的配置、获取到容器中的Bean等等。本文为大家详细讲讲工具类如何获取到Spring容器中的Bean,需要的可以参考一下
    2022-06-06
  • 详解设计模式在Spring中的应用(9种)

    详解设计模式在Spring中的应用(9种)

    这篇文章主要介绍了详解设计模式在Spring中的应用(9种),详细的介绍了这9种模式在项目中的应用,具有一定的参考价值,感兴趣的可以了解一下
    2019-04-04
  • SpringBoot中@Import注解如何正确使用

    SpringBoot中@Import注解如何正确使用

    这篇文章主要介绍了SpringBoot中@Import注解的使用方式,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-06-06
  • Spring Boot集成Redis实战操作功能

    Spring Boot集成Redis实战操作功能

    这篇文章主要介绍了Spring Boot集成Redis实战操作,包括如何集成redis以及redis的一些优点,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-11-11
  • java IO流将一个文件拆分为多个子文件代码示例

    java IO流将一个文件拆分为多个子文件代码示例

    这篇文章主要介绍了java IO流将一个文件拆分为多个子文件代码示例,具有一定借鉴价值,需要的朋友可以参考下。
    2017-12-12

最新评论