Proxy mode, dynamic proxy, and orientation

Source: Internet
Author: User
The meaning of proxy mode, dynamic proxy, and Aspect-Oriented proxy is well understood. It refers to the meaning of the proxy we use on a daily basis: something that should have been done by ourselves, for some reason, you cannot do it directly, but you can only ask someone to do it for you. The person you invite is the proxy. For example, if you want to go home after the Spring Festival, because you have to go to work and have no time to buy a ticket, you have to purchase the ticket agent for you. This is an agent mode. This scenario can be vividly described as follows: Class: Train Station {ticket selling :{......}} The railway station is the place where tickets are sold. We assume that tickets can only be bought at the railway station. Tickets are actually sold at railway stations. Class: Ticket intermediary {ticket selling: {receiving intermediary fee; railway station. Selling ticket;} when a customer asks a ticket intermediary to buy a ticket, Call Ticket intermediary. Selling a ticket. Ticket agencies actually do two things. One is to buy a ticket at the railway station, and the other is not to sell the ticket for you. You must collect the agency fee. The advantage you get is that you don't have to go directly to the train station to buy tickets, saving the time for buying tickets to go to work. We have simply simulated the proxy mode scenario and why we need to use the proxy mode. Next we will take an example to analyze the proxy mode in Java. Assume that there is an information management system where some users have the permission to browse information, some users have the permission to browse, add, and modify information, and some users have the permission in addition to the preceding permissions, there is also the permission to delete information, so we are most likely to think of the following: public class viewaction {// permission calculated by userid ...... String permission = ......; If (permission. Equals (constants. View) {system. Out. println ("You could view the information ......"); ......}} Other actions are similar to those of browsing information. Let's look at this class and we can easily see some of its shortcomings: First, it puts both permission calculation and action execution in one class, and the functions of the two are mixed together, it can easily lead to confusion of ideas, and it is difficult to modify, maintain, and test. In a word, it does not meet the single responsibility principle. Second, the customer depends on the specific class when calling, which makes it difficult to expand and call during the runtime, and does not meet the principle of dependency inversion. Since there are so many problems, we need to redesign the class. As a matter of fact, we have long thought that this class should use the proxy mode. Yes, like buying a train ticket, the ticket class cannot perform the action directly. Instead, it must first check the permissions before executing the action. First, check the permissions, the classes executed later are actually a proxy class. The modified code is as follows: public interface action {public void doaction () ;}first, an interface is designed to meet the principle of dependency inversion. Public class viewaction implements action {public void doaction () {// system. Out. println ("You could view the information ......"); ......}} Like railway stations, this class is the real performer of actions. Public class proxyviewaction implements action {private action Action = new viewaction (); Public void doaction () {// call the permission class method to obtain the user permission if (permission. getpermission (userid ). equals (constants. view) {action. doaction () ;}} is a proxy class, which is easy to understand. In our proxyviewaction class, in addition to the action that the customer really wants to do: doaction (), it also performs additional actions to check the user's permissions. Doaction is implemented in a clean class: viewaction. This class only performs core actions and does not care about others. It meets the single responsibility principle. The client calls the proxy class to execute the action. The proxy class separates the permission judgment from the action execution to satisfy the single responsibility principle. The second is to implement an interface, this satisfies the principle of dependency inversion. It is much better than the first idea. The proxy is also called delegation. It means that the proxy class does not really execute that core action, but delegates it to another class for execution, for example, in the proxyview class, the proxyview class does not actually execute the doaction () method, but is handed to the viewaction class for execution. Let's take a look at the proxy class proxyviewaction. We can see that it depends not only on the interface action, but also on the specific implementation of viewaction. This is very unfavorable for our system expansion. For example, we have ADD actions, delete actions, and modify actions. We need to write a proxy class for each action, these proxies do the same thing. They first perform permission judgment and then delegate permissions. Therefore, we need to abstract these proxies again so that they only depend on the interface action, rather than the specific implementation. To realize this idea, we need to extract the specific implementation in the proxy class so that the proxy user can provide the specific implementation class at runtime, that is, the so-called dependency injection, as follows: public class proxyaction implements action {private action; Public proxyaction (action Action) {This. action = action;} public void doaction () {// call the permission class method to obtain the user permission if (permission. getpermission (userid ). equals (action. getclass (). getname () {action. in this way, we use a proxy class to proxy all the implementations that implement the Action interface. In addition to the viewaction class, the addaction, modifyaction, and deleteaction classes extended in the future can all use a proxy class: proxyaction. Our client is similar to the following: Action action = proxyaction (New viewaction); Action. doaction (); Through dependency injection on the proxy class, we initially made the proxy class extensible. However, we also need to see that this proxy class depends on a specific interface. This still cannot meet our actual requirements. For example, the permission control of our system is generally the entire system level, it is difficult for us to abstract a unified interface in the entire system. There may be multiple interfaces. According to the proxy mode above, we need to write a proxy class for each interface. Similarly, the functions of these classes are the same. This is obviously not a good solution. Based on the above reasons, we need to solve the problem that a system uses the proxy mode for some actions of some scattered objects without a unified interface. Java API introduces dynamic proxy or dynamic delegation technology. The core of dynamic proxy is the invocationhandler interface, which must be implemented to use dynamic proxy. The delegate task of this interface is implemented in the invoke (Object proxy, method M, object [] ARGs) method: // before calling the core functions ...... // Call the core function M. Invoke (OBJ, argS); // do some operations after calling the core function ...... We can see that the dynamic proxy actually uses the reflection mechanism to call core functions: M. invoke (OBJ, argS); this reflection mechanism makes calling core functions more flexible, instead of relying on a specific interface, but object objects. Next let's take a look at how to use dynamic proxy or dynamic delegation: public class proxyaction implements invocationhandler {private object action; Public proxyaction (Object action) {This. action = action;} public static object getinstance (Object action) {return proxy. newproxyinstance (action. getclass (). getclassloader (), action. getclass (). getinterfaces (), new proxyaction (Action);} public object invoke (Object proxy, method M, object [] ARGs) throws t Hrowable {object result; try {// action before delegation, such as permission judgment system. out. println ("before method" + M. getname (); // delegate result = m. invoke (action, argS);} catch (invocationtargetexception e) {Throw E. gettargetexception ();} catch (exception e) {Throw new runtimeexception ("unexpected invocation exception:" + E. getmessage ();} finally {// perform the system action after delegates. out. println ("after method" + M. getname ();} return Result ;}} the proxy class first implements the invocationhandler interface, and then obtains the proxy class instance in the getinstance () method. It is also very easy to implement the proxy function in the invoke () method. Next let's look at the client: Action action = (Action) proxyaction. getinstance (New viewaction (); action. doaction (); we can see that the proxy class's dependency on the interface is also transferred to the client, so that the proxy class does not depend on an interface. For the same proxy class proxyaction, we can also have the following client calls: engine = (ENGINE) proxyaction. getinstance (New engineimpl());engine.exe cute (); as long as the engineimpl class implements the engine interface, it can be used as above. Now we can see that dynamic proxy is indeed quite flexible. However, we can also see that this proxy class is difficult to write, and it also writes such a same thing almost every time, only the actions before and after the assignment are different in different proxies, and other actions need to be written as needed. If such a proxy class is too frequently written, there will also be some redundant proxies. We need further optimization. Here we use the template method mode to optimize this proxy class, as follows: public abstract class baseproxy implements invocationhandler {private object OBJ; protected baseproxy (Object OBJ) {This. OBJ = OBJ;} public static object getinstance (Object OBJ, invocationhandler instance) {return proxy. newproxyinstance (obj. getclass (). getclassloader (), obj. getclass (). getinterfaces (), instance);} public object invoke (Object proxy, method M, object [] ar GS) throws throwable {// todo auto-generated method stub object result; try {system. out. println ("before method" + M. getname (); this. dobegin (); Result = m. invoke (OBJ, argS);} catch (invocationtargetexception e) {Throw E. gettargetexception ();} catch (exception e) {Throw new runtimeexception ("unexpected invocation exception:" + E. getmessage ();} finally {system. out. println ("after method" + M. getname (); this. doafter ();} return result;} public abstract void dobegin (); public abstract void doafter, the proxy implementation class only needs to focus on the pre-delegate actions and post-delegate actions, as follows: public class proxyimpl extends baseproxy {protected proxyimpl (Object O) {super (o);} public static object getinstance (Object Foo) {return getinstance (Foo, new proxyimpl (FOO);} // public void dobegin () {// todo auto-generated method stub system. ou T. println ("begin doing .... haha ");} // The assigned action public void doafter () {// todo auto-generated method stub system. out. println ("after doing ..... yeah ") ;}} from the code above, we can see that the proxy implementation class is indeed much simpler. It only focuses on the actions before and after delegation, this is what we really need to care about as a proxy. So far, the proxy mode and dynamic proxy have come to an end. We will extend the dynamic proxy to the point where it can be used as a snake in this article. This topic is Aspect-Oriented Programming, or AOP. Let's look at the above proxyimpl class, which has two methods: dobegin () and doafter (), which are the two CIDR blocks before and after the core action. These two interceptions are the basis of AOP. In Oop, The dobegin (), Core Action, and doafter () actions are always combined in multiple classes, but their logic is different, for example, dobegin () may perform permissions, and all classes have permissions. The core actions in each class are different. doafter () what may be done is log, which is used for logs in all classes. It is precisely because dobegin () or doafter () in all classes do the same logic, so we need to extract them for separate analysis, design, and encoding, this is our idea of AOP. In this way, our dynamic proxy can be used as the basis for Implementing AOP. Well, let's talk about this much. We can focus on this aspect of AOP technology.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.