zoukankan      html  css  js  c++  java
  • 关于JDK动态代理和cglib动态代理

    在spring AOP中,由于通知类中抽取了原始对象中的公共方法,使得原始对象的方法变得不能进行完整的操作。但是我们还是想通过某个方式实现原始对象完成完整操作,我们可以通过为原始对象创建代理对象的方式达到目的,有两种方式:JDK动态代理和cglib动态代理。

    一、JDK动态代理

      1、概述:针对内存中的Class对象,使用类加载器,动态为目标对象的实现接口创建代理对象。也就是说JDK代理是对对象做代理。

      2、具体实现(如下代码):

         创建一个接口及实现类     

         public interface UserDao {
          public void add();

         }

         public class UserDaoImp implements UserDao {

          @Override
          public void add() {
            System.out.println("新增用户操作");

           }

         }

        创建实现JDK动态代理的工具类

        public class JdkProxy implements InvocationHandler {

          private UserDao userDao;

          // 定义一个方法用于创建JDK代理对象
          public UserDao createProxyObject(UserDao userDao) {
            // 被代理对象作为参数传入进来
            this.userDao = userDao;
            // 获取类加载器:对谁代理,使用谁的类加载器
            ClassLoader classLoader = userDao.getClass().getClassLoader();
            // 获取被代理对象的所有实现接口
            Class<?>[] interfaces = userDao.getClass().getInterfaces();

            // 创建Handler对象,用于增强拦截,为了方便调用使用实现InvocationHandler接口的方式  

            InvocationHandler h = this;

            Object obj = Proxy.newProxyInstance(classLoader, interfaces, h);
              return (UserDao) obj;

        }

          @Override
          public Object invoke(Object proxy, Method method, Object[] args)
          throws Throwable {
            System.out.println("连接数据库");// 增强操作
            // 对原始操作进行调用(使用反射)
            method.invoke(userDao, args);
            System.out.println("关闭数据库");
            return null;
           }

          public static void main(String[] args) {
            // 1、创建一个对象
            UserDao dao = new UserDaoImp();
            // 2、为原始对象创建代理对象
            UserDao daoProxy = new JdkProxy().createProxyObject(dao);
            // 3、使用代理对象运行操作
            daoProxy.add();

          }
        }

    二、cglib动态代理

      1、概述:非接口实现的对象,对于不使用接口的业务类,无法使用JDK动态代理。cglib采用底层字节码急速,可以为一个类创建子类,也就是cglib是解决无接口代理问题,

      是对类做代理。

           2、具体实现(如下代码)

      创建Person类及生成代理的方法

      public class Person {

        public void action() {
        System.out.println("Java程序员");
        }
      }

      public Person createProxyObject(Class clazz) {
        // cglib中的核心对象是Enhance,用来在内存中创建一段动态的类的字节码
        Enhancer enhancer = new Enhancer();//此时没有做继承
        // 为其指定父类,除了完成继承关系外,还将父类所有的方法反射过来,并在自己的类中创建这些方法
        enhancer.setSuperclass(clazz);
        // 进行功能的增强
        // 设置方法的调用拦截
        Callback callback = new MethodInterceptor() {
          // proxy:代理对象
          // method:被拦截的方法对象
          // args:调用函数
          // methodProxy:使用代理机制创建被代理对象的方法
          @Override
          public Object intercept(Object proxy, Method method, Object[] args,
            MethodProxy methodProxy) throws Throwable {
            // 做增强
            System.out.println("Java后端程序员还会烤肉");
            // 调用原始的操作
            Object ret = methodProxy.invokeSuper(proxy, args);
            return ret;
          }
        };
      // 设置具体的回调操作
      enhancer.setCallback(callback);
      // 创建内存中全新类的对象
      Object proxyObj = enhancer.create();
      return (Person) proxyObj;
      }

      3、小结:cglib动态代理机制其实是利用继承的思想来实现,在代码中可以看出,代理机制创建代理对象,把被代理的对象当做父类,把代理的对象

    当做子类,走父类运行,走子类的实现,这体现了继承与多态的思想。

    三、总结

      cglib可以对任意的类进行代理,JDKdial只能对接口实现的类进行代理。

  • 相关阅读:
    年终总结 2016-08-28 22:04 422人阅读 评论(26) 收藏
    [mysql]MySQL Daemon failed to start 2016-08-14 21:27 1121人阅读 评论(18) 收藏
    solrr初步了解 2016-07-31 22:29 380人阅读 评论(4) 收藏
    基于spring-boot的测试桩设计--几种常见的controller
    利用Factory-boy和sqlalchemy来批量生成数据库表数据
    job中shell脚本异常(删除不存在容器),导致job被打断执行的问题 脚本优化方法
    利用Factory-boy来生成实例数据
    pytest相关资源收集
    pytest 用 @pytest.mark.usefixtures("fixtureName")装饰类,可以让执行每个case前,都执行一遍指定的fixture
    pytest fixture 利用 params参数实现用例集合
  • 原文地址:https://www.cnblogs.com/cxyad/p/10152832.html
Copyright © 2011-2022 走看看