“This is the sixth day of my participation in the August More Text Challenge.


The proxy pattern

Proxy is a design pattern that provides indirect access to target objects. That is, the target object is accessed through a proxy object. The advantage of doing this is that you can add additional functionality to the functionality implemented by the target object, i.e. extend the functionality of the target object. In line with the open closed principle, that is, without changing the existing code, add code for function extension.

background

The relationship between singer and agent is the relationship between agent and agent. When a singer performs in an activity, the singer is a target, as long as he is responsible for the program in the activity, and other trivial matters are entrusted to his agent. This is the typical proxy pattern

Analysis of the

There are three types of proxy mode implementations:

  • Static agent
  • A dynamic proxy
  • Additional agent

Static agent

  1. Abstract Topic class
Public interface Subject {/** * public void request(); }Copy the code
  1. Specific subject class
Public class ConcreteSubject implements Subject {// @override public void request() {// ConcreteSubject implements Subject.Copy the code
  1. The proxy class
Public class Proxy implements Subject {/** * private Subject = null; /** * default Proxy */ public Proxy() {this.subject = new Proxy(); } public Proxy(Subject subject) { this.subject = subject; } public Proxy(param objects) {public Proxy(param objects) {public Proxy(param objects); @override public void request() {this.before(); this.subject.request(); this.after(); Private void after() {//do something}} private void after() {//do something}}Copy the code
  1. The client class
public class Client { public static void main(String[] args) { Subject subject = new ConcreteSubject(); Proxy proxy = new Proxy(subject); proxy.request(); }}Copy the code

A dynamic proxy

The meaning of static agent, through the above case can be found, he can only represent one object, can be understood as an agent can only represent one singer’s activities, so there will be many agents. So we managed to do all the proxy functionality with a single proxy class, so we needed dynamic proxies.

Dynamic proxy is implemented at run time through reflection mechanism, and can proxy various types of objects.

In Java to realize the dynamic Proxy mechanism, need Java. Lang. Reflect. InvocationHandler interface and Java. Lang. Reflect. The Proxy class support.

Java. Lang. Reflect the InvocationHandler interface definition

package java.lang.reflect;
public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}
Copy the code

Parameter Description:

  • Object Proxy Proxy Object
  • Method Method Specifies the Method to be invoked
  • Object[] Parameter required when the args method is called

Definition of the java.lang.reflect.Proxy class

public class Proxy implements java.io.Serializable { private static final long serialVersionUID = -2222568056686623797L;  /** parameter types of a proxy class constructor */ private static final Class<? >[] constructorParams = { InvocationHandler.class }; /** * a cache of proxy classes */ private static final WeakCache<ClassLoader, Class<? >[], Class<? >> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); /** * the invocation handler for this proxy instance. * @serial */ protected InvocationHandler h; /** * Prohibits instantiation. */ private Proxy() {} ········ ········  Object newProxyInstance(ClassLoader loader, Class<? >[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); final Class<? >[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm ! = null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * Look up or generate the designated proxy class. */ Class<? > cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { if (sm ! = null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } final Constructor<? > cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (! Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() {  cons.setAccessible(true); return null; }}); } return cons.newInstance(new Object[]{h}); } catch (IllegalAccessException|InstantiationException e) { throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); }}}Copy the code

Parameter Description:

  • ClassLoader Indicates the loader of the loader class
  • Class
    [] interfaces get all the interfaces
  • InvocationHandler h gets an instance of a subclass of the InvocationHandler interface

The main idea is to use reflection to build proxy classes

example

Here’s an example

  1. Target interface class
ISinger{void singing(); }Copy the code
  1. Target Singers
// implements ISinger{@override public void singing() {system.out.println (" implements "); // implements ISinger{@override public void singing() {system.out.println (" implements "); }}Copy the code
  1. The agent function
Class SingerUtils{public static void method1() {system.out.println (); } public static void method2() {system.out.println (); }}Copy the code
  1. Agent precompile processing
class SingerInvocationHandle implements InvocationHandler{ private Object target; public void setTarget(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { SingerUtils.method1(); method.invoke(target, args); SingerUtils.method2(); return null; }}Copy the code
  1. Create an agent
class SingerProxyFactory{ public static Object getProxy(Object target) { SingerInvocationHandle handle = new SingerInvocationHandle(); handle.setTarget(target); Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handle); return proxy; }}Copy the code
  1. test
Public class ProxyDemo {public static void main(String[] args) {// ISinger zxy = new zxy (); // However, there is a list of things to prepare for singing, such as finding venues, sound systems, selling tickets and so on, which requires agents to do. So they create a singer's agent to do these things ISinger proxy = (ISinger) SingerProxyFactory. GetProxy (zxy); // start the concert proxy.run(); }}Copy the code

Additional agent

A similarity in the code above is that require the target object is to implement an interface object, but not any object can implement an interface, there are also don’t implement any interface object, then you can use the inherited the target class in the form of target subclass implementation agent, this method is called: additional agent, also called subclass agent.

Cglib relies on third-party JAR implementations

Implementation only enumerates key code

// instantiate a class generator Enhancer Enhancer = new Enhancer(); // Set the target class to henhancer.setsuperclass (xxx.class); // Set intercepting object, SetCallback (new MethodInterceptor() {@override public Object Intercept (Object Object); Method method, Object[] args, MethodProxy proxy throws Throwable {// Use the proxy invokeSuper method to call the target class method proxy.invokesuper (object, args); // todo returns null; }}); // then create the proxy object XXX XXX = (XXX) enhancer.create(); xxx.run();Copy the code