欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

静态代理&动态代理

程序员文章站 2022-06-10 20:53:56
...

静态代理&动态代理

前言

本文为学习记录,可能有误请谅解…

1.代理模式

1.1何为代理模式

代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。代理是通过代理对象访问目标对象,从而实现在目标对象基础上增加额外的功能,例如日志记录、事务控制、性能监控等。减少重复代码、让代码复用性好。

分为静态代理动态代理两种。

1.2为何要代理

Case1:没有目标类源码(java文件),或者是已经源码封装好了,无法直接操作到某个对象,但又必须和那个对象有所互动

Case2:只需要在某一处调用的地方进行额外功能添加,如果直接在目标类修改某个方法会导致所有调用该类此方法的逻辑都发生改变(牵一发而动全身)

2.静态代理与动态代理

2.1两者区别

静态代理与动态代理的区别在于是否生成class文件。使用静态代理是需要我们编写代理类,即最终在项目编译的文件中会看到class文件,而动态代理是动态生成字节码文件,在一些主流框架技术如spring、mybatis等使用了动态代理技术。

静态代理的实现方式有继承聚合

动态代理的实现方式有JDK动态代理和Cglib动态代理

2.2静态代理——继承

继承方式的思想:使用代理类(子类)继承目标类(父类),然后重写目标类的方法,在重写方法内部调用目标类的方法,再增加代理的功能。

  • 目标类

    package com.proxy;
    
    /**
     * 目标类
     * @author CMK
     * @date 2020-10-19 16:42
     */
    public class UserService {
        public void test(){
            System.out.println("目标类方法执行......");
        }
    }
    
  • 代理类(继承目标类)

    package com.proxy;
    
    /**
     * 代理类
     * @author CMK
     * @date 2020-10-19 16:44
     */
    public class UserProxyService extends UserService {
        @Override
        public void test() {
            super.test(); //执行目标类方法
            System.out.println("代理类方法执行......");
        }
    }
    
  • 运行测试类

    package com.proxy;
    
    /**
     * 运行测试类
     * @author CMK
     * @date 2020-10-19 16:46
     */
    public class Test {
        public static void main(String[] args) {
            UserService userService = new UserProxyService(); //此处使用了多态写法
            userService.test(); //继承关系中子类有该方法则调用子类方法,没有则调用父类方法
        }
    }
    
  • 运行结果

    静态代理&动态代理

2.3静态代理——聚合

聚合的思想:代理类和目标类实现了一个公共接口,创建代理对象时,通过构造方法或者set方法将目标对象进行聚合

  • 公共接口

    package com.proxy.aggregation;
    
    /**
     * 公共接口
     * @author CMK
     * @date 2020-10-19 17:22
     */
    public interface Service {
        /**
         * 接口方法
         */
        void test();
    }
    
    
  • 目标类

    package com.proxy.aggregation;
    
    /**
     * 目标类
     * @author CMK
     * @date 2020-10-19 17:23
     */
    public class TargetService implements Service {
        /**
         * 目标类重写接口方法
         */
        @Override
        public void test() {
            System.out.println("目标类执行接口方法......");
        }
    }
    
    
  • 代理类(通过构造方法进行聚合)

    package com.proxy.aggregation;
    
    /**
     * @author CMK
     * @date 2020-10-19 17:25
     */
    public class ProxyService implements Service {
    
        //将target目标对象当作代理类的一个成员属性
        private Service target;
    	
        //代理类构造方法
        public ProxyService(Service target) {
            this.target = target;
        }
    
        /**
         * 代理类重写接口方法
         */
        @Override
        public void test() {
            //调用目标对象的方法
            target.test();
            //编写代理增加的方法
            System.out.println("代理类方法执行......");
    
        }
    }
    
  • 运行测试类1

    package com.proxy;
    
    import com.proxy.aggregation.ProxyService;
    import com.proxy.aggregation.Service;
    import com.proxy.aggregation.TargetService;
    
    /**
     * 运行测试类
     * @author CMK
     * @date 2020-10-19 16:46
     */
    public class Test {
        public static void main(String[] args) {
            
            Service service = new ProxyService(new TargetService()); //通过创建目标类对象将其设置到代理类中
            service.test();
        }
    }
    
  • 代理类(通过set方法进行聚合)

    package com.proxy.aggregation;
    
    /**
     * @author CMK
     * @date 2020-10-19 17:25
     */
    public class ProxyService implements Service {
    
        //target目标对象
        private Service target;
    
        //set方法
        public void setTarget(Service target) {
            this.target = target;
        }
    
        /**
         * 代理类重写接口方法
         */
        @Override
        public void test() {
            //调用目标对象的方法
            target.test();
            //编写代理增加的方法
            System.out.println("代理类执行接口方法......");
    
        }
    }
    
  • 运行测试类2

    package com.proxy;
    
    import com.proxy.aggregation.ProxyService;
    import com.proxy.aggregation.Service;
    import com.proxy.aggregation.TargetService;
    
    /**
     * 运行测试类
     * @author CMK
     * @date 2020-10-19 16:46
     */
    public class Test {
        public static void main(String[] args) {
    
            ProxyService proxyService = new ProxyService();
            proxyService.setTarget(new TargetService());
            proxyService.test();
        }
    }
    
    
  • 运行结果

    静态代理&动态代理

