1, What is agent mode
The proxy mode provides a proxy for other objects to control access to this object. In some cases, one object is not suitable or can not directly refer to another object, while the proxy object can mediate between the client and the target object, which is characterized by the same interface between the proxy class and the delegate class. Agent pattern is a common java design pattern.
The agent mode can enhance the method without modifying the source code, and add logging, permission management and other functions before and after the method.
The form of expression is shown in the figure:
img
In Java, there are two kinds of proxy patterns: static proxy pattern and dynamic proxy pattern;
-
Static agent mode is also very common in daily life, such as the small matter of buying train tickets. Scalpers are the same as railway station agents. We can buy tickets through scalpers or agency points, but we can only go to the railway station to change and refund tickets, because only the railway station can change and refund tickets.
-
In the dynamic agent, the agent class is not implemented in Java code, but generated in runtime. Compared with the static agent, the dynamic agent can easily handle the methods of the agent class in a unified way, such as adding method calls, adding log functions, etc. the dynamic agent is divided into jdk dynamic agent and cglib dynamic agent. Here is an example to see how to implement jdk dynamic agent Agent.
2, Advantages and disadvantages of agent mode
-
advantage:
-
Clear responsibilities.
-
High scalability.
-
Intelligent.
-
-
Disadvantages:
-
Due to the addition of proxy objects between the client and the real topic, some types of proxy patterns may slow down the processing of requests.
-
The implementation of agent pattern needs extra work, and some of them are very complex.
-
-
Comparison of other modes
-
Difference from adapter mode: adapter mode mainly changes the interface of the object under consideration, while proxy mode cannot change the interface of the class under proxy.
-
Difference from decorator mode: decorator mode is for enhancing functions, while agent mode is for controlling.
-
3, Use scenario
The agent mode mainly solves the problems brought by direct access to objects, such as: the object to be accessed is on a remote machine. In the object-oriented system, for some reasons (such as high cost of object creation, security control of some operations, or access outside the process), direct access will bring a lot of troubles to the user or system structure. We can add an access layer to this object when we access this object.
1. Application scenario
Divided by responsibilities, there are usually the following usage scenarios:
-
Remote agent.
-
Virtual agent.
-
Copy on write agent.
-
Protect or Access agent.
-
Cache agent.
-
Firewall agent.
-
Synchronization agent.
-
Smart Reference agent.
2. Application examples
-
Windows desktop and shortcuts in Explorer.
-
Buying train tickets doesn't have to be at the railway station, they can also be bought at the agency or online.
-
Dynamic proxy used in Spring AOP.
4, Code implementation
1. Static agent mode
The static agent satisfies the following conditions:
-
The classes of proxy objects are real and not dynamically generated.
-
The proxy object holds a reference to the proxied object.
-
The method in the proxy object calls the method of the proxy object through the reference of the proxy object, and executes the proxy logic at the same time.
Here is a simple proxy model:
Interface class:
/* * Interface * Both proxy and delegate classes must implement this class */public interface ISubject { //Abstract methods of processing taskspublic void dealTask(String task);}
Delegation class:
/* * Real role (agent class, delegate class) * Implement interface issubject */public class RealSubject implements ISubject {@Overridepublic void dealTask(String task) {//Real role processing tasksSystem.out.println("In progress"+task);} }
Proxy class:
/* * proxy class * Implement the issubject interface * Hold references to proxied classes */public class Proxy implements ISubject { //Hold references to proxied classesprivate RealSubject realSubject; //Initializing the proxied class in the constructorpublic Proxy(RealSubject r) {this.realSubject=r;} @Override//Add proxy logic to the methodpublic void dealTask(String task) {System.out.println("Start helping....");//Join thread sleep to simulate helping behaviortry {Thread.sleep(2000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}//It's still the real character who does the actionrealSubject.dealTask(task);} }
Static factory class:
/* * Static factory class * For the client, it doesn't care whether the agent object or the real role performs the action * So we create a static method to return the object directly */public class StaticFactory { //Call this method to get an instancepublic static ISubject getInstance(){return new Proxy(new RealSubject());}}
Test class:
/* * Test class (customer class) */public class Test { public static void main(String[] args) {//An instance of a real object is required to create a proxy objectISubject instance = StaticFactory.getInstance();//Methods using proxy classesinstance.dealTask("Knock code");}}
The real business functions are implemented by delegation classes, but some public services before the implementation of business classes. For example, in project development, we didn't add buffer and log functions. If we want to add them later, we can use agent to implement them, without opening the encapsulated delegate class.
2. Dynamic agent mode
1. Define business logic
public interface Service { //Target method public abstract void add(); } public class UserServiceImpl implements Service { public void add() { System.out.println("This is add service"); } }
2. Utilization java.lang.reflect.Proxy class and java.lang.reflect The. Invocationhandler interface defines the implementation of the proxy class.
class MyInvocatioHandler implements InvocationHandler { private Object target; public MyInvocatioHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("-----before-----"); Object result = method.invoke(target, args); System.out.println("-----end-----"); return result; } // Build proxy object public Object getProxy() { ClassLoader loader = Thread.currentThread().getContextClassLoader(); Class<?>[] interfaces = target.getClass().getInterfaces(); return Proxy.newProxyInstance(loader, interfaces, this); } }
3. Use dynamic proxy
public class ProxyTest { public static void main(String[] args) { Service service = new UserServiceImpl(); MyInvocatioHandler handler = new MyInvocatioHandler(service); Service serviceProxy = (Service)handler.getProxy(); serviceProxy.add(); } }
Execution result:
-----before----- This is add service -----end-----