1. 代理模式(Proxy Pattern)

代理模式(Proxy Pattern) ,给某一个对象提供一个代理,并由代理对象控制对原对象的引用,对象结构型模式。这种也是静态代理

11. 代理模式(Proxy Pattern) - 图1

代理模式包含如下角色:

Subject: 抽象主体角色(抽象类或接口)

Proxy: 代理主体角色(代理对象类)

RealSubject: 真实主体角色(被代理对象类)

2. 静态代理

  • 静态代理就是装饰器模式
  • 装饰器模式是代理模式的一种

Subject: 抽象主体角色(抽象类或接口)

  1. /**
  2. * 抽象主体 被代理角色
  3. */
  4. public interface ManTikTok {
  5. void tiktok();
  6. }

Proxy: 代理主体角色(代理对象类)

  1. /**
  2. * 代理一般和被代理对象属于同一个接口
  3. * 静态代理就是装饰器模式
  4. * 装饰器模式是代理模式的一种
  5. */
  6. public class TiktokProxy implements ManTikTok{
  7. //被代理对象
  8. private MiTikTok miTikTok;
  9. public TiktokProxy(MiTikTok miTikTok) {
  10. this.miTikTok = miTikTok;
  11. }
  12. @Override
  13. public void tiktok() {
  14. System.out.println("增强功能");
  15. miTikTok.tiktok();
  16. }
  17. }

RealSubject: 真实主体角色(被代理对象类)

  1. /**
  2. * subject 主体
  3. *
  4. */
  5. public class MiTikTok implements ManTikTok{
  6. @Override
  7. public void tiktok() {
  8. System.out.println("雷军正在直播");
  9. }
  10. }

测试

  1. public static void main(String[] args) {
  2. TiktokProxy tiktokProxy = new TiktokProxy(new MiTikTok());
  3. tiktokProxy.tiktok();
  4. }

3. JDK动态代理

利用JDK动态代理 反射增强

Subject: 抽象主体角色(抽象类或接口)

  1. /**
  2. * 抽象主体 被代理角色
  3. */
  4. public interface ManTikTok {
  5. void tiktok();
  6. }
  1. public interface SellTiktok {
  2. void send();
  3. }

Proxy: 代理主体角色(代理对象类)

  1. public class JdkTiktokProxy<T> implements InvocationHandler {
  2. private T target;
  3. //接受被代理对象
  4. public JdkTiktokProxy(T target) {
  5. this.target = target;
  6. }
  7. /**
  8. * 获取被代理对象的 代理对象
  9. *
  10. * @param t
  11. * @param <T>
  12. * @return
  13. */
  14. public static <T> T getProxy(T t) {
  15. /**
  16. * ClassLoader loader, 当前被代理的类加载器
  17. * Class<?>[] interfaces, 当前被代理对象所实现的所有接口 必须要有接口 如果无则会报异常 代理对象无法创建
  18. * InvocationHandler h 当前被代理对象执行目标方法的时候我们使用h可以定义拦截增强方法
  19. */
  20. Object o = Proxy.newProxyInstance(t.getClass().getClassLoader(),
  21. t.getClass().getInterfaces(),
  22. new JdkTiktokProxy<>(t)
  23. );
  24. return (T) o;
  25. }
  26. /**
  27. * 定义目标方法的拦截逻辑:每个方法都会进来的
  28. *
  29. * @param proxy
  30. * @param method
  31. * @param args
  32. * @return
  33. * @throws Throwable
  34. */
  35. @Override
  36. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  37. //反射执行
  38. System.out.println("被代理对象原身方法被执行");
  39. Object invoke = method.invoke(target, args);
  40. System.out.println("返回值" + invoke);
  41. return invoke;
  42. }
  43. }

RealSubject: 真实主体角色(被代理对象类)

  1. /**
  2. * subject 主体
  3. *
  4. */
  5. public class MiTikTok implements ManTikTok,SellTiktok {
  6. @Override
  7. public void tiktok() {
  8. System.out.println("雷军正在直播");
  9. }
  10. @Override
  11. public void send() {
  12. System.out.println("卖货 只要999");
  13. }
  14. public void self(){
  15. System.out.println("自身方法");
  16. }
  17. }

测试方法

  1. /**
  2. * 动态代理模式
  3. * JDK要求被代理对象必须要有接口
  4. *
  5. */
  6. public class MainTest {
  7. public static void main(String[] args) {
  8. ManTikTok miTikTok = new MiTikTok();
  9. ManTikTok proxy = JdkTiktokProxy.getProxy(miTikTok);
  10. proxy.tiktok();
  11. System.out.println("---------------");
  12. SellTiktok sellTikTok = (SellTiktok)miTikTok;
  13. SellTiktok proxy1 = JdkTiktokProxy.getProxy(sellTikTok);
  14. proxy1.send(); //只能调用某个接口的实现方法
  15. System.out.println("---------------");
  16. MiTikTok miTikTok1 = (MiTikTok) miTikTok;
  17. //无法代理对象本类自己的方法 proxy只能转成接口类
  18. // MiTikTok proxy2 = JdkTiktokProxy.getProxy(miTikTok1);
  19. miTikTok1.self();
  20. System.out.println(Arrays.asList(miTikTok1.getClass().getInterfaces()));
  21. }
  22. }

4. cglib动态代理

pom.xml导入cglib依赖

  1. <dependencies>
  2. <dependency>
  3. <groupId>cglib</groupId>
  4. <artifactId>cglib</artifactId>
  5. <version>3.1</version>
  6. </dependency>
  7. </dependencies>

cglib不依赖于接口代理反射,他会根据代理对象去继承一个新类,从而代理这个对象。

Proxy: 代理主体角色(代理对象类)

  1. public class CglibProxy {
  2. //为任意对象创建代理
  3. public static <T> T crateProxy(T t) {
  4. //1. 创建一个增强器
  5. Enhancer enhancer = new Enhancer();
  6. //2.设置增强哪个类的功能 增强器为这个类动态创建一个子类
  7. enhancer.setSuperclass(t.getClass());
  8. //3.设置回调
  9. enhancer.setCallback(new MethodInterceptor() {
  10. @Override
  11. public Object intercept(Object o, Method method //为了能获取原方法的一些原数据信息
  12. , Object[] objects, MethodProxy methodProxy) throws Throwable {
  13. //编写拦截逻辑
  14. System.out.println("cglib 代理");
  15. //当前方法的信息
  16. // method.getAnnotatedReturnType();
  17. //目标方法进行执行 原对象的方法
  18. Object invoke = methodProxy.invokeSuper(o, objects);
  19. return invoke;
  20. }
  21. });
  22. //创建代理对象
  23. Object o = enhancer.create();
  24. return (T)o;
  25. }
  26. }

RealSubject: 真实主体角色(被代理对象类)

  1. /**
  2. * subject 主体
  3. *
  4. */
  5. public class MiTikTok {
  6. public void self(){
  7. System.out.println("自身方法");
  8. }
  9. }

测试类

  1. public class CglibTest {
  2. public static void main(String[] args) {
  3. //原对象都不用new
  4. MiTikTok miTikTok = new MiTikTok();
  5. MiTikTok proxy = CglibProxy.crateProxy(miTikTok);
  6. proxy.self();
  7. }
  8. }

5. 应用场景

  • MyBatis的mapper到底是什么?怎么生成的?

    • 动态代理

    • UserMapper、CityMapper,mybatis帮我们写实现MapperProxy

  • Alibaba Seata的DataSourceProxy是什么?

  • DruidDataSource存在的Proxy模式

    • 监控链…