This article will analyze and introduce the application of AOP interception in byteart retail. It will also introduce the specific implementation methods of the two applications, namely, exception handling and cache mechanism implementation.
Background
For an enterprise-level application, the main purpose of implementing it is to solve practical problems in the enterprise production process, such as data problems and management problems. Therefore, the core part of an application should be related to the business of the enterprise, that is, the "Domain Model" that we often mention ". In the modeling process of a domain model, all components unrelated to the business need to be excluded based on the field-driven experience, so that the model can fully express the description of a common language, this plays an important role in system analysis and teamwork. Therefore, in actual system design, we use the so-called poco or pojo to express the relationship between the domain model object and it. Poco/pojo are not objects that do not contain methods. On the contrary, these objects not only contain method definitions, but also are used to process business logic, domain Models composed of these object types are called "Rich Domain Models ". What's different from other objects in the system is that they don't "care" about anything related to technology. For example, they don't know how they will be persisted, I don't know what logs are, What Is cache, how to record logs, how to obtain other required objects from the cache, and so on. In the domain model, Poco/pojo has only one purpose: domain-driven.
Based on this background, since domain models need to maintain their "purity", some framework technologies are required for the entire application to support this requirement. AOP interception is a good method (the other is domain events, which I will introduce in topics related to "Domain Modeling"). Through the AOP technology, you can dynamically generate the intercepted type of proxy, and customize the input and output (such as log records) of the type operation in the proxy type, the type of the proxy only needs to focus on the problem domains that it needs to handle (that is, what we usually call "business"). For those technical-related operations, you can submit the method to the proxy class.
The biggest benefit of doing so is the separation of concerns (separation of concerns), that is, the "proxy class only needs to care about the problem domain" mentioned above, and the second is the flexibility of technology-related processing, for example, we can choose to adopt or not use the logging function, without re-compiling the code. We can dynamically select the cache solution, and do not need to re-compile the code. In addition, the adoption of AOP also brings many benefits to the standalone test of the domain model.
Application of AOP in byteart retail case
Byteart retail uses Microsoft patterns & Practices unity as the AOP framework to demonstrate the application of exception handling and caching Based on AOP. Next, let's take a look at how to use the unity AOP function (interception, which seems to be a policy injection in the past) in the application ).
Interception)
In fact, unity interception is an extension of Unity IOC. There are two separate assemblies related to interception: Microsoft. Practices. Unity. Interception and Microsoft. Practices. Unity. Interception. configuration. Therefore, when using unity interception, You need to introduce these two sets.
First, add the sectionextension node to the unity configuration information:
<sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration"/>
Then, for the type registration that requires the execution of the AOP interception, add the type definition of the interceptor and the definition of the interception behavior. For example, in byteart retail, all AOP interception operations are performed on the application layer service. Therefore, the Unity configuration information of byteart retail contains the following content:
<register type="ByteartRetail.ServiceContracts.IUserService, ByteartRetail.ServiceContracts" mapTo="ByteartRetail.Application.Implementation.UserServiceImpl, ByteartRetail.Application"><interceptor type="InterfaceInterceptor"/><interceptionBehavior type="ByteartRetail.Infrastructure.InterceptionBehaviors.CachingBehavior, ByteartRetail.Infrastructure"/><interceptionBehavior type="ByteartRetail.Infrastructure.InterceptionBehaviors.ExceptionLoggingBehavior, ByteartRetail.Infrastructure"/></register>
In the preceding configuration information, the interceptionbehavior node specifies the interception behavior definition. We can easily see that byteart retail uses two actions: cache and exception handling. The following describes the specific implementation of the two interception behaviors.
Finally, it defines the interception behavior. In byteart retail, all interception behaviors are defined in the byteartretail. Infrastructure. interceptionbehaviors namespace. The interception based on unity usually requires the Microsoft. Practices. Unity. interceptionextension. iinterceptionbehavior interface. This interface contains a read-only attribute willexecute and defines two methods: getrequiredinterfaces and invoke. The most important one is the invoke method. Readers can refer to the implementation of cachingbehavior and predictionloggingbehavior in the byteart retail case to learn about these attributes and methods.
Interception behavior: Exception Handling
The interception behavior of exception handling in byteart retail is very simple, that is, to determine whether there is an exception in the intercepted method call. If yes, utils is used. the log method records exceptions to logs, while at the underlying layer, utils. log is recorded using log4net. The invoke Method for exception handling interception behavior is implemented as follows:
/// <Summary> /// implement this method to intercept calls and execute the required interception behavior. /// </Summary> /// <Param name = "input"> specifies the input information when the interception target is called. </Param> /// <Param name = "getnext"> the behavior chain is used to obtain the delegate of the next interception behavior. </Param> /// <returns> returned information from the interception target. </Returns> Public imethodreturn invoke (imethodinvocation input, getnextinterceptionbehaviordelegate getnext) {var methodreturn = getnext (). Invoke (input, getnext); If (methodreturn. Exception! = NULL) {utils. Log (methodreturn. Exception);} return methodreturn ;}
Therefore, when an exception occurs in the application layer service call, we can find the relevant exception information in the file system, such:
In actual projects, exception handling methods are diverse. Here only exception records are used to demonstrate the AOP-based exception handling methods.
Interception behavior: Cache
Cache is also a very important technology widely used in enterprise applications. In byteart retail, the cache is not directly implemented and used through a specific caching mechanism, but is implemented in a way that intercepts behavior in Unity interception. The introduction of cache reduces the system I/O pressure (such as reducing network traffic and the number of database disk reads), thus improving the system performance to a certain extent.
As mentioned above, in byteart retail, because the interception behavior is implemented based on the application layer service, the cache is also designed based on the application layer service. Specifically, for example, when the client calls iproductservice before the cache interception is introduced. when getproductbyid is used, the application-layer service productservice will reconstruct the domain object from the database based on the input parameters, and then convert it to the data transmission object (DTO) to return. After the cache interception is introduced, productservice first checks whether the required objects exist in the cache. If yes, it returns directly; otherwise, it searches the database and returns, at the same time, the searched object will be saved to the cache for future use. Of course, before implementation, it is best to analyze the objects to be cached so as to better implement caching. For example, in the byteart retail case, the product information, product category, and other objects are cached. because the information is much queried and slightly changed, the response of the application is greatly improved.
To decouple the specific implementation of the application and cache mechanism, byteart retail uses the proxy mode, Singleton mode, and service locator) the entire cache mechanism is designed.
First, a "cache provider" interface is defined, which provides applications with a method to access the cache mechanism, including: add an object to the cache, obtain the object from the cache, and determine whether the object exists in the cache. The Code is as follows:
/// <Summary> /// indicates that the type of the interface implemented is the type that can provide the cache mechanism for the application. /// </Summary> Public interface icacheprovider {# Region Methods // <summary> // Add an object to the cache. /// </Summary> /// <Param name = "key"> the cached key value, which is usually the name of the method using the cache mechanism. </Param> // <Param name = "valkey"> the key value of the cached value, which is usually generated by the parameter value of the method using the cache mechanism. </Param> /// <Param name = "value"> specifies the object to be cached. </Param> void add (string key, string valkey, object value); // <summary> // update an object to the cache. /// </Summary> /// <Param name = "key"> the cached key value, which is usually the name of the method using the cache mechanism. </Param> // <Param name = "valkey"> the key value of the cached value, which is usually generated by the parameter value of the method using the cache mechanism. </Param> /// <Param name = "value"> specifies the object to be cached. </Param> void put (string key, string valkey, object value); // <summary> // read the object from the cache. /// </Summary> /// <Param name = "key"> the cached key value, which is usually the name of the method using the cache mechanism. </Param> // <Param name = "valkey"> the key value of the cached value, which is usually generated by the parameter value of the method using the cache mechanism. </Param> /// <returns> the cached object. </Returns> Object get (string key, string valkey); // <summary> /// remove an object from the cache. /// </Summary> /// <Param name = "key"> the cached key value, which is usually the name of the method using the cache mechanism. </Param> void remove (string key); // <summary> // obtain a <see CREF = "Boolean"/> value, indicates whether the cache with the specified key value exists. /// </Summary> /// <Param name = "key"> specifies the key value. </Param> /// <returns> If the cache exists, true is returned. Otherwise, false is returned. </Returns> bool exists (string key); // <summary> // obtain a <see CREF = "Boolean"/> value, indicates whether the cache with the specified key value and cache key exist. /// </Summary> /// <Param name = "key"> specifies the key value. </Param> /// <Param name = "valkey"> cache value Key. </Param> /// <returns> If the cache exists, true is returned. Otherwise, false is returned. </Returns> bool exists (string key, string valkey); # endregion}
Next, the specific implementation of the cache mechanism (byteart retail provides two implementations: the cache based on Microsoft patterns & Practices Enterprise Library caching Application Block and the cache based on Windows Server appfabric caching, see byteartretail. infrastructure. both the caching namespace and cache manager implement the icacheprovider interface. The cache manager provides cache services for applications in combination with the proxy mode and service locator mode. The relationship between related types can be represented by the following class diagrams:
Based on this design, when the application needs to use the cache mechanism, you only need to call the related methods of cachemanager.
Next, let's take a look at how the cache is used in interception. The general process of Cache Usage is that the system first sets the cachingattribute attribute in the method in the application layer service interface to determine the Cache Usage method of the currently blocked method, for example, in iproductservice. in the getproductbyid method, the Cache Usage is set to get through cachingattribute, which means that when the client calls this method, the interception behavior first tries to get the object from the cache based on the input parameters, if yes, the system will directly return an object. Otherwise, the interception will call the proxy application layer service to obtain the object, cache it, and return it. For example, in iproductservice. on the deleteproduct method, you can use cachingattribute to set the Cache Usage method to remove. This means that when the client calls this method, blocking will clear all objects stored in the cache in the specified method, then, the proxy application layer service is called, so that the cached data will be updated when the get method is called next time. For example, in iproductservice. in the definition of the deleteproducts method, cachingattribute sets the names of all methods that will generate the product information cache. The cached data generated by these methods will be deleted when deleteproducts is called:
/// <Summary> /// Delete the product information. /// </Summary> /// <Param name = "productids"> ID of the item to be deleted. </Param> [operationcontract] [faultcontract (typeof (faultdata)] [caching (cachingmethod. remove, "getproductsforcategory", "getproductswithpagination", "getfeaturedproducts", "identifier", "getproducts", "getproductbyid")] void deleteproducts (idlist productids );
In fact, such an implementation method still has some minor problems. It is not the best way to delete all cached objects in one brain, however, byteart retail mainly aims to demonstrate the implementation of cache in AOP interception, so it has not been carefully considered. If you are interested in it, you can continue to optimize it. The implementation code of the cache interception behavior cachingbehavior will not be repeated here. Readers can click here to view it. Finally, let's take a look at the impact of byteart retail on system performance when introducing different cache mechanisms. Iproductservice is called without caching, appfabric-based caching, and Enterprise Library caching Application Block. compare the response time (average) of the getproductbyid method. From the result, the call response time cached by the Enterprise Library caching application block is the shortest with the same number of calls, the call response time without using the cache mechanism is the longest. Although appfabric caching does not have a short response time for the caching application block, it can provide more flexible and distributed cache management solutions, this allows cached data to be used by processes across application domains. Therefore, the specific solution used in the actual project depends on the actual situation.
Summary
This article describes in detail how to handle exceptions and cache based on AOP interception in byteart retail cases. These methods can be used for your reference, in addition, more cross-cutting functions can be implemented based on this idea, such as security verification. Finally, let's review the original intention of using AOP: we did not bring any technical content into the domain model.
[Apworks.org site this article link: http://apworks.org /? P = 372]