Before we learn about agency, we first understand the meaning of agency
- Definition: provide a proxy object to the target object, and the proxy object controls the reference of the target object
- Objective: to indirectly access the target object by introducing an agent to prevent the uncertain complexity of the system caused by direct access to the target object
Static agent and dynamic agent
According to the different time of loading the proxy class, the proxy is divided into static proxy and dynamic proxy.
- Static proxy: the class to be proxy is determined at compile time
- Dynamic proxy: the runtime determines which class to proxy
Static proxy usage
1. Methods to be implemented by static agent
public interface Subject { void sayGoodBye(); void sayHello(String str); boolean isProxy(); }
2. Define the proxy class (the original function class) and implement the function logic of the proxy class (the one that doesn't change)
public class RealSubject implements Subject { @Override public void sayGoodBye() { System.out.println("RealSubject I'm the original code sayGoodBye "); } @Override public void sayHello(String str) { System.out.println("RealSubject I'm the original code sayHello " + str); } @Override public boolean isProxy() { System.out.println("RealSubject I'm the original code isProxy "); return false; } }
3. Define a static proxy class (function addition class). This proxy class must also implement the same Subject interface as the proxy class to facilitate the enhancement of the original functions
public class ProxySubject implements Subject { private Subject subject; public ProxySubject(Subject subject) { this.subject = subject; } @Override public void sayGoodBye() { //Agent class, function enhancement, sayGoodBye can do operations before calling (such as whether the authority authentication can be called) System.out.println("ProxySubject sayGoodBye begin " + "Proxy class, function enhancement, before call sayGoodBye Do operations (such as whether you can call permission authentication)"); //The method that indirectly accesses the proxied object in the method of the proxy class subject.sayGoodBye(); System.out.println("ProxySubject sayGoodBye end " + "Here you can handle the logical processing after the original method call"); } @Override public void sayHello(String str) { //Proxy class, function enhancement, sayHello can do operations before calling (such as whether the permission authentication can be called) and test the methods with parameters System.out.println("ProxySubject sayHello begin " + "Proxy class, function enhancement, before call sayHello Do operations (such as whether you can call permission authentication)"); //The method that indirectly accesses the proxied object in the method of the proxy class subject.sayHello(str); System.out.println("ProxySubject sayHello end " + "Here you can handle the logical processing after the original method call"); } @Override public boolean isProxy() { //Proxy class, function enhancement isProxy can do operations before calling (such as whether the permission authentication can be called) and test the method with return System.out.println("ProxySubject isProxy begin " + "Proxy class, function enhancement, before call isProxy Do operations (such as whether you can call permission authentication)"); boolean boolReturn = subject.isProxy(); System.out.println("ProxySubject isProxy end " + "Here you can handle the logical processing after the original method call"); return boolReturn; } }
4. Static proxy usage
public class ProxyMain { public static void main(String[] args) { //In some cases, we do not want to modify the existing code for the proxy object. We use the proxy to access it indirectly RealSubject realSubject = new RealSubject(); //Proxy class object, transfer the object that the original code does not want to modify into the proxy class object ProxySubject proxySubject = new ProxySubject(realSubject); //Call the method of the proxy class object proxySubject.sayGoodBye(); System.out.println("******"); proxySubject.sayHello("Test"); System.out.println("******"); proxySubject.isProxy(); } }
5. Final printing
ProxySubject sayGoodBye begin Proxy class, function enhancement, before call sayGoodBye Do operations (such as whether you can call permission authentication) RealSubject I'm the original code sayGoodBye ProxySubject sayGoodBye end Here you can handle the logical processing after the original method call ****** ProxySubject sayHello begin Proxy class, function enhancement, before call sayHello Do operations (such as whether the authority authentication can be invoked) RealSubject I'm the original code sayHello Test ProxySubject sayHello end Here you can handle the logical processing after the original method call ****** ProxySubject isProxy begin Proxy class, function enhancement, before call isProxy Do operations (such as whether you can call permission authentication) RealSubject I'm the original code isProxy ProxySubject isProxy end Here you can handle the logical processing after the original method call
6. Summary:
The implementation of static proxy (traditional proxy model) is more violent and direct. It is necessary to write all the methods of all the proxy classes and manually forward them one by one, which is cumbersome and cumbersome. So we need to learn and use dynamic agents.
Core principles of dynamic agent
1. In the dynamic proxy mechanism of java, there are two important classes or interfaces
- One is the InvocationHandler(Interface), which needs to be implemented in the code
- One is Proxy(Class)
2. InvocationHandler (Interface) details
public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
- Proxy: refers to the generated proxy object;
- Method: refers to the method object of a method of the real object we want to call;
- args: refers to the parameters accepted when calling a method of a real object;
3. Core principle of Proxy (Class)
- When compiling, the class of the proxy object does not exist. When you need to call proxy When using the newproxyinstance method, a class bytecode of Proxy0 will be constructed and loaded into memory
4,Proxy. Detailed explanation of newproxyinstance method
@CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {....}
- loader: a ClassLoader object that defines which ClassLoader object loads the generated proxy object
- Interfaces: an array of Interface objects, which indicates what set of interfaces I will provide to the object I need to proxy. If I provide a set of interfaces to it, the proxy object claims to implement the Interface (polymorphic), so that I can call the methods in this set of interfaces
- An InvocationHandler object indicates which InvocationHandler object will be associated when I call the method as a dynamic proxy object.
Dynamic proxy usage
Step 1: define an interface (logic to be implemented)
public interface Subject { void sayGoodBye(); void sayHello(String str); boolean isProxy(); }
Step 2: define the real object (the proxy class, the one that doesn't change after being killed):
public class RealSubject implements Subject { @Override public void sayGoodBye() { System.out.println("RealSubject I'm the original code sayGoodBye "); } @Override public void sayHello(String str) { System.out.println("RealSubject I'm the original code sayHello " + str); } @Override public boolean isProxy() { System.out.println("RealSubject I'm the original code isProxy "); return false; } }
Step 3: define an InvocationHandler, which is equivalent to a proxy processor
public class SubjectInvocationHandler implements InvocationHandler { //This is the real object we want to represent private Object subject; //The construction method assigns the initial value to the real object we want to represent public SubjectInvocationHandler(Object subject) { this.subject = subject; } @Override public Object invoke(Object object, Method method, Object[] args) throws Throwable { //We can add our own operations before representing real objects System.out.println("before Method invoke Proxy class, function enhancement, before call "+method+" Do operations (such as whether you can call permission authentication)"); System.out.println("Method:" + method); //When the proxy object calls the method of the real object, it will automatically jump to the invoke method of the handler object associated with the proxy object to get the corresponding return value, and finally return the corresponding return value Object obj = method.invoke(subject, args); //After representing the real object, we can also add some of our own operations System.out.println("after Method invoke Here you can handle the logical processing after the original method call "); return obj; } }
Step 4: call
public class ProxyMain { public static void main(String[] args) { //Proxy class Subject realSubject = new RealSubject(); //We pass the object into the class we want to proxy, and finally call its method through the proxy object SubjectInvocationHandler handler = new SubjectInvocationHandler(realSubject); //Generate proxy class Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), handler); //Output proxy class object System.out.println("Proxy : " + subject.getClass().getName()); System.out.println("Proxy super : " + subject.getClass().getSuperclass().getName()); System.out.println("Proxy interfaces : " + subject.getClass().getInterfaces()[0].getName()); //Call the sayGoodBye method of the proxy class subject.sayGoodBye(); System.out.println("--------"); //Call the proxy class sayHello method subject.sayHello("Test"); System.out.println("--------"); System.out.println("---subject.isProxy()-----" + subject.isProxy()); } }
Final print:
Proxy : com.sun.proxy.$Proxy0 Proxy super : java.lang.reflect.Proxy Proxy interfaces : staticproxy.Subject before Method invoke Proxy class, function enhancement, before call public abstract void staticproxy.Subject.sayGoodBye() Do operations (such as whether you can call permission authentication) Method:public abstract void staticproxy.Subject.sayGoodBye() RealSubject I'm the original code sayGoodBye after Method invoke Here you can handle the logical processing after the original method call -------- before Method invoke Proxy class, function enhancement, before call public abstract void staticproxy.Subject.sayHello(java.lang.String) Do operations (such as whether you can call permission authentication) Method:public abstract void staticproxy.Subject.sayHello(java.lang.String) RealSubject I'm the original code sayHello Test after Method invoke Here you can handle the logical processing after the original method call -------- before Method invoke Proxy class, function enhancement, before call public abstract boolean staticproxy.Subject.isProxy() Do operations (such as whether you can call permission authentication) Method:public abstract boolean staticproxy.Subject.isProxy() RealSubject I'm the original code isProxy after Method invoke Here you can handle the logical processing after the original method call ---subject.isProxy()-----false ---subject.isProxy()-----false
Dynamic agent summary
- Dynamic proxy can increase the flexibility of the program, such as the logical processing before and after calling the method
- To solve the decoupling problem perfectly, dynamic agent can separate the calling layer from the implementation layer
- Dynamic proxies do not require interface implementation classes
- Dynamic agent can solve the process of program execution (the event in the next installment will be transferred to activity execution)