Proxy(代理模式)

文章目录

  • 代理模式
  • 静态代理模式
    • 代码实现
  • 动态代理模式
    • JDK动态代理
    • CGLIB动态代理
    • 总结

代理模式

代理模式是通过代理对象来访问真实对象,通过建立一个对象代理类,由代理对象控制原对象的引用,从而实现对真实对象的操作。

静态代理模式

代码实现

创建接口

	package com.lq.proxy.v1;
	
	/**
	 * @author lq
	 * @PACKAGE_NAME: com.lq.proxy.v1
	 * @CLASS_NAME: Court
	 * @date 2022/11/16 21:08
	 * @Description:  
	 */
	public interface Court {
	
	    void doCourt();
	}

创建被代理类

	/**
	 * @author lq
	 * @PACKAGE_NAME: com.lq.proxy.v1
	 * @CLASS_NAME: Person
	 * @date 2022/11/16 21:09
	 * @Description: 人物类  被代理者
	 */
	public class Person implements Court {
	
	    private String name;
	
	    public Person(String name) {
	        this.name = name;
	    }
	
	    @Override
	    public void doCourt() {
	        System.out.println(name + "说:我没有犯罪!");
	    }
	}

创建静态代理类

	package com.lq.proxy.v1;
	
	/**
	 * @author lq
	 * @PACKAGE_NAME: com.lq.proxy.v1
	 * @CLASS_NAME: Lawyer
	 * @date 2022/11/16 21:08
	 * @Description:  律师   代理者
	 */
	public class Lawyer implements Court{
	
	    //被代理类
	    private Person person;
	
	    public Lawyer(Person person) {
	        this.person = person;
	    }
	    @Override
	    public void doCourt() {
	        person.doCourt();
	        System.out.println("律师取证:视频证明张三当时正在旅游,不在案发现场!");
	        System.out.println("律师总结:张三不可能犯罪!");
	    }
	}

测试

	package com.lq.proxy.v1;
	
	/**
	 * @author lq
	 * @PACKAGE_NAME: com.lq.proxy.v1
	 * @CLASS_NAME: Main
	 * @date 2022/11/16 21:11
	 * @Description:
	 */
	public class Main {
	
	    public static void main(String[] args) {
	        Person person =new Person("张三");
	        Court court=new Lawyer(person);
	        court.doCourt();
	    }
	}

结果:

	张三说:我没有犯罪!
	律师取证:视频证明张三当时正在旅游,不在案发现场!
	律师总结:张三不可能犯罪!

动态代理模式

动态代理可以针对于一些不特定的类或者一些不特定的方法进行代理,我们可以在程序运行时动态的变化代理的规则,代理类在程序运行时才创建的代理模式成为动态代理。这种情况下,代理类并不是在Java代码中定义好的,而是在程序运行时根据我们的在Java代码中的“指示”动态生成的。

代理类型 使用场景
JDK动态代理 面向接口
cglib动态代理 面向父类

JDK动态代理

声明接口

	package com.lq.proxy.v2;
	
	/**
	 * @author lq
	 * @PACKAGE_NAME: com.lq.proxy.v2
	 * @CLASS_NAME: Dinner
	 * @date 2022/11/16 21:13
	 * @Description:
	 */
	public interface Dinner {
	    /**
	     * 吃什么东西
	     * @param foodName
	     */
	    void eat(String foodName);
	
	    /**
	     * 喝什么东西
	     * @param drinkName
	     */
	    void drink(String drinkName);
	}

创建实现类

	package com.lq.proxy.v2;
	
	/**
	 * @author lq
	 * @PACKAGE_NAME: com.lq.proxy.v2
	 * @CLASS_NAME: Student
	 * @date 2022/11/16 21:14
	 * @Description:
	 */
	public class Student implements Dinner {
	
	    private String name;
	
	    public Student(String name) {
	        this.name = name;
	    }
	
	    @Override
	    public void eat(String foodName) {
	        System.out.println(name + ":正在吃-->" + foodName);
	    }
	
	    @Override
	    public void drink(String drinkName) {
	        System.out.println(name + "正在喝-->" + drinkName);
	    }
	}

