Agent Mode in software design mode; Agent Mode in Design Mode
It seems that I have stopped the service for nearly half a month. It's really not the case. In the new year, I should keep myself at zero.
Back To Zero. Let's start from this article.
This article will introduce the basic concepts of proxy mode and the advantages and disadvantages of static proxy and dynamic proxy and how to use it (including the extension package CGLIB)
The proxy mode, also known as the delegation mode, is the name suggests entrusting something to do something.
For example, in my life, my friends who have been studying and working in other places have also begun to buy train tickets for returning home, friends who are close to the railway station can easily purchase tickets directly at the station. What should they do if they live in the suburbs and stay away from the railway station? Of course, you can also take a ride to the train station to buy a ticket, but it is really troublesome. At this time, something is derived-the train ticket sales agency. Yes, with it, our friends who are away from the railway station can easily purchase train tickets.
Here, the train ticket sales representative is actually an agent (delegated). The train ticket sales representative acts as an agent for ticket sales at the railway station. However, we can do what we want, such as permission control, the sales agency does not have the permission to refund the ticket.
Let's get down to the truth. Let's take a look at the agent concept.
1. Agent Concept
Provides a proxy for an object to control access to this object. The proxy class and the proxy class have a common parent class or parent interface, so that the proxy object can be used in any place where the proxy class object is used. The proxy class is responsible for Request preprocessing, filtering, distributing requests to the proxy class for processing, and subsequent processing after the proxy class executes the request.
To a UML diagram:
It can be seen that the proxy interface (Subject), ProxySubject, and RealSubject form a "product" structure.
Both the proxy class and the proxy class implement the proxy interface at the same time, and then the proxy class processes user access requests by referencing the objects of the proxy class.
Here, two types of proxies are divided based on the generation time of the proxy class, one is static proxy and the other is dynamic proxy.
The theoretical concept of the article is hard to understand. The following is an example to help you understand it.
2. Static proxy
The source code of the proxy class is generated by a developer or a tool, and then the proxy class is compiled. Static means that the bytecode file of the proxy class already exists before the program runs, which is determined before the proxy class and the agent class runs.
Here, we simulate a timer operation to record the time for processing the business. The following code is directly used:
The first is the proxy interface, which declares the business method. Both the proxy class and the proxy class must implement it.
1 package com. lcw. proxy. test; 2 3/** 4*5 * business interface (proxy interface) 6*7 */8 public interface ITask {9 10 public void doTask (String taskName); 11 12}
The next step is the proxy class, which implements the proxy interface and executes the main business logic operations.
1 package com. lcw. proxy. test; 2 3 import java. util. random; 4 5/** 6*7 * business processing class, processing main businesses (by proxy class) 8*9 */10 public class DealTask implements ITask {11 12 @ Override13 public void doTask (String taskName) {14 try {15 System. out. println ("execution task:" + taskName); 16 Thread. sleep (new Random (). nextInt (1000); // random sleep for a period of time 17} catch (InterruptedException e) {18 e. printStackTrace (); 19} 20} 21 22}
Then, the proxy class implements the proxy interface. In this way, the proxy class and the objects under the proxy class are both "assimilated", and the constructor can reference the objects under the proxy class, this allows you to access the main business methods of the proxy class.
1 package com. lcw. proxy. test; 2 3 4/** 5*6 * proxy class, the same interface as the proxy class needs to be implemented. 7 * use the constructor method to reference an object of the proxy class to own 8*9 */10 public class ProxyTask implements ITask {11 12 private ITask dealTask; 13 14 public ProxyTask (ITask dealTask) {15 this. dealTask = dealTask; // reference a proxy class Object 16} 17 18 @ Override19 public void doTask (String taskName) {20 21 long startTime = System. currentTimeMillis (); // record the business start time 22 dealTask. doTask (taskName); // executes the main business of the proxy class 23 long endTime = System. currentTimeMillis (); // record the business end time 24 System. out. println ("the task execution time is:" + (endTime-startTime + "millisecond"); 25 26} 27 28}
Then a test class is provided.
1 package com. lcw. proxy. test; 2 3 4 public class ProxyTest {5 6/** 7 * test class 8 */9 public static void main (String [] args) {10 // static proxy 11 ITask dealTask = new DealTask (); // obtain the object of the proxy class 12 ITask proxyTask = new ProxyTask (dealTask ); // inject the object of the proxy class to obtain the static proxy class object 13 proxyTask. doTask ("sneezing .. "); 14 15} 16}
Check the running effect:
Here, the static proxy has been implemented. First, let's take a look at the advantages of the static proxy. The proxy class only needs to focus on the main business implementation, and other operations such as logging, timing, permission control and so on can be handed over to the proxy class for additional processing.
However, is there no problem with this implementation method?
If we want to implement the timing function for many business methods, and if these methods are distributed in different classes, do we need to create a proxy class for each class separately for a long time, the class size will expand, and it will explode.
Let's take a look back. If we want to expand our business and add a new business method to the proxy interface, in addition to implementing this method by the proxy class, is it true that all proxy classes need to be added to implement this method? the so-called "Pull-and-pull" requires a large amount of repeated code, which violates the software design principles.
In addition, the proxy object serves only one type of object. If you want to serve multiple types of objects. The agent is required for each type of object, and the static agent cannot be used when the program is a little large.
To solve this problem, our dynamic proxy is coming soon.
3. JDK dynamic proxy
The source code of the JDK dynamic proxy class is dynamically generated by the Virtual Machine JVM according to reflection and other mechanisms during the program running, so there is no bytecode file of the proxy class. It is determined when the proxy class and the program is running by the proxy class.
To implement the dynamic Proxy mechanism in Java, java. lang. reflect. InvocationHandler interface and java. lang. reflect. Proxy class are required.
Let's take a look at the main methods in Java APIs (read through them by yourself)
Java. lang. reflect. Proxy
Java. lang. reflect. InvocationHandler
This is to call the processor interface. It customizes an invoke Method for centralized processing of method calls on a dynamic proxy object. Generally, this method implements access to the proxy of the proxy class.
Dynamic proxy implementation steps
1. Implement the InvocationHandler interface to create your own call Processor
2. Provide ClassLoader and Proxy Interface Types for Proxy classes to create dynamic Proxy classes
3. Use the reflection mechanism to obtain the constructor of the dynamic proxy class based on the called Processor type.
4. Use the constructor of the dynamic proxy class to create a dynamic proxy class object with the called processor object as the parameter
Now, some friends are starting to get confused. Let's look at the instance and sort out their ideas.
It is still the proxy interface above. here we need to create our own calling processor (implementing the InvocationHandler Interface)
1 package com. lcw. proxy. test; 2 3 import java. lang. reflect. invocationHandler; 4 import java. lang. reflect. method; 5 6/** 7*8 * the dynamic proxy class uses the InvocationHandler interface to create its own calling processor 9*10 */11 public class JDKProxy implements InvocationHandler {12 13 private Object dealTask; 14 15 public JDKProxy (Object dealTask) {16 this. dealTask = dealTask; // reference the object of the proxy class 17} 18 19/** 20 * parameter: proxy is the Object of the proxy class. method is the Method of the proxy class. args is the parameter array of this method. 21*22 */23 @ Override24 public Object invoke (Object proxy, method Method, object [] args) 25 throws Throwable {26 // call to implement the business logic method and implement the ancillary functions (logs, permission judgment, etc) 27 // use the reflection mechanism to distribute requests to the proxy class for processing 28 29 long startTime = System. currentTimeMillis (); // record business start time 30 // The invoke method parameter sub is the actual proxy object, and args is the 31 method required to execute the corresponding operation on the proxy object. invoke (dealTask, args); // the return value is an Object and the return value of the method called by the proxy (here only implement the timing operation, so the return value is null) 32 long endTime = System. currentTimeMillis (); // record service end time 33 System. out. println ("the task execution time is:" + (endTime-startTime + "millisecond"); 34 return null; 35} 36 37}
Next is the test class.
1 package com. lcw. proxy. test; 2 3 import java. lang. reflect. proxy; 4 5 public class ProxyTest {6 7/** 8 * test class 9 */10 public static void main (String [] args) {11 /// static proxy 12 // ITask dealTask = new DealTask (); // get the object of the proxy class 13 // ITask proxyTask = new ProxyTask (dealTask ); // obtain the static proxy class Object 14 // proxyTask. doTask ("sneezing .. "); 15 16 // dynamic proxy 17 ITask dealTask = new DealTask (); // get the object of the proxy class 18 JDKProxy jdkProxy = new JDKProxy (dealTask ); // get the dynamic Proxy class Object 19/** 20 * loader Class loader interfaces implementation interface h InvocationHandler21 */22 ITask iTask = (ITask) Proxy. newProxyInstance (dealTask. getClass () 23. getClassLoader (), dealTask. getClass (). getInterfaces (), 24 jdkProxy); 25 iTask. doTask ("in a daze... "); 26} 27 28}
See the implementation result:
Advantages and disadvantages of dynamic Proxy:
The biggest advantage of dynamic proxy compared with static proxy is that all methods declared in the interface are transferred to the InvocationHandler. invoke method that calls the processor ). In this way, when there are a large number of interface methods, we can flexibly process them without the need to transfer each method like a static proxy. In this example, the invoke method is embedded with a specific peripheral business (recording the time before and after processing the task and calculating the time difference). In reality, you can configure the peripheral business like Spring AOP. The application of dynamic proxy makes our class responsibilities more uniform and more reusable.
Weaknesses in the US:
Proxy has been designed very beautifully, but there is still a little regret, that is, it is always unable to get rid of the shackles that only support interface Proxy, because its design is doomed to this regret. JDK dynamic proxy can only be used as a proxy for classes that implement interfaces. classes that do not implement interfaces cannot be used as proxies.
If you have any problems, you will want to solve them. Therefore, Cglib is coming soon.
4. Cglib dynamic Proxy:
Cglib introduction:
The proxy provides a way to control the target object to be accessed. When accessing an object, it introduces an indirect layer. JDK has introduced dynamic proxies since version 1.3 and is often used to dynamically create proxies. JDK dynamic proxy is very simple to use, but it has a limitation that the object using dynamic proxy must implement one or more interfaces. What should I do if I want to proxy classes that do not implement interface inheritance? Now we can use the Cglib package.
Cglib implements proxy for classes. The implementation principle is to generate a subclass for the proxy class and intercept the calling of the parent class method by Intercept Technology.
Let's look at a small example:
First, a business logic class
1 package com. lcw. proxy. test; 2 3 import java. util. random; 4 5 public class Task {6 7 public void doTask () {8 System. out. println ("I'm finished"); 9 try {10 Thread. sleep (new Random (). nextInt (1000); 11} catch (InterruptedException e) {12 e. printStackTrace (); 13} 14} 15 16}
Another Cglib proxy class provides proxy objects. The MethodInterceptor interface must be implemented here.
1 package com. lcw. proxy. test; 2 3 import java. lang. reflect. method; 4 5 import net. sf. cglib. proxy. enhancer; 6 import net. sf. cglib. proxy. methodInterceptor; 7 import net. sf. cglib. proxy. methodProxy; 8 9/** 10*11 * Create the Cglib proxy class (you need to implement the MethodInterceptor Interface) 12*13 */14 public class CglibProxy implements MethodInterceptor {15 16 // a proxy class Object 17 private Enhancer enhancer = new Enhancer () needs to be returned to the client (); 18 19 public Object getProxy (Class c) {20 // The principle of cglib proxy is to create a subclass 21 enhancer for the proxy Class (parent Class. setSuperclass (c); 22 enhancer. setCallback (this); 23 return enhancer. create (); 24} 25 26/** 27 * parameters: 28 * obj proxy class Object 29 * method proxy class method 30 * args parameters 31 * proxy class Object 32 */33 @ Override34 public Object intercept (Object obj, method method, Object [] args, 35 MethodProxy proxy) throws Throwable {36 long startTime = System. currentTimeMillis (); // record the Business Start Time 37 proxy. invokeSuper (obj, args); // The principle of cglib proxy is to create a subclass for the proxy class (parent class), so the parent class super is called here. Parameter 1: parent Class Object and parameter 2: method parameter 38 long endTime = System. currentTimeMillis (); // record the business end time 39 System. out. println ("the task execution time is:" + (endTime-startTime + "millisecond"); 40 return null; 41} 42 43}
Try writing a test class
1 package com. lcw. proxy. test; 2 3 import java. lang. reflect. proxy; 4 5 public class ProxyTest {6 7/** 8 * test class 9 */10 public static void main (String [] args) {11 /// static proxy 12 // ITask dealTask = new DealTask (); // get the object of the proxy class 13 // ITask proxyTask = new ProxyTask (dealTask ); // obtain the static proxy class Object 14 // proxyTask. doTask ("sneezing .. "); 15 16 // dynamic proxy 17 // ITask dealTask = new DealTask (); // get the proxy class Object 18 // JDKProxy jdkProxy = new JDKProxy (dealTask ); // get the dynamic Proxy class Object 19 /// ** 20 // * loader interfaces implementation interface h InvocationHandler21 // */22 // ITask iTask = (ITask) Proxy. newProxyInstance (dealTask. getClass () 23 //. getClassLoader (), dealTask. getClass (). getInterfaces (), 24 // jdkProxy); 25 // iTask. doTask ("in a daze... "); 26 27 // Cglib proxy 28 CglibProxy cglibProxy = new CglibProxy (); 29 Task task Task = (Task) cglibProxy. getProxy (Task. class); 30 task. doTask (); 31 32} 33 34}
Running effect:
Author: Balla _ rabbit
Source: http://www.cnblogs.com/lichenwei/
The copyright of this article is shared by the author and the blog. You are welcome to repost this article, but you must keep this statement without the author's consent and provide the original article link clearly on the article page.
I am reading this kid's shoes from my blog. I think you are so angry that you have a secret of the king in your conversation. You will do something in the future! With the word "recommendation" next to it, you can just click it. it's accurate. I don't accept anything. If you're not sure, you can come back to me!