Proxy mode (Java implementation)

The proxy mode is one of the common design modes. As the name suggests, the proxy mode is that the proxy object has the functions of the real object, and completes the corresponding operation instead of the real object, and can enhance the operation before and after the operation is executed. (Provide a proxy for the real object, and then allow other objects to access the real object through the proxy)

Divided into

  • static proxy

  • dynamic proxy

    • jdk dynamic proxy

    • cglib dynamic proxy

static proxy

The real class and the proxy class should implement the same interface, and the method of the real class can be implemented in the proxy class, and the method of the real class can be enhanced at the same time, and the injection of multiple real objects can be completed in a proxy class.

public interface IRentHouse {
    void rentHouse();
}
public class RentHouse implements IRentHouse {

    @Override
    public void rentHouse() {
        System.out.println("实现租房");
    }
}
public class IntermediaryProxy implements IRentHouse {
    private IRentHouse iRent;
    public IntermediaryProxy(IRentHouse iRentHouse) {
        iRent=iRentHouse;
    }
    @Override
    public void rentHouse() {
        System.out.println("交中介费");
        iRent.rentHouse();
        System.out.println("中介负责维修管理");
    }
}
//client测试类
public class TestStaticProxy {
    public static void main(String[] args) {
        //定义租房
        IRentHouse iRentHouse = new RentHouse();
        //定义中介
        IRentHouse intermediaryProxy = new IntermediaryProxy(iRentHouse);
        //中介租房
        intermediaryProxy.rentHouse();
    }
}

dynamic proxy

从静态代理的代码中可以发现,静态代理的缺点显而易见,那就是当真实类的方法越来越多的时候,这样构建的代理类的代码量是非常大的,所以就引进动态代理.

Dynamic proxies allow a single class with one method (the proxy class) to service multiple method calls of any class (the real class) with any number of methods ,

The JAVA reflection mechanism is in the running state. For any class, you can know all the properties and methods of this class; for any object, you can call any of its methods and properties; this dynamically obtained information and dynamic call The function of the method of the object is called the reflection mechanism of the java language.

jdk dynamic proxy (interface proxy)

The Jdk proxy involves the InvocationHandler interface and the Proxy class in the java.lang.reflect package. The core method is

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 

In the jdk dynamic proxy process, the interface is actually proxied, because when creating a proxy instance, it relies on the newProxyInstance method of the Proxy class in the java.lang.reflect package, and this method needs this parameter to take effect;

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException{
        ……
}

The following is a case to illustrate the complete process of jdk dynamic proxy:

//接口
public interface Person {
    void wakeup();
    void sleep();
}
//实现类1
public class Student implements Person{
    private String name;
    public Student() {
    }
    public Student(String name) {
        this.name = name;
    }
    @Override
    public void wakeup() {
        System.out.println("学生"+name+"早晨醒来啦");
    }
    @Override
    public void sleep() {
        System.out.println("学生"+name+"晚上睡觉啦");
    }
}
//代理类
public class JDKDynamicProxy implements InvocationHandler {
    private Object bean;
    public JDKDynamicProxy(Object bean) {
        this.bean=bean;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodname=method.getName();
        if (methodname.equals("wakeup")){
            System.out.println("早安~~~");
        }else if(methodname.equals("sleep")){
            System.out.println("晚安~~~");
        }
        return method.invoke(bean,args);
    }
}
//测试类
public class TestJDKDynamicProxy {
    public static void main(String[] args) {
        JDKDynamicProxy proxy = new JDKDynamicProxy(new Student("张三"));
        //创建代理实例
        Person student = (Person) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{Person.class}, proxy);
        student.wakeup();
        student.sleep();
    }
}

The output is

早安~~
学生张三早晨醒来啦
晚安~~
学生张三晚上睡觉啦
The method in the interface, and the invoke method rewritten in the proxy class, but the invoke() method is not explicitly called, but the invoke method is called in the interface virtual proxy class generated during the process of creating the proxy instance. (Forcibly convert the instance of Sproxy0 into a reference of the corresponding interface type, then execute the interface method, and then execute invoke () in the proxy class) 

Summary comparison:

1. In the static proxy, the proxy class and the real class implement the same interface and rewrite the same method; in the jdk dynamic proxy, the proxy class has little relationship with the real class, and the proxy class implements non-intrusive code extension.

2. When the method in the interface increases in the static proxy, the amount of code in the proxy class will also increase, which is obviously inappropriate; jdk dynamic proxy solves this problem. When the business increases, the code of the proxy class will not increase.

3. The jdk dynamic proxy implements the jdk's own InvocationHandler interface. The class that implements this interface is also called an interceptor class, or a proxy class.

cglib dynamic proxy

It can be seen from the above that the prerequisite for jdk dynamic proxy is that there must be an interface, and there are still many scenarios without interfaces. At this time, cglib dynamic proxy is needed. CGLIB (Code Generation Library) is an ASM-based word Section code generation library, which allows us to modify and dynamically generate bytecode at runtime. CGLIB implements proxies through inheritance. The subclass of the implementation class is generated during the cglib dynamic proxy process. How does cglib create the subclass of the implementation class out of thin air? The following is the test code

//所需的代理类
public class CglibProxy implements MethodInterceptor {
    private Enhancer enhancer=new Enhancer();
    private Object bean;

    public CglibProxy(Object bean) {
        this.bean = bean;
    }

    public Object getProxy(){
        //设置需要创建子类的类
        enhancer.setSuperclass(bean.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        String methodName = method.getName();
        if (methodName.equals("wakeup")){
            System.out.println("早安~~~");
        }else if(methodName.equals("sleep")){
            System.out.println("晚安~~~");
        }
        return method.invoke(bean,objects);
    }
}
//测试类
public class TestCglibProxy {
    public static void main(String[] args) {
        //生成虚拟代理类的代码,本来虚拟代理子类是看不见的,
        //下面这句话的作用就是把执行过程中cglib增强后的class字节码文件
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\aop");
        CglibProxy proxy = new CglibProxy(new Cat("咪咪"));
        Cat cat = (Cat) proxy.getProxy();
        cat.wakeup();
        cat.sleep();
    }
}

Summarize:

The difference between cglib dynamic proxy and jdk dynamic proxy is obvious, but the implementation logic is similar. The cglib proxy class achieves the purpose of proxy enhancement code by implementing MethodInterceptor, rewriting the intercept method, and generating subclasses of the proxy class; while Jdk proxy is through Implement InvocationHandler, rewrite the invoke method, and achieve the purpose of code enhancement by generating the proxy class of the interface. Therefore, the implementation of jdk dynamic proxy requires an interface, but cglib does not need it. Spring 5.0 and above and springboot 2.0 and above use cglib dynamic implementation by default AOP.

Guess you like

Origin blog.csdn.net/Ally441/article/details/132269713