2.4动态代理——JDK

JDK动态代理:基于接口的代理,必须有接口才可以代理。

  • 接口

    package com.proxy.service;
    
    /**
     * 接口
     * @author CMK
     * @date 2020-10-19 19:11
     */
    public interface UserService {
        //接口方法
        void test();
    }
    
  • 目标类(接口实现类)

    package com.proxy.service.impl;
    
    import com.proxy.service.UserService;
    
    /**
     * 目标类(接口实现类)
     * @author CMK
     * @date 2020-10-19 19:13
     */
    public class UserServiceImpl implements UserService {
        @Override
        public void test() {
            System.out.println("目标类实现接口方法......");
        }
    }
    
  • JDK动态代理

    通过代理,对目标类进行增强

    package com.proxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * JDK动态代理
     * @author CMK
     * @date 2020-10-19 19:18
     */
    public class JDKProxy {
    
        /**
         * 生成一个目标类的代理对象
         * @param target 目标对象
         * @return Object类型的代理类(可明确指定UserService类型)
         */
        public static Object getProxy(Object target){
            return Proxy.newProxyInstance(             // 代理(Proxy)的newProxyInstance()方法参数说明
                    JDKProxy.class.getClassLoader(),   // 参数1:目标对象的类加载器
                    target.getClass().getInterfaces(), // 参数2:目标对象实现的接口
                    new InvocationHandler() {          // 参数3:事件处理程序,用于对目标进行增强
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //proxy:目标对象增强后的代理对象
                    //method:目标对象的方法
                    //args:目标对象的方法参数
                    System.out.println("JDK动态代理:执行目标类方法前,此处就可以写代理对象的方法逻辑");
    
                    Object result = method.invoke(target,args); //执行目标方法(涉及到反射)
    
                    System.out.println("JDK动态代理:执行目标类方法后,此处也可以写代理对象的方法逻辑");
    
                    return result;
                }
            });
        }
    }
    
  • 运行测试类

    package com.proxy;
    
    import com.proxy.service.UserService;
    import com.proxy.service.impl.UserServiceImpl;
    
    /**
     * 运行测试类
     * @author CMK
     * @date 2020-10-19 16:46
     */
    public class Test {
        public static void main(String[] args) {
    
            UserService jdkProxy = (UserService) JDKProxy.getProxy(new UserServiceImpl()); //因为在getUserServiceProxy那里返回的是Object类型,所以此处需要进行强转才可调用下面的test()
            jdkProxy.test();
        }
    }
    
  • 运行结果

    静态代理&动态代理

2.5动态代理——Cglib

目标对象没有接口时,JDK动态代理无法使用,此时需要使用Cglib动态代理。

Cglib动态代理:在运行时期动态生成一个类的子类方式实现对目标对象的功能拓展。

  • pom.xml

    Cglib动态代理需要引入cglib包

    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>3.1</version>
    </dependency>
    
  • 基类

    package com.proxy.service;
    
    /**
     * @author CMK
     * @date 2020-10-19 20:02
     */
    public class UserServiceImpl {
    
        public void test(){
            System.out.println("目标类方法......");
        }
    }
    
  • Cglib动态代理

    package com.proxy;
    
    import java.lang.reflect.Method;
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    import java.lang.reflect.Method;
    
    /**
     * Cglib动态代理
     *
     * @author CMK
     * @date 2020-10-19 20:03
     */
    public class CglibProxy {
    
        public static Object getProxy(Object target) {
    
            return Enhancer.create(           //增强者(Enhancer)的create()方法参数说明
                    target.getClass(),        //参数1:设置目标对象的类
                    new MethodInterceptor() { //参数2:拦截目标对象的方法,进行增强
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    //o:目标对象增强后的代理对象,也是目标对象的子类
                    //method:目标对象的方法
                    //objects:目标对象的方法参数
                    System.out.println("Cglib动态代理:执行目标类方法前,此处就可以写代理对象的方法逻辑");
    
                    Object result = method.invoke(target, objects); //执行目标方法(涉及到反射)
    
                    System.out.println("Cglib动态代理:执行目标类方法后,此处也可以写代理对象的方法逻辑");
    
                    return result;
                }
            });
        }
    }
    
  • 测试运行类

    package com.proxy;
    
    import com.proxy.service.UserServiceImpl;
    
    /**
     * 运行测试类
     * @author CMK
     * @date 2020-10-19 16:46
     */
    public class Test {
        public static void main(String[] args) {
          
            UserServiceImpl cglibProxy = (UserServiceImpl) CglibProxy.getProxy(new UserServiceImpl());
            cglibProxy.test();
        }
    }
    
  • 运行结果

静态代理&动态代理