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

2022-04-28  本文已影响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中代理的选择是:

上一篇 下一篇

猜你喜欢

热点阅读