JDK代理实现

	package com.lq.proxy.v2;

	import java.lang.reflect.InvocationHandler;
	import java.lang.reflect.Method;
	import java.lang.reflect.Proxy;
	
	/**
	 * @author lq
	 * @PACKAGE_NAME: com.lq.proxy.v2
	 * @CLASS_NAME: Main
	 * @date 2022/11/16 21:16
	 * @Description:         Proxy  动态代理 JDK动态代理    面向接口
	 */
	public class Main {
	
	    public static void main(String[] args) {
	        Dinner dinner = new Student("张三");
	
	        // 通过Porxy动态代理获得一个代理对象,在代理对象中,对某个方法进行增强
	
	        // ClassLoader loader,被代理的对象的类加载器
	        ClassLoader classLoader = dinner.getClass().getClassLoader();
	
	        // Class[] interfaces,被代理对象所实现的所有接口
	        Class[] interaces = dinner.getClass().getInterfaces();
	
	        // InvocationHandler h,执行处理器对象,专门用于定义增强的规则
	        InvocationHandler handler = new InvocationHandler() {
	            // invoke 当我们让代理对象调用任何方法时,都会触发invoke方法的执行
	            @Override
	            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	                // Object proxy, 生成后的代理类 及下边的  dinnerProxy
	                // Method method,被代理的方法
	                //Object[] args,被代理方法运行时的实参
	                Object res = null;
	                if (method.getName().equals("eat")) {
	                    System.out.println("饭前洗手");
	                    // 让原有的eat的方法去运行
	                    res = method.invoke(dinner, args);
	                    System.out.println("饭后刷碗");
	                } else {
	                    // 如果是其他方法,那么正常执行就可以了
	                    res = method.invoke(dinner, args);
	                }
	                return res;
	            }
	        };
	        Dinner dinnerProxy = (Dinner) Proxy.newProxyInstance(classLoader, interaces, handler);
	        dinnerProxy.eat("包子");
	        dinnerProxy.drink("可乐");
	    }
	}

结果

	饭前洗手
	张三:正在吃-->包子
	饭后刷碗
	张三正在喝-->可乐

CGLIB动态代理

创建目标类

	package com.lq.proxy.v3;
	
	/**
	 * @author lq
	 * @PACKAGE_NAME: com.lq.proxy.v3
	 * @CLASS_NAME: Person
	 * @date 2022/11/16 21:28
	 * @Description:
	 */
	public class Person {
	
	
	    public Person() {
	    }
	
	
	    public void eat(String foodName) {
	        System.out.println("正在吃 -->" + foodName);
	    }
	}

CGLIB动态代理实现

	package com.lq.proxy.v3;
	
	import org.springframework.cglib.proxy.Enhancer;
	import org.springframework.cglib.proxy.MethodInterceptor;
	import org.springframework.cglib.proxy.MethodProxy;
	
	import java.lang.reflect.Method;
	
	/**
	 * @author lq
	 * @PACKAGE_NAME: com.lq.proxy.v3
	 * @CLASS_NAME: Main
	 * @date 2022/11/16 21:29
	 * @Description:
	 */
	public class Main {
	
	    public static void main(String[] args) {
	        Person person = new Person();
	        // 获取一个Person的代理对象
	
	        // 1 获得一个Enhancer对象
	        Enhancer enhancer = new Enhancer();
	
	        // 2 设置父类字节码
	        enhancer.setSuperclass(person.getClass());
	
	        // 3 获取 MethodInterceptor 对象 用于定义增强规则
	        MethodInterceptor methodInterceptor = new MethodInterceptor() {
	            @Override
	            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
	                //Object o,  生成之后的代理对象 personProxy
	                //Method  method,  父类中原本要执行的方法  Person >>> eat()
	                //Object[] objects, 方法在调用时传入的实参数组
	                //MethodProxy  methodProxy  子类中重写父类的方法 personProxy >>> eat()
	
	                Object res = null;
	                if (method.getName().equals("eat")) {
	                    // 如果是eat方法 则增强并运行
	                    System.out.println("饭前洗手");

	                    res = methodProxy.invokeSuper(o, objects); 
	
	                    //res =  method.invoke(person,objects); 
	                    System.out.println("饭后刷碗");
	                } else {
	                    // 如果是其他方法 不增强运行
	                    res = methodProxy.invokeSuper(o, objects); // 子类对象方法在执行,默认会调用父类对应被重写的方法
	                }
	                return res;
	            }
	        };
	        // 4 设置 methodInterceptor 回调
	        enhancer.setCallback(methodInterceptor);
	
	        // 5 获得代理对象
	        Person personProxy = (Person) enhancer.create();
	
	        // 6 使用代理对象完成功能
	        personProxy.eat("包子");
	    }
	}

结果

	饭前洗手
	正在吃 -->包子
	饭后刷碗

总结

  1. 在不修改原有代码的 或者没有办法修改原有代码的情况下 ,增强对象功能 ,使用代理对象代替原来的对象去完成功能进而达到拓展功能的目的
  2. JDK Proxy 动态代理面向接口的动态代理 一定要有接口和实现类的存在 代理对象增强的是实现类 在实现接口的方法重写的方法生成的代理对象只能转换成 接口的不能转换成 被代理类代理对象只能增强接口中定义的方法 实现类中其他和接口无关的方法是无法增强的代理对象只能读取到接口中方法上的注解 不能读取到实现类方法上的注解
  3. CGLIB动态代理是面向父类的动态代理,可以增强定义的方法还可以读取父类方法上所有的注解。

你可能感兴趣的:(23种设计模式,代理模式,java)