zoukankan      html  css  js  c++  java
  • Java的动态代理

    1.什么是代理?

    简单来说,代理就是帮[目标对象]去完成它应该做,但是不想或者不擅长做的事情。

    代理在程序的世界里面,主要是为了增强[目标对象]的各种方法。

    2.代理模式分为静态代理和动态代理

    • 静态代理就是程序员自己编写一个代理类
    • 动态代理就是让程序帮忙在运行时动态生成一个代理类

    3.动态代理的实现方式分为两种,生成的代理类都是继承了Proxy

    • JDK原生实现:
    /**
     * 主要作用就是生成代理类 使用JDK的动态代理实现 它是基于接口实现的
     */
    public class JDKProxyFactory implements InvocationHandler {
    
        //目标对象的引用
        private Object target;
    
        //通过构造方法将目标对象注入到代理对象中
        public JDKProxyFactory(Object target) {
            super();
            this.target = target;
        }
    
        /**
         * 获取proxy代理类实例
         */
        public Object getProxy() {
    
            //如何生成一个代理类呢?
            //1、编写源文件
            //2、编译源文件为class文件
            //3、将class文件加载到JVM中(ClassLoader)
            //4、将class文件对应的对象进行实例化(反射)
            
            // Proxy是JDK中的API类
            // 第一个参数:目标对象的类加载器
            // 第二个参数:目标对象的接口()
            // 第二个参数:代理对象的执行处理器
            Object object = Proxy.newProxyInstance(target.getClass().getClassLoader(),
                    target.getClass().getInterfaces(), this);
    
            return object;
        }
    
        /**
         * 重写invoke方法,把method重新invoke到target(传入的类实例)上,然后可以在前后进行方法的额外增强功能
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("这是增强的功能");
            // 下面的代码,是反射中的API用法
            // 该行代码,实际调用的是[目标对象]的方法
            // 利用反射,调用[目标对象]的方法
            Object returnValue = method.invoke(target, args);
          
            return returnValue;
        }
    }
    • CGLib实现:
    /**
     * 主要作用就是生成代理类
     * 使用CGLib动态代理技术实现 它是基于继承的方式实现的
     */
    public class CgLibProxyFactory implements MethodInterceptor{
    
    
        public Object getProxyByCgLib(Class clazz) {
    
            // 创建增强器
            Enhancer enhancer = new Enhancer();
            // 设置需要增强的类的类对象
            enhancer.setSuperclass(clazz);
    
            // 设置回调函数
            enhancer.setCallback(this);
    
            // 获取增强之后的代理对象
            return enhancer.create();
        }
    
        /***
         * Object proxy:这是代理对象,也就是[目标对象]的子类
         * Method method:[目标对象]的方法
         * Object[] arg:参数
         * MethodProxy methodProxy:代理对象的方法
         */
        @Override
        public Object intercept(Object proxy, Method method, Object[] arg, MethodProxy methodProxy)
                throws Throwable {
            // 因为代理对象是目标对象的子类
            // 该行代码,实际调用的是目标对象的方法
            // proxy:代理对象
            // 父类目标对象,调用父类目标对象中的方法
            System.out.println("这是cglib的代理方法");
            
            // 调用[目标对象]的方法
            Object returnValue = methodProxy.invokeSuper(proxy, arg);
            return returnValue;
        }
    }
    • 使用
    @Test
        public void testJDKProxy() {
            
            //1、创建目标对象
            UserService service = new UserServiceImpl();
            
            //2、生成代理对象
            JDKProxyFactory proxyFactory = new JDKProxyFactory(service); 
            UserService proxy = (UserService) proxyFactory.getProxy();
            
            //3、调用目标对象的方法
            service.saveUser();
            System.out.println("===============");
            //4、调用代理对象的方法
            proxy.saveUser();
        }
        
        @Test
        public void testCgLibProxy() {
            //创建目标对象
            UserService service = new UserServiceImpl();
            
            //生成代理对象
            CgLibProxyFactory proxyFactory = new CgLibProxyFactory();
            UserService proxy = (UserService) proxyFactory.getProxyByCgLib(service.getClass());
            
            //调用目标对象的方法
            service.saveUser();
            System.out.println("===============");
            //调用代理对象的方法
            proxy.saveUser();
        }

    4.总结

    1)既然JDK已经帮我们实现了Proxy,为什么还要用第三方库CGLib来实现呢?

      从代码里,我们不难发现,JDK的实现方式是有缺陷的,因为要想用这种方式实现代理,【目标对象】必须要有Interface。显然CGLib的实现没有要求【目标对象】有实现的Interface

    2)实现原理

    ps:可以看出CGLib就算没有要求目标对象类有Interface,它内部也按照它的样子制作了一个Interface出来

      因为method.invoke(object, args)传的object必须是和提取出这个method的类是实现了同一个Interface的

      因此,Interface对于整个流程来说是必须品,只不过CGLib帮我们在它内部处理了。

  • 相关阅读:
    新型肺炎实时动态
    大学排名数据爬取
    python BeautifulSoup基本用法
    爬虫爬取
    人口普查系统--信息查找
    人口普查系统--信息删除
    人口普查系统--信息修改
    人口普查系统--信息登记
    期中考试题目
    期中考试前准备--数据库查找代码
  • 原文地址:https://www.cnblogs.com/amiezhang/p/9684735.html
Copyright © 2011-2022 走看看