代理

一、代理模式

定义

由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

代理模式的主要优点有:

  • 代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
  • 代理对象可以扩展目标对象的功能;
  • 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度,增加了程序的可扩展性。

代理模式的结构与实现

模式的结构

  • 抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。
  • 真实主题(Real Subject)类:实现了抽象主题中的具体业务,是最终要引用的对象。
  • 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。

image.png

模式的实现

// 抽象接口
public interface Subject {
    void optation();
}

// 真实实现
public class RealSubject implements Subject {
    @Override
    public void optation() {
        System.out.println("Progremming RealSubjecg [doSometing].");
    }
}

// 代理类
public class MyProxy {

    private RealSubject subject = new RealSubject();

    public void optaion(){
        System.out.println("Preprocessor before targer method running.");
        subject.optation();
        System.out.println("Postprocessor after target method running.");
    }

}
// 测试类
public class Client {
    public static void main(String[] args) {
        MyProxy proxy = new MyProxy();
        proxy.optaion();
    }
}

二、Jdk Dynamic Proxy

JDK的动态代理的对象必须实现一个或多个接口。

模式的实现


// 代理类
public class JdkDynamicProxy implements InvocationHandler {

    private Object target;

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

    public <T> T getProxy(){
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Preprocessor by JDKProxy before targer method running.");
        method.invoke(target,args);
        System.out.println("Postprocessor by JDKProxy after target method running.");
        return null;
    }

}

//测试类
public class Client {
    public static void main(String[] args) {
        Subject subject = new JdkDynamicProxy(new RealSubject()).getProxy();
        subject.optation();
    }
}

// 执行结果
Preprocessor by JDKProxy before targer method running.
Progremming RealSubjecg [doSometing].
Postprocessor by JDKProxy after target method running.

三、Cglib Dynamic Proxy

Cglib代理,也叫做子类代理,是一个强大的高性能的代码生成包,它可以在运行期在内存中构建一个子类对象从而实现扩展Java类与实现Java接口。CGLIB包的底层是通过使用一个字节码处理框架ASM,来转换字节码并生成新的类。ASM具体的功能实现涉及到JVM内部结构包括class文件的格式和指令集。

特点

  • 需要引入cglib jar文件,spring的核心包中已经包括了cglib功能,所以直接引入spring-core-3.2.5.jar也可。
  • 代理的类不能为final, 否则报错。
  • 目标对象的方法如果为final/static,不会被拦截,即不会执行目标对象额外的业务方法。

引入依赖

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

模式实现

// 目标类
public class Subject {

    public void insert(){
        System.out.println("insert");
        select();
    }

    public void select(){
        System.out.println("select");
    }

    public void delete(){
        System.out.println("delete");
    }

    public void updata(){
        System.out.println("updata");
    }
}

// 代理类
public class CglibDynamicProxy implements MethodInterceptor {

    private static Object target;

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

    public <T> T getProxy(){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return (T) enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

        System.out.print("Before ");
        methodProxy.invokeSuper(o,objects);
        return null;
    }
}

//测试类
public class Client {
    public static void main(String[] args) {
        CglibDynamicProxy cglibDynamicProxy = new CglibDynamicProxy(new Subject());
        Subject subject = cglibDynamicProxy.getProxy();
        subject.insert();
    }
}

// 执行结构
Before insert
Before select

四、JDk与Cglib代理

生成的代理文件

1、jdk代理(InvocationHandler)

Jdk代理会根据接口生成动态代理字节码文件,生成的代理类实现目标类(Subject)[$oroxy.class implement Subject]。执行目标方法的方式是通过反射的方法直接调用原Bean的方法。

2、cglib代理(MethodInterceptor)

Cglib代理是通过ASM生成继承被代理类的class(多个),会重写被代理类的方法。执行目标方法的方式是子类重写的方法。

代理的重复性

代理的重复增强是在增强的类中方法A调用方法B,是否会重复执行代理增强的功能。

  • Jdk动态代理不会重复增强[通过反射调用原方法]
  • cglib动态代理会重复增强[执行代理实现的子类]
posted @ 2020-10-17 09:32  Shalow  阅读(151)  评论(0)    收藏  举报