方法的增强——代理模式

作者: RunAlgorithm | 来源:发表于2019-05-14 07:45 被阅读0次

1. 定义

代理模式:给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问。

代理对象会表现出和目标对象一样的行为,同时对目标对象进行增强,完成了一些无法完成的业务。

现实的例子:

  • 律师。没有完善的法律知识,依然可以进行维权。

  • 代购。无需护照,无需出国,通过朋友直接买到国外的商品。

代理模式-效果图

2. 设计

代理模式两大角色:

  • 目标对象。
  • 代理对象。

类图如下:

代理模式-类图

根据业务模型,代理可以进行分类。

根据我的理解,从对目标对象侵入程度的影响,可以分成两大类:

  • 强权代理。会干涉目标对象的执行。比如权限控制。
  • 佛系代理。不影响目标对象的执行。比如日志记录,方法耗时统计。

代理模式的实现,有个关键的地方就是 代理与目标需要有一致的行为

Java 有这几种方式:

  • 静态代理。设计接口,代理与目标实现接口。
  • JDL 动态代理。在内存中使用反射工具创建代理对象。也需要接口
  • CGLIB 动态代理。使用 ASM 工具直接进行字节码修改,创建代理对象。不需要接口。但属于继承关系,所以无法代理 final 修饰的目标类。

2.1. 静态代理

目标对象创建接口:

public interface ISubject {
    void request();
}

实现类:

public class RealSubject implements ISubject {
    public void request() {
        System.out.println("Hello world!");
    }
}

代理对象也实现该接口,并且持有目标对象的引用:

public class Proxy implements ISubject {
   
   public ISubject target;

    public Proxy(ISubject target) {
        this.target = target;
    }

    public void request() {
        System.out.println("begin");
        target.request();
        System.out.println("end");
    }

    public static ISubject wrap(ISubject target) {
        return new Proxy(target);
    }
}

使用者面向接口编程:

public class TestStaticProxy {

    public static void main(String[] args) {

        ISubject subject = new RealSubject();

        System.out.println("代理前:");
        subject.request();

        System.out.println("代理后:");
        subject = Proxy.wrap(subject);
        subject.request();
    }
}

确实实现了代理。

静态代理实现简单,但有以下弊端:

  • 必须实现同一个接口
  • 目标类型多样,代理类数量会膨胀

2.2. JDK 动态代理

无需静态创建代理类,解决了静态代理类膨胀的问题。

使用 JDK reflect 包的工具,核心类有:

  • Proxy
  • InvocationHandler

两种的关系为:把目标类的接口传递给 Proxy 生成代理对象,在调用接口的方法时,会触发 InvocationHandler 回调,在回调中实现代理业务。

还是上面的例子,这里代理对象实现 InvocationHandler:

public class JDKProxy implements InvocationHandler {

    public Object target;

    public JDKProxy(Object target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("begin");
        Object result = method.invoke(target, args);
        System.out.println("end");
        return result;
    }

    @SuppressWarnings("unchecked")
    public static <T> T wrap(Object target) {
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new JDKProxy(target));
    }
}

使用:

public class TestJDKProxy {

    public static void main(String[] args) {
        ISubject subject = new RealSubject();

        System.out.println("代理前:");
        subject.request();

        System.out.println("代理后:");
        subject = JDKProxy.wrap(subject);
        subject.request();
    }
}

因为动态去创建代理对象,所以 SimpleProxy 可以应用到任务实现接口的目标类型中,而不仅仅是 ISubject。

JDK 动态代理虽强大,但也存在几个问题:

  • 反射消耗性能
  • 目标类必须实现接口

假如我们的目标类就没有实现接口,该怎么做?

2.3. Cglib 动态代理

静态代理和 JDK 动态代理都需要实现接口,但 Cglib 不需要。

Cglib 的底层使用了 ASM 修改字节码,动态创建代理类并加载。

虽然没有实现同一套接口,但与目标类属于继承关系,所以 final 类型的类是无法代理的。

核心类:

  • Enhance,生产代理对象。
  • MethodInterceptor,方法拦截器,执行到对应方法会触发拦截器。

使用方式和 JDK 动态代理类似:

public class CglibProxy implements MethodInterceptor {

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("begin");
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println("end");
        return result;
    }

    @SuppressWarnings("unchecked")
    public static <T> T wrap(Class<T> targetCls) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(targetCls);
        enhancer.setCallback(new CglibProxy());
        return (T) enhancer.create();
    }
}

