• 11 结构型模式- 代理模式


    结构性模式一共包括七种:

    代理模式、桥接模式、装饰者模式、适配器模式、门面(外观)模式、组合模式、和享元模式。
    在这里插入图片描述

    1 代理模式介绍

    在这里插入图片描述
    软件开发中的代理
    代理模式中引入了一个新的代理对象,代理对象在客户端对象和目标对象之间起到了中介的作用,它去掉客户不能看到的内容和服务或者增加客户需要的额外的新服务.

    在这里插入图片描述

    2 代理模式原理

    在这里插入图片描述

    3 静态代理实现

    在这里插入图片描述

    举例:保存用户功能的静态代理实现
    public interface IUserDao {
    
        void save();
    }
    
    • 1
    • 2
    • 3
    • 4
    /**
     * 目标类
     **/
    public class UserDaoImpl implements IUserDao {
    
        @Override
        public void save() {
            System.out.println("保存数据");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    /**
     * 代理类
     **/
    public class UserDaoProxy implements IUserDao {
    
        private IUserDao target;
    
        public UserDaoProxy(IUserDao target) {
            this.target = target;
        }
    
        @Override
        public void save() {
            System.out.println("开启事务"); //扩展额外的功能
            target.save();
            System.out.println("提交事务");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    /**
         * 静态代理
         *     优点: 可以在不修改目标类的前提下,扩展目标类的功能
         *     缺点:
         *        1.冗余.由于代理对象要实现和目标对象一致的接口,会产生很多的代理.
         *        2.不易维护.一旦接口中增加方法,目标对象和代理对象都要进行修改.
         */
        @Test
        public void testStaticProxy(){
    
            //目标类
            IUserDao dao = new UserDaoImpl();
    
            //代理对象
            UserDaoProxy proxy = new UserDaoProxy(dao);
            proxy.save();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    4 JDK动态代理

    在这里插入图片描述
    在这里插入图片描述

    举例:保存用户功能的静态代理实现

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * 代理工厂类-动态的生成代理对象
     **/
    public class ProxyFactory {
    
        //维护一个目标对象
        private Object target;
    
        public ProxyFactory(Object target) {
            this.target = target;
        }
    
        //为目标对象生成代理对象
        public Object getProxyInstance(){
    
            return Proxy.newProxyInstance(
                    //目标类使用的类加载器
                    target.getClass().getClassLoader(),
                    //目标对象实现的接口类型
                    target.getClass().getInterfaces(),
                    new InvocationHandler() { //事件处理器
    
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
                            System.out.println("开启事务");
                            method.invoke(target,args);
                            System.out.println("提交事务");
                            return null;
                        }
                    }
            );
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    测试:

    public static void main(String[] args) {
    
            IUserDao userDao = new UserDaoImpl();
            System.out.println(userDao.getClass()); //目标对象的信息
    
            IUserDao proxy = (IUserDao) new ProxyFactory(userDao).getProxyInstance();//获取代理对象
            System.out.println(proxy.getClass());
            proxy.save();//代理方法
    
            while (true){}
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    5 类是如何动态生成的

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    6代理类的调用过程

    我们通过借用阿里巴巴的一款线上监控诊断产品 Arthas(阿尔萨斯) ,对动态生成的代理类代码进行查看.
    在这里插入图片描述
    在这里插入图片描述
    代理类代码如下:

    package com.sun.proxy;
    
    import com.mashibing.proxy.example01.IUserDao;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;
    
    public final class $Proxy0 extends Proxy implements IUserDao {
    	
    	private static Method m1;
    	private static Method m3;
    	private static Method m2;
    	private static Method m0;
    	
    	public $Proxy0(InvocationHandler invocationHandler) {
    		super(invocationHandler);
    	}
    
    	static {
    		try {	
    			m1 = Class.forName("java.lang.Object").getMethod("equals",Class.forName("java.lang.Object"));
    			m3 = Class.forName("com.mashibing.proxy.example01.IUserDao").getMethod("save", new Class[0]);
    			m2 = Class.forName("java.lang.Object").getMethod("toString", newClass[0]);
    			m0 = Class.forName("java.lang.Object").getMethod("hashCode", newClass[0]);
    			return;
    		}catch (NoSuchMethodException noSuchMethodException) {
    			throw new NoSuchMethodError(noSuchMethodException.getMessage());
    		}catch (ClassNotFoundException classNotFoundException){
    			throw new NoClassDefFoundError(classNotFoundException.getMessage());
    		}
    	}
    
    	public final boolean equals(Object object) {
    		try {
    			return (Boolean)this.h.invoke(this, m1, newObject[]{object});
    		}catch (Error | RuntimeException throwable) {
    			throw throwable;
    		}catch (Throwable throwable) {
    			throw new UndeclaredThrowableException(throwable);
    		}
    	}
    
    	public final String toString() {
    		try {
    			return (String)this.h.invoke(this, m2, null);
    		}catch (Error | RuntimeException throwable) {
    			throw throwable;
    		}catch (Throwable throwable) {
    			throw new UndeclaredThrowableException(throwable);
    		}
    	}
    
    	public final int hashCode() {
    		try {
    			return (Integer)this.h.invoke(this, m0, null);
    		}catch (Error | RuntimeException throwable) {
    			throw throwable;
    		}catch (Throwable throwable) {
    			throw new UndeclaredThrowableException(throwable);
    		}
    	}
    
    	public final void save() {
    		try {
    			this.h.invoke(this, m3, null);
    			return;
    		}catch (Error | RuntimeException throwable) {
    			throw throwable;
    		}catch (Throwable throwable) {
    			throw new UndeclaredThrowableException(throwable);
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    爲了方便理解简化后的代码:

    package com.sun.proxy;
    
    import com.mashibing.proxy.example01.IUserDao;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;
    
    public final class $Proxy0 extends Proxy implements IUserDao {
    	
    	private static Method m3;
    	
    	public $Proxy0(InvocationHandler invocationHandler) {
    		super(invocationHandler);
    	}
    
    	static {
    		try {
    			m3 = Class.forName("com.mashibing.proxy.example01.IUserDao").getMethod("save", new Class[0]);
    			return;
    		}
    	}
    
    	public final void save() {
    		try {
    			this.h.invoke(this, m3, null);
    			return;
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    在这里插入图片描述

    7 cglib动态代理

    在这里插入图片描述
    在这里插入图片描述
    使用cglib 需要引入cglib 的jar包,如果你已经有spring-core的jar包,则无需引入,因为spring中包含了cglib 。

    <dependency>
    	<groupId>cglib</groupId>
    	<artifactId>cglib</artifactId>
    	<version>3.2.5</version>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    示例代码
    目标类:

    /**
     * 目标类
     **/
    public class UserServiceImpl {
        //查询功能
        public List<User>  findUserList(){
            return Collections.singletonList(new User("tom",23));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    cglib代理类,需要实现MethodInterceptor接口,并指定代理目标类target

    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    import java.text.SimpleDateFormat;
    import java.util.Calendar;
    //在實現動態代理的同時擴展一個日志的功能
    public class UserLogProxy implements MethodInterceptor {
        /**
         * 生成CGLIB动态代理类方法
         * @param target    需要被代理的目标类
         * @return: java.lang.Object  代理类对象
         */
        public Object getLogProxy(Object target){
    
            //增强器类,用来创建动态代理类
            Enhancer enhancer = new Enhancer();
    
            //设置代理类的父类字节码对象
            enhancer.setSuperclass(target.getClass());
    
            //设置回调
            enhancer.setCallback(this);
    
            //创建动态代理对象,并返回
            return enhancer.create();
        }
    
        /**
         * 实现回调方法
         * @param o      代理对象
         * @param method  目标对象中的方法的Method实例
         * @param args      实际参数
         * @param methodProxy  代理类对象中的方法的Method实例
         * @return: java.lang.Object
         */
        @Override
        public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    
            Calendar instance = Calendar.getInstance();
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    
            System.out.println(format.format(instance.getTime()) + "[ " +method.getName() +"] 查询用户信息...");
            Object result = methodProxy.invokeSuper(o, args);
            return null;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    public class User {
    
        private String name;
    
        private int age;
    
        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    8 cglib代理流程

    在这里插入图片描述

    9代理模式总结

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    參考文章:

    https://www.cnblogs.com/hg-blogs/p/17314887.html
    
    • 1
  • 相关阅读:
    Springboot在云原生中的作用
    Debian11.5安装Podman并以多容器方式搭建LEMP环境
    Spring数据绑定之DataBinder篇---01
    .Net 472&6.0 Razor编译时的小差异
    【算法学习】LeetCode 724寻找数组的中心下标
    什么是乌干达COC认证?乌干达COC认证是什么意思?
    js数组介绍:创建、length的用法、冒泡排序法、选择排序法
    基于yolov8的半自动标注
    【java面试题】Redis多线程模型怎么理解,那它会有线程安全问题吗?
    【iOS】多线程梳理
  • 原文地址:https://blog.csdn.net/weixin_39563769/article/details/133998598