In learning the spring framework, there is an important idea of AOP, aspect-oriented programming, using the idea of AOP combined with some of the spring's API to achieve the separation of core business and ancillary services, that is, in the execution of the core business, some ancillary business can be added, and ancillary services (such as logs, Permissions control, etc.) is generally a public business, so that the separation of the two, so that the core business code is more pure, and ancillary services can be reused, this note was written at the time of learning Spring, using SPRINGAPI and custom classes to implement an example of AOP. The bottom of the AOP is through the dynamic agent to achieve, recently specialized learning proxy mode, reflection mechanism, (dynamic agent is also based on reflection mechanism to achieve) the understanding of the agent and three-dimensional a little bit, the following examples to explain the agent.
Why agents are required:
To play a simple analogy, I now want to learn, then you have to take the Schoolbag, the book out, ready for paper and pens, and then began to study, and so finished I have to tidy up the book, the book Back to the bag, but also to tidy up the schoolbag, this is a complete learning process, but I am lazy, do not want to move, That may have to let mother help me to take the schoolbag, open the book, I just study good, after learning, mother help me to put the book back. (I'm what a metaphor ...), here, the mother represents a proxy object , to learn the person is me, and I just study, so efficiency is the highest, as for the other to the surrogate object (mother) to do just fine, draw an ugly diagram to show:
Again, when we first approached the JDBC operations database, the business layer needed 1 for each approach. Open the database connection,2. Do what we want 3. Close the database connection. This makes the business layer code is not pure, my function is to query user data, Opening and closing a database connection what am I going to do about it? This is a problem in traditional development, and now it's time to demonstrate it by code:
/*** Simple business layer interface with only one save method*/Interfaceuserservice{ Public voidsaveuser ();}
/////////////////////////////////////////////////////////*** Business Layer implementation class, implementing the Save method*/classUserserviceimplImplementsuserservice{@Override Public voidSaveuser () {System.out.println ("1: Open database Connection"); System.out.println ("2: Save user Information"); System.out.println ("3: Close Database Connection"); } }
We can see that the implementation of this method is a problem, the core business and auxiliary services written in a method, not only the business redundancy does not say, like the switch database connection such as the public operation is also a large number of duplication, at this time there is the idea of proxy mode , We can use the idea of proxy mode to rewrite the above code:
PackageCom.wang.proxy;/*** Simple business layer interface with only one save method*/Interfaceuserservice{ Public voidsaveuser ();}/*** proxy class*/classUserserviceproxyImplementsuserservice{PrivateUserService UserService; Publicuserserviceproxy (UserService userservice) {Super(); This. UserService =UserService; } Public voidOpen () {System.out.println ("1: Open database Connection"); } Public voidClose () {System.out.println ("3: Close Database Connection"); } @Override Public voidSaveuser () { This. open (); Userservice.saveuser (); This. Close (); } }/*** Business Layer implementation class, implementing the Save method*/classUserserviceimplImplementsuserservice{@Override Public voidSaveuser () {System.out.println ("2: Save user Information"); } }/*** Test Class*/ Public classTestproxy { Public Static voidMain (string[] args) {UserService userservice=NewUserserviceproxy (NewUserserviceimpl ()); Userservice.saveuser (); }}
By testing the code to print the results, and the above is not using the proxy code is exactly the same, but through the changes can be clearly seen that the business layer code is pure and pure, leaving only the core of the code to save the user information. Through the proxy model, we can extract the core business and ancillary services, but the problem followed, I write here userserviceproxy is very good, but it can only serve with UserService this interface object Ah, if I have 1000 business, that would not be to write 1000 proxy class, after all 1000 people heart there are 1000 Hamlet Ah, In fact, this proxy mode is static proxy, its shortcomings are obvious, static agent can only serve a type of object, not conducive to business expansion , then we think, can design a proxy class can serve all business objects? So, at this time, the dynamic agent will debut.
If you want to implement a dynamic proxy, then the proxy class you want to write will need to implement a Invocationhandle interface. This interface is located at Java.lang.reflect.InvocationHandler. See reflect, we'll know. Dynamic proxies are definitely implemented by reflection, and there is a method in this interface:
Object Invoke (Object proxy, method, object[] args): Processes the method call on the proxy instance and returns the result.
The Invoke method is actually a method of reflection inside, with three parameters in this method:
ojbectProxy: Represents an object that requires a proxy
Method: Represents the way to operate
object[] args: The arguments that are required by method methods (may not be, null. There may be multiple)
If you want to make the proxy design really usable, we must also have a proxy class object to produce, which is useful to another class: Java.lang.reflect.Proxy. My Chinese JDK document describes him as:
Proxy
Provides a static method for creating dynamic proxy classes and instances, or a superclass of all dynamic proxy classes created by these methods.
Below this class, we find a way to:
newproxyinstance (ClassLoader loader, Class<?>[] interfaces, Invocationhandler h) throws IllegalArgumentException
The method returns a proxy class instance of the specified interface that can assign a method call to the specified invocation handler. There are three parameters in the method:
Parameters:
loader
-Class loader for defining proxy classes
interfaces
-List of interfaces to be implemented by the proxy class
h
-Assigning call handlers for method calls
Return:
A proxy instance of the specified invocation handler with the proxy class, defined by the specified class loader, and implements the specified interface
OK, with this knowledge, we can write a universal dynamic proxy class.
classServiceproxyImplementsInvocationhandler {PrivateObject target=NULL;//Save Real Business Objects /*** Returns the object of the dynamic proxy class so that the user can manipulate the real object using the proxy class object *@paramobj contains objects that have real business implementations *@returnreturns the proxy object*/ Publicobject GetProxy (Object obj) { This. target=obj;//Save Real Business Objects returnproxy.newproxyinstance (Obj.getclass (). getClassLoader (), obj. GetClass (). Getinterfaces (), This); } @Override Publicobject Invoke (Object proxy, Method method, object[] args)throwsthrowable {Object result=method.invoke (target, args);//invokes the business method of the real business object by reflection, and returns returnresult; }}
Now let's test it out so that:
/***/Publicclass testproxy {publicstatic void main (string[] args) { userservice servicenew serviceproxy (). GetProxy (new Userserviceimpl ()); Service.saveuser (); }} // Printing results: // 2. Save User Information
See!!!! Perfect, what do you say? Why didn't you open the database connection and shut down the database connection? Simple, we add two methods directly in the Serviceproxy, open () and close (), one put on the Method.invoke () above, one put below, you can, notice, we are now writing a universal dynamic proxy class, is not associated with any of the business layer interfaces, so you can do whatever you like next.
Here's a summary:
The biggest benefit of dynamic proxies compared to static proxies is that all the methods declared in the interface are transferred to a centralized approach, which is Invocke () method. This way, we can do this flexibly when the methods declared in the interface are much more, without the need to relay each method like a static proxy.
Dynamic agents can only proxy interfaces, and proxy classes need to implement the Invocationhandler class to implement the Invoke method. The Invoke method is called when calling all methods of the Proxied interface, and the return value of the Invoke method is an implementation class of the Proxy interface.
So is it possible that we can not rely on the interface? At this time need to implement dynamic agent Cglib, this jar can let us get rid of the trouble of the interface, interested in their own to check it, anyway, I also useless, not ...
Proxy design mode static agent and dynamic Agent (super.) Detailed