美文网首页
代理模式 之 静动态代理,这么简单,一看就懂!

代理模式 之 静动态代理,这么简单,一看就懂!

作者: 程就人生 | 来源:发表于2022-04-28 20:01 被阅读0次

说到代理模式,你最先想到的是什么?在实际项目中,你有单独写过代理模式吗?spring中的动态代理又有哪些类型?有什么区别?


代理模式(proxy pattern),可以简单理解为一个类代理另一个类的功能。它是一种结构型模式。代理模式分为:静态代理和动态代理。

业务场景:想要保护一个对象时,想要增强一个对象时,都可以使用代理模式。
关键代码:代理对象实现了被代理类的接口,并且持有被代理对象的引用。

下面看UML类图:


代码实现步骤:
1.形状接口;

/**
 * 1.形状接口
 * @author 程就人生
 * @Date
 */
public interface IShape {
  public void draw();
}

2.接口实现类;

/**
 * 2.矩形继承了形状接口;
 * @author 程就人生
 * @Date
 */
public class Rectangle implements IShape{
  
  // 宽度
  private int width;
  // 高度
  private int height;

  @Override
  public void draw() {
    System.out.println("rectangle:width=" + width + ",height=" + height);
  }

  public int getWidth() {
    return width;
  }

  public void setWidth(int width) {
    this.width = width;
  }

  public int getHeight() {
    return height;
  }

  public void setHeight(int height) {
    this.height = height;
  }
}

3.矩形代理类,静态代理类;

public static void main(String[] argo){    
    Rectangle rectangle = new Rectangle();
    rectangle.setHeight(10);
    rectangle.setWidth(5);
    IShape shape = new RectangleProxy(rectangle);
    shape.draw();
}

测试代码;

public static void main(String[] argo){    
    Rectangle rectangle = new Rectangle();
    rectangle.setHeight(10);
    rectangle.setWidth(5);
    IShape shape = new RectangleProxy(rectangle);
    shape.draw();
}

测试结果;

提前做点什么
rectangle:width=5,height=10
之后做点什么

这段代码的意思是:为矩形加了一个代理类,在代理类中对画的方法进行了增强,画之前做了一点事,画之后又做了一点事。

4.动态代理类,JDK实现方式;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * 动态代理 - JDK实现方式
 * @author 程就人生
 * @Date
 */
public class RectangleProxy2 implements InvocationHandler {
  
  // 被代理对象
  private Object target;
  
  //通过反射机制获取对象,获取接口
  public Object getInstance(Object target) throws Exception{
    this.target = target;
    Class<?> clazz = target.getClass();
    return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // 业务增强
    before();
    Object obj = method.invoke(this.target, args);
    after();
    return obj;
  }
  
  private void before(){
    System.out.println("提前做点什么");
  }
  
  private void after(){
    System.out.println("之后做点什么");
  }
}

测试代码:

public static void main(String[] argo){    
    Rectangle rectangle = new Rectangle();
    rectangle.setHeight(10);
    rectangle.setWidth(5);
    // 动态代理测试1
    IShape shape = (IShape) new RectangleProxy2().getInstance(rectangle);
    shape.draw();
}

测试结果:

提前做点什么
rectangle:width=5,height=10
之后做点什么

5.动态代理类,CGLib实现方式;

/**
 * 无继承的被代理类
 * @author 程就人生
 * @Date
 */
public class Rectangle2 {
  
  // 宽度
  private int width;
  // 高度
  private int height;

  public void draw() {
    System.out.println("rectangle:width=" + width + ",height=" + height);
  }

  public int getWidth() {
    return width;
  }

  public void setWidth(int width) {
    this.width = width;
  }

  public int getHeight() {
    return height;
  }

  public void setHeight(int height) {
    this.height = height;
  }
}

import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

/**
 * 动态代理 - CGlib
 * @author 程就人生
 * @Date
 */
public class RectangleProxy3 implements MethodInterceptor {

  //通过反射机制获取对象,获取接口
  public Object getInstance(Class<?> clazz) throws Exception{
    Enhancer enhancer = new Enhancer();
    // 即将生成的新类的父类
    enhancer.setSuperclass(clazz);
    enhancer.setCallback(this);
    return enhancer.create();
  }
  
  private void before(){
    System.out.println("提前做点什么");
  }
  
  private void after(){
    System.out.println("之后做点什么");
  }

  @Override
  public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    // 业务增强
    before();
    Object obj = methodProxy.invokeSuper(o, objects);
    after();
    return obj;
  }
}

测试代码:

// 动态代理测试2
Rectangle2 rectangle2 = (Rectangle2) new RectangleProxy3().getInstance(Rectangle2.class);
rectangle2.draw();

测试结果:

提前做点什么
rectangle:width=0,height=0
之后做点什么

静态代理和动态代理的区别:

  • 静态代理只能手动完成代理操作,如果被代理类增加了新方法,代理类需要同步增加,违背了开闭原则。
  • 动态代理采用运行时生成代码的方式,取消了被代理类的扩展限制,遵循开闭原则。

最后总结
上面代码使用了两种实现动态代理的方式,第一种被代理对象有接口,第二种被代理对象无接口,所以Spring中代理的选择是:

  • 当bean有实现接口时,Spring就会用JDK动态代理;
  • 当bean没有实现接口时,Spring就会选择CGLib代理;
  • 可以通过设置aspectj-autoproxyd的proxy-target-class为true,来强制使用CGLib代理。

相关文章

  • 代理模式 之 静动态代理,这么简单,一看就懂!

    说到代理模式,你最先想到的是什么?在实际项目中,你有单独写过代理模式吗?spring中的动态代理又有哪些类型?有什...

  • 设计模式之代理模式

    设计模式之代理模式 10分钟看懂动态代理设计模式(升级篇)-对这篇动态代理模式的思路整理 仿JDK实现动态代理逻辑...

  • Java代理模式之JDK动态代理

    了解什么是动态代理模式,可参考Java设计模式之代理模式 简介 JDK动态代理是java.lang.reflect...

  • Java设计模式之代理模式

    Java设计模式之代理模式 代理模式 静态代理 动态代理 为什么需要代理 通过代理,我们能够不用知道委托人是谁,而...

  • 设计模式之代理

    设计模式之代理模式 一、定义 在Java中代理的实现一般分为三种:JDK静态代理、JDK动态代理以及CGLIB动态...

  • Spring之代理模式

    九、代理模式 目录:静态代理、动态代理AOP的底层机制就是动态代理。代理模式分为静态代理和动态代理。接触aop之前...

  • Java代理模式之CGLIB动态代理

    了解什么是动态代理模式,可参考Java设计模式之代理模式 简介 前面我们了解了JDK动态代理技术,发现其真实对象必...

  • 代理模式

    代理模式的典型就是springAOP代理模式的目的有两个:保护目标对象,增强目标对象分类:静态代理和动态代理。 静...

  • 代理模式

    应用场景 代理模式Service层、事务处理 @Transactional 底层AOP代理-JDK动态代理 1.静...

  • Spring AOP源码解析

    欲了解AOP,需先了解Java动态代理;欲了解Java动态代理,先熟悉设计模式之代理模式。入门有道,先从简学。 1...

网友评论

      本文标题:代理模式 之 静动态代理,这么简单,一看就懂!

      本文链接:https://www.haomeiwen.com/subject/ipgdyrtx.html