Design Patterns proxy mode (Java)

Brief introduction

Proxy mode outspoken appearance quite high, almost without exception, all frameworks have used the agency model, so look at the profit is still high.

What is a proxy mode

If you use a word to describe proxy mode:

Proxy mode to provide a proxy to control access to the proxy object, that is, we often say that the intermediary is another object

In the development and life often hear forward proxy, reverse proxy such words, illustration

  • Forward Proxy

    As the network reasons we can not access Google, this time we need to find a ladder for us to visit Google, and the information we need to return this proxy ladder

  • Reverse Proxy

    As a server for security, we do not want to expose the actual information to the server, it has been to prevent the attacks of lawless elements, this time we need a proxy unified I accept the user's request, and helps the user requests the back-end user is returned to the user

Proxy mode of action

In a nutshell is decoupled, create a proxy can not access objects for our use, but we can add some additional functionality in the proxy object, so that will not destroy the package, to satisfy the principle of opening and closing

UML

There is a sleeping animal behavior, most people did not see the polar bears (RealSubject) method, we can only shoot the animal world through the program group of photographers (Proxy) to the North Pole, returned from the picture we see a polar bear asleep in its den, and also added a caption on the screen, "look here, there are only hibernating polar bear!"

practice

Agent model to achieve a number of ways can be divided into static and dynamic agent Proxy

Static agents

  • Subject
public interface LifeService {
    String sleep();
}
  • RealSubject
public class WhiteBear implements LifeService {
    @Override
    public String sleep() {
        return "Zzzzzzz";
    }
}
  • Proxy
public class Proxy implements LifeService {

    // 被代理对象
    private LifeService target;

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

    @Override
    public String sleep() {
        // 拿到被代理对象行为的返回值,加上辅助功能,一起返回
        return "快看这里有只冬眠的北极熊! \n" + this.target.sleep();
    }
}
  • Factory, the factory can also do direct new clients
public class ProxyFactory {

    public static Proxy getLifeServiceProxy(Class clz) throws IllegalAccessException, InstantiationException {
        LifeService target = (LifeService) clz.newInstance();
        return new Proxy(target);
    }
}
  • Client
public class Test {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        Proxy proxy = ProxyFactory.getLifeServiceProxy(WhiteBear.class);
        System.out.println(proxy.sleep());
    }

    /**
     * 输出:
     * 快看这里有只冬眠的北极熊!
     * Zzzzzzz
     */
}

You can see the static agent actually quite good understanding that we are the agent and agent classes are written, generates two class bytecode files, that is, the so-called static byte code file already exists in the proxy class before running

insufficient

  • An interface proxy object to serve only one type of object, if you want to proxy many ways, is bound to have carried the agent for each method, the static agent in the slightly larger size of the program will not be able to perform competently.
  • If the interface to add a method, in addition to all the implementation class needs to implement this method, all proxy class also need to implement this method. It increases the complexity of code maintenance

Dynamic Proxy

JDK comes

General idea is in the process of running JVM monitoring, dynamic agency created when the occurrence of specified behavior, to be accessed through a proxy object reflection
  • Subject
public interface LifeService {
    String sleep();
    String wake();
}
  • RealSubject
public class Person implements LifeService {
    @Override
    public String sleep() {
        return "晚安晚安";
    }

    @Override
    public String wake() {
        return "早鸭";
    }
}
  • Proxy

    We realize InvocationHandler this interface to perform proxy behavior invoke method

public class InvocationProxy implements InvocationHandler {

    // 被监控的对象(此例中为Person类实例)
    private LifeService lifeService;

    // 监控启动拿到需要被监控的对象
    public InvocationProxy(LifeService lifeService) {
        this.lifeService = lifeService;
    }

