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

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

作者: 程就人生 | 来源:发表于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代理。

    相关文章

      网友评论

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

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