及时目标对象没有实现接口,也可以进行代理。

3. 应用

在实际开发中,代理模式有着很广的应用,也是很多框架的基础。

具体的应用有:

  • 远程访问:客户端要调用远程对象时可以使用,比如 RPC 调用。

  • 权限控制:方法执行权限的控制。

  • 数据校验:输入参数的校验。

  • 缓存设计:调用频繁或耗性能的操作加入缓存。

  • 统计设计:对一些关键方法进行埋点,加入统计信息。

  • 日志设计:对方法调用加入一些日志记录。

  • 实现 AOP 编程

3.1. Spring:AopProxy

AOP 编程,在我理解就是把通用的规则、规律或者公共行为统一在统一的地方搞定,然后通知到各个要处理的分类对象中(对象没有继承关系)。这样就可以实现非侵入式代码,而且便于维护和修改规则代码。

Spring AOP 编程中,来指定切入点(point cut),获取连接点(join point),编写通知(advice),内聚到一个切面类(Apect)中并使用 @Aspect 注解。

框架会去识别到这个切面类。

然后 Bean 的创建后,内部会使用 AopProxy,结合我们定义好的规则,创建代理对象,找到每个代理对象的连接点,织入增强代码。

AopProxy 的定义如下:

public interface AopProxy {

    /**
     * Create a new proxy object.
     * <p>Uses the AopProxy's default class loader (if necessary for proxy creation):
     * usually, the thread context class loader.
     * @return the new proxy object (never {@code null})
     * @see Thread#getContextClassLoader()
     */
    Object getProxy();

    /**
     * Create a new proxy object.
     * <p>Uses the given class loader (if necessary for proxy creation).
     * {@code null} will simply be passed down and thus lead to the low-level
     * proxy facility's default, which is usually different from the default chosen
     * by the AopProxy implementation's {@link #getProxy()} method.
     * @param classLoader the class loader to create the proxy with
     * (or {@code null} for the low-level proxy facility's default)
     * @return the new proxy object (never {@code null})
     */
    Object getProxy(ClassLoader classLoader);
}

AopProxy 的具体实现有:

  • JdkDynamicAopProxy,使用 JDK 动态代理。
  • CglibAopProxy,使用 Cglib 动态代理。

4. 特点

4.1. 优势

  • 解耦:降低系统耦合。
  • 易修改:代理类独立变化,不影响目标类。
  • 非侵入式 代码。

4.2. 缺点

  • 性能损耗:增加了代理的业务逻辑,目标对象方法处理变慢。
  • 增加复杂度:有些代理实现复杂。

4.3. 注意事项

  • 代理类的设计要注意性能问题。

相关文章

  • 代理模式 静态代理到动态代理

    代理模式这种设计模式是一种使用代理对象来执行目标对象的方法并在代理对象中增强目标对象方法的一种设计模式。代理对象代...

  • java 代理模式详解

    简介 代理是什么? 代理也称“委托”,分为静态代理和动态代理,代理模式也是常用的设计模式之一,具有方法增强、高扩展...

  • 方法的增强——代理模式

    1. 定义 代理模式:给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问。 代理对象会表现出和目标...

  • Java 代理模式:静态代理、JDK 动态代理和 Cglib 动

    代理模式是Java常用的设计模式,代理类通过调用被代理类的相关方法,并对相关方法进行增强。加入一些非业务性代码,比...

  • 代理模式

    简介 代理模式也是一种增强现有对象的方法,Java中主要有静态代理和动态代理两种模式,在实现具体实现层面,...

  • java方法增强的三种方式:继承,装饰和代理

    在java中,在不改变源代码的情况下,实现方法增强的方式有三种: 1,继承 2,装饰者模式 3,代理模式(静态代理...

  • 2018-10-21 java代理模式

    关键字:代理模式,方法增强、方法拦截 代理可以在不改动目标对象的基础上,增加其他额外的功能(扩展功能)。 也就是在...

  • 有关动态代理

    代理模式的作用 方法的增强,不修改源码的情况下增强一些方法,在方法执行前后做任意事,解耦 简单的比喻,就像房主(委...

  • 8 代理设计模式

    代理模式是主要对我们方法执行之前与之后实现增强。代理模式应用场景1,日志采集2,权限控制3,实现aop4,myba...

  • 代理模式

    代理模式: 不改变原有对象的情况下,增强对象或者类的方法 两种实现方法: 1:如果被代理的类继承或实现了某个类,代...

网友评论

    本文标题:方法的增强——代理模式

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