    /**
     * 监控的行为发生时,JVM会拦截到行为执行invoke
     *
     * @param proxy  监控对象:监控行为是否发生
     * @param method 被监控的行为方法
     * @param args   被监控行为方法的参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 因为我们拦截了行为,并且加了一些辅助行为,完成之后我们要替被拦截行为把值返回
        Object result = null;
        String methodName = method.getName();
        if ("sleep".equals(methodName)) {
            result = getTime();
            result += (String) method.invoke(this.lifeService, args);
        } else if ("wake".equals(methodName)) {
            result = getTime();
            result += (String) method.invoke(this.lifeService, args);
        }
        return result;
    }

    // 辅助方法
    private String getTime() {
        return Clock.systemDefaultZone().instant().toString() + "\n";
    }

}
  • Factory, the factory can also do direct new clients
public class ProxyFactory {

    public static LifeService getLifeServiceProxyInstance(Class clz) throws IllegalAccessException, InstantiationException {
        // 创建被代理对象
        LifeService target = (LifeService) clz.newInstance();
        // 绑定到代理执行器中
        InvocationHandler handler = new InvocationProxy(target);
        // JVM层面对被代理对象进行监控,行为发生就动态创建代理对象处理
        LifeService $proxy = (LifeService) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                handler);
        return $proxy;
    }
}
  • Client
public class Test {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException, InterruptedException {
        LifeService zhang = ProxyFactory.getLifeServiceProxyInstance(Person.class);
        System.out.println(zhang.sleep());
        System.out.println(zhang.wake());
    }

    /**
     * 输出:
     * 2019-11-10T05:24:16.932Z
     * 晚安晚安
     * 2019-11-10T05:24:16.942Z
     * 早鸭
     */
}

We use the dynamic proxy agents need to achieve all of this behavior concentrated to invoke a method to execute, do not write a lot of code templates, and we actually can represent multiple interfaces in a InvocationHandler

Inadequate :

  • If the proxy InvocationHandler two interfaces, two interfaces has two methods completely identical, would not be able to distinguish between the
  • Agent must be based on the interface, the class does not implement the interface can not be proxied

Tripartite library Cglib

Cglib based ASM bytecode manipulation framework help us to generate the proxy subject in need, and is not required to implement the interface

Join dependence

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

    We do not need to implement a specific interface

public class Person {

    public String sleep() {
        return "晚安晚安";
    }

    public String wake() {
        return "早鸭";
    }
}
  • Proxy

    Our logic and comes with the JDK dynamic proxy is the same

public class CglibProxy implements MethodInterceptor {
    //需要代理的目标对象
    private Object target;

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

    /**
     *
     * @param o 监控对象:监控行为是否发生
     * @param method 被监控的行为方法
     * @param objects 被监控行为方法的参数
     * @param methodProxy 代理中生成的方法
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        Object result = null;

        String methodName = method.getName();
        if ("sleep".equals(methodName)) {
            result = getTime();
            result += (String) method.invoke(this.target, objects);
        } else if ("wake".equals(methodName)) {
            result = getTime();
            result += (String) method.invoke(this.target, objects);
        }
        return result;
    }

    // 辅助行为
    private String getTime() {
        return Clock.systemDefaultZone().instant().toString() + "\n";
    }
}
  • Factory, the factory can also do direct new clients
public class ProxyFactory {

    public static Object getCglibProxyInstance(Class clz) throws IllegalAccessException, InstantiationException {
        // Enhancer类是CGLib中的一个字节码增强器
        Enhancer enhancer=new Enhancer();
        // 设置被代理类的字节码文件,这里我们关注的不再是接口
        enhancer.setSuperclass(clz);
        // 创建被代理对象
        Object target = clz.newInstance();
        // 绑定到代理执行器中
        CglibProxy proxy = new CglibProxy(target);
        // 设置回调这个代理对象
        enhancer.setCallback(proxy);
        // 生成返回代理对象
        return enhancer.create();
    }
}
  • Client
public class Test {

    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        Person zhang = (Person) ProxyFactory.getCglibProxyInstance(Person.class);
        System.out.println(zhang.sleep());
        System.out.println(zhang.wake());
    }

    /**
     * 输出:
     * 2019-11-10T06:01:13.105Z
     * 晚安晚安
     * 2019-11-10T06:01:13.115Z
     * 早鸭
     */
}

No need to implement the interface can also be dynamic proxy you, really terrific

Inadequate :

  • Dependence tripartite library
  • For final classes and methods can not proxy because the proxy class all methods Cglib generated proxy class needs to be rewritten

Guess you like

Origin www.cnblogs.com/xyy2019/p/11830852.html