Design patterns

The proxy pattern

The proxy pattern extends the capabilities of our objects by providing them with a mediation secretary that accesses them.

Static agent

For example, we want to invite Liu Yifei to dinner, and Liu Yifei faces so many parties every day, no time to contact us directly, at this time Liu Yifei invited an agent that is the broker. If we want to make an appointment for Liu Yifei’s dinner, we need to make an appointment with her agent. After dinner, Liu Yifei’s agent will help her record it.

Abstract theme class Star, Liu Yifei can abstract out the Star, with the interface to eat

package com.wangscaler.proxy;

/ * * *@author wangscaler
 * @dateThe loathsome 2021.06.30 * /
public interface Star {
    public void eat(a);
}
Copy the code

Real topic category: LiuYiFei

package com.wangscaler.proxy;

/ * * *@author wangscaler
 * @dateThe loathsome 2021.06.30 * /
public class LiuYiFei implements Star {
    public void eat(a) {
        System.out.println("Accompany Liu Yifei to dinner"); }}Copy the code

Proxy class: The broker Agent, which implements EAT but calls LiuYiFei’s methods

package com.wangscaler.proxy;

/ * * *@author wangscaler
 * @dateThe loathsome 2021.06.30 * /
public class Agent implements Star {
    private LiuYiFei liuYiFei;

    public Agent(LiuYiFei liuYiFei) {
        this.liuYiFei = liuYiFei;
    }

    public void eat(a) {
        System.out.println("Make a dinner reservation with Liu Yifei.");
        liuYiFei.eat();
        System.out.println("Record the incident."); }}Copy the code

main

package com.wangscaler.proxy;

/ * * *@author wangscaler
 * @dateThe loathsome 2021.06.30 * /
public class StaticProxy {
    public static void main(String[] args) {
        Agent agent = new Agent(newLiuYiFei()); agent.eat(); }}Copy the code

Both the static proxy target object and the proxy object must implement the same interface, and both the target object and the proxy object must be maintained once new methods are added.

A dynamic proxy

The real proxy object is created dynamically by the JDK at runtime for us, so it is also called JDK proxy, interface proxy. In contrast to static proxies, only the target object needs to implement the interface, and the proxy object does not need to implement the interface.

In this case, the abstract theme class Star and the real theme class LiuYiFei remain unchanged.

Add dynamic proxy ProxyFactory

package com.wangscaler.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/ * * *@author wangscaler
 * @date2021.06.30 14:07 * /
public class ProxyFactory {
    private Object target;

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

    public Object getProxyInstance(a) {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("Reservation");
                Object object = method.invoke(target, args);
                System.out.println("Record the incident.");
                returnobject; }}); }}Copy the code

main

package com.wangscaler.proxy;

/ * * *@author wangscaler
 * @date2021.06.30 14:07 * /
public class DynamicProxy {
    public static void main(String[] args) {
        Star liuYiFei = new LiuYiFei();
        Star object = (Star) newProxyFactory(liuYiFei).getProxyInstance(); object.eat(); }}Copy the code

At this time we want to add methods only need Star

package com.wangscaler.proxy;

/ * * *@author wangscaler
 * @dateThe loathsome 2021.06.30 * /
public interface Star {
    public void eat(a);

    public void play(a);
}
Copy the code

Add the interface and implement it in LiuYiFeia.

package com.wangscaler.proxy;

/ * * *@author wangscaler
 * @dateThe loathsome 2021.06.30 * /
public class LiuYiFei implements Star {
    public void eat(a) {
        System.out.println("Accompany Liu Yifei to dinner");
    }

    public void play(a) {
        System.out.println("Accompany Liu Yifei on the set."); }}Copy the code

What about individual objects that don’t need to implement the interface? Use the Cglib proxy! Of course, Cglib can also be used for class methods of interfaces.

Additional agent

The agent class cannot be final, otherwise an IllegalArgumentException will be reported

Start by introducing cglib’s dependencies. Open the Maven repository and import the latest version.


      
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>DesignPattern</artifactId>
    <version>1.0 the SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>
    </dependencies>
</project>
Copy the code

Because Cglib does not implement the interface, LiuYiFei changes it to the following

package com.wangscaler.proxy;

/ * * *@author wangscaler
 * @date2021.06.30 and * /
public class LiuYiFei1 {
    public void eat(a) {
        System.out.println("Accompany Liu Yifei to dinner");
    }

    public void play(a) {
        System.out.println("Accompany Liu Yifei on the set."); }}Copy the code

Then create ProxyFactory1 to implement Intercept. enhancer.setCallback(this); This line causes the program to call back to the Intercept method

package com.wangscaler.proxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;


/ * * *@author wangscaler
 * @date2021.06.30 14:07 * /
public class ProxyFactory1 implements MethodInterceptor {
    private Object target;

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

    public Object getProxyInstance(a) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Reservation");
        Object object = method.invoke(target,objects);
        System.out.println("Record the incident.");
        returnobject; }}Copy the code

main

package com.wangscaler.proxy;

/ * * *@author wangscaler
 * @date2021.06.30 and * /
public class CglibProxy {
    public static void main(String[] args) {
        LiuYiFei1 liuYiFei1 = new LiuYiFei1();
        LiuYiFei1 object = (LiuYiFei1) newProxyFactory1(liuYiFei1).getProxyInstance(); object.eat(); object.play(); }}Copy the code

conclusion

The proxy mode can play the role of intermediary, protection and enhancement to the target object, on the one hand, it reduces the coupling of the program, on the other hand, it increases the scalability of the program.

The package generated by Cglib is called the package name of our program, while the JDK proxy is the underlying package name.

The main roles of the proxy mode are as follows.

  1. Abstract topic classes: Business methods that declare real topics and proxy object implementations through interfaces or abstract classes, such as the Star class above.
  2. Real topic classes: These are the target objects, the objects that the business actually calls, and the methods that implement abstract topic classes, such as LiuYiFei above.
  3. Proxy class: Contains internal references to real topics that can access, control, or extend the functionality of real topics. So Spring Aop often uses proxies.

When to use: Exercise some control over access to a class.

The resources

  • JAVA Design Pattern