Document directory
- 6.2.1. Use AOP for loose coupling
- 6.2.2. Use AOP to combine two business logic
- 6.3.1 AspectObject abstract class
- 6.3.2 IAspect Interface
- 6.3.3 AspectManagedAttribute
- 6.3.4 define AspectProxy class
- 6.3.5 other auxiliary classes
- 6.3.6 configuration file
Chapter 2 Aspect-Oriented Programming 6th AOP Concept
AOP is short for Aspect Oriented Programming. It is usually translated into Aspect-Oriented Programming and its core content is the so-called "cross-cutting concern ". [17]
We know that using the object-oriented method to build a software system, we can use the features of OO to solve vertical problems, because the core concepts of OO, such as inheritance, they are all vertically structured. However, in a software system, there are often many modules, or many classes share a behavior, or a behavior exists in each part of the software, this behavior can be seen as "horizontal" in the software, and he is concerned with some common behavior of each part of the software, and in many cases, this behavior is not part of the business logic. For example, the operation log record, this operation is not a part of the business logic call, but we often do not have to explicitly call in the code, and bear the resulting consequences (for example, when the log recorded interface changes, you have to modify the calling code ). This problem is difficult to solve using the traditional OO method. The goal of AOP is to separate these "cross-cutting concerns" from the business logic code to achieve better software architecture, performance, stability, and other advantages.
Fig 6.1
AOP includes the following concepts [18]:
? Aspect: modularization of a focus, which may cause cross-cutting of multiple objects. Transaction Management is a good example of horizontal attention in J2EE applications.
? Joinpoint connection point: a specific point in the program execution process, such as a method call or a specific exception thrown.
? Advice notification: The action performed by the AOP framework at a specific connection point. Various types of notifications include "around", "before", and "throws. The notification type is discussed below. Many AOP frameworks use the interceptor as the notification model to maintain an interceptor chain around the connection points.
? Pointcut entry: Specifies a set of connection points that a notification will be triggered. The AOP framework must allow developers to specify the entry point, for example, using a regular expression.
? Introduction: add methods or fields to the notification class.
? IsModified interface to simplify cache.
? Target object: The object that contains the connection point. It is also used to reference notification or proxy objects.
? AOP proxy: the object created by the AOP framework, including notifications.
? Weaving: Creates notification objects for assembly. This can be completed during compilation (for example, using the AspectJ compiler) or at runtime. Spring and some other pure Java AOP frameworks are woven at runtime.
Various notification types include:
? Und und notification: notifications that enclose a connection point, such as method calls. This is the most powerful notification. The Aroud notification completes the custom action before and after the method call. They are responsible for choosing to continue executing the connection point or directly returning their own return values or throwing an exception to short-circuit execution.
? Before notification: a notification that is executed Before a connection point, but this notification cannot prevent the process from continuing to the connection point (unless it throws an exception ).
? Throws notification: the notification that is executed when the method Throws an exception.
? After returning notification: the notification executed After the connection point is normal. For example, if a method returns normally, no exception is thrown.
Around und notification is the most common notification type. Most Interceptor-based AOP frameworks such as Nanning and JBoss4 only provide Around-und notifications.
AOP brings a new perspective and software architecture method to our software design. With AOP, we can focus on the compilation of business logic code, and transfer system functions such as logging and security detection to the AOP framework, which is automatically coupled at runtime.
Generally, we can use the AOP technology in the following scenarios:
? Authentication permission
? Caching Cache
? Context passing content transmission
? Error handling
? Lazy loading
? Debugging
? Logging, tracing, profiling and monitoring record tracking optimization Calibration
? Performance optimization
? Persistence
? Resource pooling Resource pool
? Synchronization
? Transactions transaction
Websharp implements a. Net-based lightweight AOP framework.
6.2 use of Websharp AOP 6.2.1. Use of AOP for loose coupling
Next, we will use an example to discuss the application of AOP technology. To better illustrate this problem, we will provide some code. Therefore, we need to select a specific AOP framework. Here, we still use the Websharp framework for illustration. In the Websharo framework, we also implemented an Aspect framework.
Consider the following situation: Permission control is a common example for application software systems. To get a good program structure, we usually use the OO method to encapsulate the permission verification process in a class. This class contains a code for permission verification, for example:
Public class Security { Public bool CheckRight (User currentUser, Model accessModel, OperationType operation) { ...... // Verify the permission } } |
Then, perform the following calls in the business logic process:
Public class BusinessClass { Public void BusinessMethod () { Security s = new Security (); If (! S. CheckRight (......)) { Return; } ...... // Execute the business logic } } |
This is a common practice in OO design. However, this approach may cause the following problems:
1. unclear business logic: In a sense, the permission verification process is not part of the business logic execution. This task belongs to the system. However, in this case, we had to mix the system permission verification process with the business logic execution process, resulting in code confusion.
2. Code waste: to use this method, we must use Security classes in all the business logic code to make the same verification code flood the whole software, which is obviously not a good phenomenon.
3. Tight coupling: to use this method, we must explicitly reference the Security class in the business logic code. This causes the tight coupling between the business logic code and the Security class, which means that, when Security changes, for example, when the system evolves and the CheckRight method needs to be modified, all referenced code may be affected. All of the following problems come from this.
4. Not easy to scale: Here, we only add permission verification in the business logic. On which day, when we need to add additional features, such as the logging function, we have to add this function to all the business logic code.
5. Inflexible: Sometimes, due to some specific needs, we need to temporarily disable or add a function to adopt the traditional approach, as shown above, we have to modify the source code.
To solve these problems, we usually adopt methods such as design patterns to improve the above solution, which often requires high skills. With AOP, we can easily solve the above problems.
Let's take Websharp Aspect as an example to see how to modify the above code to get a better system structure.
First, Security does not need to be modified.
Then, we make a small change to BusinessClass: add an Attribute named AspectManaged to BusinessClass, make BusinessClass inherit AspectObject, and then delete the Security call in the Code. In this way, our code becomes as follows:
[AspectManaged (true)] Public class BusinessClass: AspectObject { Public void BusinessMethod () { ...... // Execute the business logic } } ...... // Execute the business logic |
Then, we add a SecurityAspect for the system.
Public class SecurityAspect: IAspect { Public void Execute (object [] paramList) { If (! Security. CheckRight (......)) { Throw new SecurityException ("You have no permission! "); } } } |
Finally, we add the necessary information to the system configuration file:
<Websharp. Aspects> <Aspect type = "MyAPP. SecurityAspect, MyAPP" deploy-model = "Singleton" Pointcut-type = "Method" action-position = "before" match = "*, *"/> </Websharp. Aspects> |
In this way, we have reconstructed the code. When BusinessClass is called, the AOP framework automatically blocks the BusinessMethod method of BusinessClass and calls the corresponding permission verification method.
In this way, we do not explicitly reference the Security class and its corresponding methods in BusinessClass, and there is no need to reference the Security class in all business logic code. In this way, with the help of the AOP mechanism, we have achieved loose coupling between BusinessClass and Security, and all the problems listed above have been solved. This is also an easy-to-expand mechanism. For example, when we need to add the logging function, we only need to add the corresponding Aspect class and then configure it in the configuration file, without any changes to the business logic code.
6.2.2. Use AOP to combine two business logic
With AOP, we can not only separate system functions and business logic, but also couple different business logic as we did above to obtain a more flexible software structure. Next, we will use a specific case to see how to use AOP to combine two business logic processes.
Assume that the following scenario is used:
We have designed an ERP system in which the inventory management system needs to interact with the financial system. For example, when an inventory item is scrapped, a corresponding financial processing process is required. Therefore, we usually need to reference the relevant financial processing logic in the business logic of inventory goods decommission. This will inevitably lead to coupling of the two parts. Of course, to minimize the coupling between the two parts, we usually use Fa? Ade and other design patterns for decoupling.
For some reason, we need to sell the inventory management system separately, which requires us to remove the referenced financial processing logic from the business logic of stock item decommission, this means we need to modify the original code. To solve this problem, you can add the financial processing logic or delete it from the business logic of stock item decommission at any time. We can use some methods, such as setting some switch parameters, in the business logic of inventory item decommission, determine whether to execute the financial processing logic based on the value of these switch parameters.
The problem is that this is still not an ideal solution. In this way, you must know all the switch parameters that need to be set in advance, and add the corresponding judgment in the business logic code. When you add a similar part to the system that requires flexible processing, the developer has to add the corresponding parameters and modify the corresponding code (add the corresponding judgment code ). It is always bad to modify the code, because according to the software engineering requirements, when there is a new requirement, try not to modify the original code, but add the corresponding code. However, in this case, you cannot.
With AOP, we can achieve this goal in a more natural way. The basic method is as follows:
First, write the related inventory product decommission business logic, do not need to add any other content, and set the logic code to AOP.
Second, write the financial processing logic in the normal way.
Add an Aspect that combines the inventory decommission business logic and financial processing logic. This Aspect can intercept the execution of inventory decommission business logic, dynamically Add the process of financial processing logic, and, configure in the configuration file.
In this way, we combine the two business logic through an Aspect. In addition, we can modify the configuration file to remove the financial processing from the inventory goods decommission business logic at any time without modifying any code.
From the above example, we can see that the advantage of using AOP is that we can write various business logic independently to minimize the coupling between various parts of the system. Then, you can combine two logics at any time in the system as needed without modifying any original code.
6.3 Implementation of Websharp AOP
We should realize that the full implementation of AOP requires the support of development languages. Because the research on AOP is still in progress, the current development languages do not fully support AOP yet. However, we can use some existing language functions, to implement some features of AOP.
The key to Implementing AOP is to intercept normal method calls and transparently "Weave" the functions we need to add to these methods to fulfill some additional requirements. In general, there are two main types of Weaving Methods: static weaving and dynamic weaving.
Static weaving methods generally require extension of the compiler function. You can modify the code to be woven by modifying the bytecode (Java) or IL code (.. Net) method, directly add to the corresponding weaving point; or, we need to add a new syntax structure for the original language, and support AOP from the syntax. AspectJ [19] adopts this method. To implement AOP in this way, the code execution efficiency is high. The disadvantage is that the implementer must have a deep understanding of the virtual machine to modify the bytecode. Since the weaving method is static, when you need to add a new weaving method, you often need to re-compile it, or run the bytecode booster to re-execute the static weaving method. Of course, on the. Net platform, we can also use the powerful features provided by Emit to achieve this. In addition, the bytecode booster brings a lot of opacity, and it is difficult for programmers to visually debug the enhanced bytecode. Therefore, many programmers always resist this bytecode booster psychologically.
There are many options for implementing the Dynamic Weaving method. On the Java platform, you can use the Proxy mode or customize ClassLoader to implement the AOP function. On the. Net platform, the following methods can be used to achieve dynamic AOP weaving:
L use ContextAttribute and ContextBoundObject to intercept object methods. For more information about how to use ContextAttribute, see MSDN.
L use Emit to dynamically construct the class after the code is woven at runtime. When the program call is woven into the class, the modified class is actually called. LOOM uses this method. However, I personally think that the current implementation of LOOM is very rigid, and its scalability and flexibility are not very good.
L use the Proxy mode. This is also the implementation method of Websharp.
The implementation of Websharp uses the object Proxy mechanism. The so-called Proxy is "providing a Proxy for other objects to control access to this object ". You can use the figure below (Figure 5.2) to represent the Proxy mode:
Fig 6.2
For more information and information about the Proxy mode, see annotations.
In WebsharpAspect, when an object is marked as AspectManaged, the creation process and method call of this class will be controlled by WebsharpAspect. Therefore, when you call the following statement:
BusinessClass bc = new BusinessClass ();
In fact, what you get is not an instance of the BusinessClass class, but a proxy of it (for the implementation mechanism, see the relevant source code ). Therefore, when the "instance" method is called, all the calls will be captured by the proxy, and the proxy will perform some predefined operations transparently before the actual method is called, then execute the actual method, and then execute some predefined operations after the actual method is called. In this way, the function of AOP is implemented.
Note that AOP is not only equivalent to method call interception, but also the most common and effective AOP function.
In Websharp AOP, the main classes and interfaces are defined as follows:
6.3.1 AspectObject abstract class
The abstract class AspectObject is defined first. All classes that require AOP management must be inherited from this class. The class is defined as follows:
Public abstract class AspectObject: ContextBoundObject |
The reason for defining this class and letting it inherit ContextBoundObject is that ContextBoundObject subclass ,.. Net runtime environment will establish a binding context for it, so that we can make some custom control over its behavior at runtime. AspectObject inherits ContextBoundObject. In addition, no other attributes and methods are added to AspectObject. In fact, WebsharpAspect can intercept any class directly derived from ContextBoundObject, so it only defines AspectObject for possible scalability in the future.
When a business logic class needs to be managed by Aspect, it must inherit AspectObject and add the AspectManaged feature. For example:
[AspectManaged (true)] Public class BusinessClass: AspectObject { ...... } |
The AspectManaged feature will be described later
6.3.2 IAspect Interface
IAspect defines an aspect. This aspect can intercept the execution of methods before or after the execution of intercepted methods, and then execute the corresponding Advice notification method. The IAspect method of Websharp AOP defines the PreProcess and PostProcess methods to support Before and After notifications. IAspect is defined as follows:
Public interface IAspect { Void PreProcess (IMessage msg ); Void PostProcess (IMessage msg ); } |
6.3.3 AspectManagedAttribute
This is a key class and its function is to intercept the constructor of the class. As mentioned above, when you are executing the following commands:
BusinessClass cls = new BusinessClass ()
In fact, what you get is not BusinessClass, but a proxy of BusinessClass. Because of this, we can intercept the methods of this object, insert our own code.
The class is defined as follows:
[AttributeUsage (AttributeTargets. Class)] [SecurityPermissionAttribute (SecurityAction. Demand, Flags = SecurityPermissionFlag. Infrastructure)] Public class aspectmanagedattriattribute: ProxyAttribute { Private bool aspectManaged; Public AspectManagedAttribute () { AspectManaged = true; } Public aspectmanagedattried (bool AspectManaged) { AspectManaged = AspectManaged; } } |
In aspectmanagedattriject, the most important method is the MarshalByRefObject method. You must reload it. When we intercept constructors, this method will be executed. Here, we can process the intercepted constructor classes to generate proxies for the instantiated classes. The principle code is as follows:
Public override implements albyrefobject CreateInstance (Type serverType) { Export albyrefobject mobj = base. CreateInstance (serverType ); If (aspectManaged) { RealProxy realProxy = new AspectProxy (serverType, mobj ); Export albyrefobject retobj = realProxy. GetTransparentProxy () as your albyrefobject; Return retobj; } Else { Return mobj; } } |
Here, we add a proxy named AspectProxy for the intercepted class. The definition of this proxy is discussed below.
6.3.4 define AspectProxy class
The class is defined as follows:
Public class AspectProxy: RealProxy |
This class is the Proxy class we define. The method weaving is carried out here. When the method of an object is executed by the proxy, It is intercepted by the proxy and the proxy executes the Invoke method. The code we need to execute is woven here. The code for this part is as follows:
Public override IMessage Invoke (IMessage msg) { PreProcess (msg ); IMessage retMsg; If (msg is IConstructionCallMessage) { IConstructionCallMessage ccm = (IConstructionCallMessage) msg; RemotingServices. GetRealProxy (target). InitializeServerObject (ccm ); ObjRef oRef = RemotingServices. Marshal (target ); RemotingServices. Unmarshal (oRef ); RetMsg = EnterpriseServicesHelper. CreateConstructionReturnMessage (Ccm, (FIG) this. GetTransparentProxy ()); } Else { IMethodCallMessage mcm = (IMethodCallMessage) msg; RetMsg = RemotingServices. ExecuteMessage (target, mcm ); } PostProcess (msg ); Return retMsg; } |
We can see that here we have done some processing before and after the method execution. Based on the configuration file, find the matched IAspect derived class defined above and execute the corresponding Advice notification method.
6.3.5 other auxiliary classes
Some of the above classes have completed the main functions of our AOP framework. Of course, we also need some assistance to do some other work, for example, how to find matching Aspect woven classes, the methods of these classes are not listed here for how to read configuration files. For more information, see source code.
6.3.6 configuration file
The configuration file format is defined as follows:
<? Xmlversion = "1.0" encoding = "UTF-8"?> <Configuration> <ConfigSections> <Sectionname = "Websharp. Aspects" type = "Websharp. Aspect. AspectConfigHandler, Websharp. Aspect"/> </ConfigSections> <Websharp. Aspects> <Aspecttype = "WeaveTest. FirstAspect, WeaveTest" deploy-model = "None" Pointcut-type = "Method | Construction | Property" action-position = "Both" match = "*, Get *"/> </Websharp. Aspects> </Configuration> |
First, add a configuration section (configSections) to the configuration file to specify the details of the class used to read the configuration file. In the Windows Form program, the configuration file can generally be app. config. For Web projects, you can add configuration information in the Web. config file. For more information about the configuration file, refer to the related
In the <Websharp. Aspects> section, describe the information of Aspect. You can add multiple Aspect instances to a system.
In Aspect configuration, the attributes are described as follows:
The u type attribute specifies the type of the Aspect class. The format of "Aspect class full name, Assembly" describes the type of the Aspect class and the Assembly.
The u deploy-model attribute specifies the behavior of the Aspect class at the runtime. Values of Singleton and None are supported. When the attribute value is Singleton, only one instance of this Aspect class is available in the system. When the attribute value is None, instances of this class are generated for each call of this class. The Singleton mode provides performance advantages.
U pointcut-type attribute, indicating the type of the Aspect interception point. It can be Method, Construction, or Property, indicating the interception Method, constructor, and attribute respectively. You can use the "|" symbol to specify multiple types of interception points, for example, "Method | Construction ".
U action-position indicates the position of the interceptor relative to the interception point. It can have three values: Before, After, and Both, the Aspect class method is executed relative to the front, back, and back of the interception point.
U match indicates the matching method of the intercepted class. The format is "namespace, Class Name". For example, "MyNamespace, GetString" indicates the method to intercept the MyNamespace namespace and the name is GetString; for example, "*, Get *" indicates to intercept Methods Starting with Get in all namespaces. It can intercept Methods Starting with Get, such as GetString and GetName.
6.4 about AOP and filters
In some development, we may use filters to complete some AOP functions. For example, when a user accesses some resources, we can filter the access information. A common scenario is that in JSP development, in order to correctly process Chinese characters, we usually need to transcode the data transmitted between the browser and the server, to get the correct text encoding. Manual transcoding in each Request is certainly not a good solution. A good example is to write a Filter for the application and perform transcoding automatically. For example, we can write a filter for TOMCAT to implement transcoding:
Public class SetCharacterEncodingFilter implements Filter { Public void doFilter (ServletRequest request, ServletResponse response, FilterChain chain) Throws IOException, ServletException { Request. setCharacterEncoding ("gb2312 "); Chain. doFilter (request, response ); } } |
In this way, we do not have to perform manual transcoding in specific service processing. The business logic is separated from the system functions such as transcoding.
Currently, common Web servers provide similar mechanisms. For example, you can also use the filter function in IIS. The traditional development method is to use VC to develop an ISAPI Filter. After the release of. Net, you can use HttpHandler and HttpModule to implement the same functions, but the development difficulty is much lower [20].
Another scenario that uses filters can be permission control. For example, when a customer requests a Web page (this Web page is usually associated with a service function), the user can use a filter to intercept the request. Then, determine whether the user has the permission to access the requested resource. If yes, the filter can put the request and do nothing. Otherwise, the filter can redirect to a page to tell the user why the request cannot be accessed, or directly throw an exception, it is handled by the previous processor. In this way, we can also separate system functions and business logic such as identity authentication to achieve a better system structure.
Through the functions provided by application environments such as Web servers, we can also implement other AOP functions to build a better system framework.
Conclusion 6.5
AOP gives us a new perspective on the software architecture. Sometimes, even if we do not use the AOP technology, we only use some concepts of AOP and existing technologies to build the system architecture, separating some of these concerns is inherently tightly coupled and is very beneficial to us.