There are two kinds of beans that are indispensable in any project, one is the bean that implements the core function of the system, we call it the business class, the second is the service bean which is unrelated to the core business of the system but also provides very important service beans at the same time. The bean of the business class can be arbitrarily multiple depending on the core function of each system, but the difference between the types of service classes in each system is not very large. There are several services that are frequently used in the system. Permissions service, log service. Caching services, transaction services, and early warning services. In the process of continuous evolution of the entire system. The relationship between service class and business class has changed constantly, from the original vertical mode to the crosscutting mode, which is also the process of programming thought. Service classes and business classes should not be coupled together, otherwise it will not only cause a lot of code redundancy at the same time it is difficult to make a controllable change to the service.
So how to solve the problem of providing different services according to different business classes ' own requirements? Spring AOP gives the perfect solution. The core idea of spring's solution to this conundrum is to put the service and business classes into the spring container management. Dynamically configure service classes based on the different requirements of different business classes. It is also the free combination of the dynamic Union service class and the business class implementation. The evolution of the relationship between the business class and the service class can be presented in a simple way:
This picture is the most primitive business-service relationship diagram, see this even want to dare not think, the same service repeatedly out of today N multiple business, think is also drunk, assuming that the service content changes in addition to jumping off the expected to have no other choice, fortunately, the advent of spring AOP will be a headache for the problem. Using the spring annotations to cross-cut a slice class into each service class is a great way to resolve code redundancy. Issues that are difficult to maintain
The drawing in the code is for example the following:
Package com.test.util; @Aspectpublic class Authorityservice {@Autowiredprivate Logmanager logmanager; @Before (" Execution (* com.test.web.*.* (..)) ") public void Logall (Joinpoint point) throws Throwable {System.out.println ("======authority-before======");} @After ("Execution (* com.test.web.*.* (..))") public void After () {System.out.println ("=========authority-after=========");} Call @around ("Execution (* com.test.web.*.* (..))") before and after the method runs Public Object around (Proceedingjoinpoint point) throws Throwable {System.out.println ("====== Authority-around before the beginning of before====== "); HttpServletRequest request = ((servletrequestattributes) requestcontextholder.getrequestattributes ()). GetRequest () ;//Get specific time simpledateformat df = new SimpleDateFormat ("Yyyy-mm-dd HH:mm:ss");//Calendar CA = calendar.getinstance ();//St Ring Operdate = Df.format (Ca.gettime ()); Log SysLog = new log ();//Start Time Syslog.setstarttime (Df.format (New Date ()));//Get IP address string ip = tcpiputil.getipaddr ( request); String LoginName; String name; String Methodremark = Getmthodremark (point); String methodName = Point.getsignature (). GetName (); String packages = Point.getthis (). GetClass (). GetName (); if (Packages.indexof ("$ $EnhancerByCGLIB $$") >-1) {// Assume that the cglib dynamically generated class try {packages = packages.substring (0, Packages.indexof ("$$")),} catch (Exception ex) {Ex.printstacktrace ();}} Object object;try {//Method_param = Point.getargs ();//Get Method Parameters//String param= (String) point.proceed (Point.getargs ()); O Bject = Point.proceed ();} catch (Exception e) {//Exception handling log: Log.error (e); throw e;} Syslog.setip (IP); syslog.setclazz (packages); Syslog.setmethod (methodName); Syslog.setmessage (Methodremark);// End Time Syslog.setendtime (Df.format (New Date ()));//Returns the result if (object = = null) {Syslog.setresult ("no return Value");} else { Syslog.setresult (Object.ToString ());} Logmanager.addlog (SYSLOG); System.out.println ("======authority-around before after======"); return object;} @AfterReturning ("Execution (* com.test.web.*.* (..))") public void X () {System.out.println ("-------authority-afterreturning-------");} Get partyThe Chinese note ____ is used to record the user's operation log description public static String Getmthodremark (Proceedingjoinpoint joinpoint) throws Exception {String TargetName = Joinpoint.gettarget (). GetClass (). GetName (); String methodName = Joinpoint.getsignature (). GetName (); object[] arguments = Joinpoint.getargs (); Class Targetclass = Class.forName (targetName); Method[] method = Targetclass.getmethods (); String Methode = ""; for (Method M:method) {if (M.getname (). Equals (MethodName)) {class[] tmpcs = M.getparametertypes (); if (Tmpcs.length = = arguments.length) {Logger Methodcache = m.getannotation (Logger.class);//get token, NULL if not marked if (Methodcache! = null) {Methode = Methodcache.remark ();} Break;}}} return Methode;}}
It can be seen from the above code that the permission service class is cut into all the methods of all classes under the Com.test.web package. Similarly, we can build the cache service class again. Log service classes are cut into other business classes, and now it seems that the headache is being solved by spring based on @aspect-style AOP, but do we think carefully about the problem? As we all know, the grain size of this cut-in method is too coarse, and not all the methods of all classes under the same package need this kind of service, to give a very easy example. In the case of caching services and log services, the log service is required to be specifically documented and can be cut into whatever method it is. But the caching service is not. The caching service may only exist on the method where the class gets the data, at which point the cache service is cut into the class's changes. Delete and so on the method is very wonderful, and then the popular will is no matter what a service may exist only in the specific method of a particular class, this uncertainty determines the use of only spring @Aspect annotation is difficult to solve the problem
What do we need to do now? Fortunately, Spring provides an AOP based on XML configuration, which, to a considerable extent, compensates for @aspect, and he is able to cut different services into different ways based on different configurations. This fine granularity allows us to achieve a dynamic combination of services to the business. It may be asked if spring provides an AOP based on XML configuration. So we just need to configure different services in the XML file is not the same can achieve business and service dynamic combination? That sounds plausible, and it seems that the annotation-based AOP seems to be able to be replaced. However, the problem of the efficiency of the program let us have to correct the XML configuration and annotation method to re-measure.
Because XML is an execution-time dynamic union to determine facets, the process of parsing XML will undoubtedly consume system resources, assuming that a large number of AOP configuration in the XML file will be more than the loss, and the @aspect way to support the compile-time weaving and do not need to generate agents, This makes an advantage in efficiency. In this way, it is only a mix of XML and @aspect. Coarse-grained services, such as logs and rights services, are cut into the @aspect way, and the use of XML configuration for fine-grained services such as caching services can solve these problems perfectly in spring.
The following are examples of the two ways in which they are used together. First look at the configuration file:
<?XML version= "1.0" encoding= "UTF-8"?
><beans xmlns= "Http://www.springframework.org/schema/beans" xmlns:xsi= "http://www.w3.org/2001/ Xmlschema-instance "xmlns:aop=" HTTP://WWW.SPRINGFRAMEWORK.ORG/SCHEMA/AOP "xmlns:context="/HTTP/ Www.springframework.org/schema/context "xmlns:mvc=" Http://www.springframework.org/schema/mvc "xsi:schemalocation = "Http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp ://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsdhttp:// Www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.2.xsdhttp ://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd "><!-- Annotation Scan Package--><context:component-scan base-package= "Com.test"/><!--opening annotations--><mvc:annotation-driven/ ><!--access to static resources (js/image)--><mvc:resources location= "/js/" mapping= "/js/**"/><!--define view Resolver-- <bean id= "Viewresolver" class= "Org.springframework.web.servlet.view.InternalResourceViewResolver "><property name=" prefix "value="/"> </property><property name= "suffix" value= ". jsp" ></property></bean><!-- Enable spring for @aspectj aspects-based configuration support--><aop:aspectj-autoproxy></aop:aspectj-autoproxy><bean id= " Logservice "class=" Com.test.util.LogService "></bean><bean id=" Cacheservice "class=" Com.test.util.CacheService "></bean> <aop:config proxy-target-class=" true "> <aop:aspect ref= "Cacheservice" > <aop:pointcut id= "Log" expression= "Execution (* com.test.web.UserController.getAl Luser (..)) " /> <aop:before pointcut-ref= "log" method= "Logall"/> <aop:after pointcut-ref= "Log "Method=" after "/> <aop:after-returning pointcut-ref=" Log "method=" x "/> <aop:aro und pointcut-ref= "Log" method= "Around"/> </aop:aspect> </aop:config></beans>
Next is the Log service class:
Package com.test.util; @Aspectpublic class Logservice {@Autowiredprivate Logmanager logmanager; @Before ("Execution (* Com.test.web.*.* (..)) ") public void Logall (Joinpoint point) throws Throwable {System.out.println ("======log-before======");} @After ("Execution (* com.test.web.*.* (..))") public void After () {System.out.println ("=========cache-after=========");} Call @around ("Execution (* com.test.web.*.* (..))") before and after the method runs Public Object around (Proceedingjoinpoint point) throws Throwable {System.out.println ("======log-around before beginning before==== =="); HttpServletRequest request = ((servletrequestattributes) requestcontextholder.getrequestattributes ()). GetRequest () ;//Get specific time simpledateformat df = new SimpleDateFormat ("Yyyy-mm-dd HH:mm:ss"); Log SysLog = new log ();//Start Time Syslog.setstarttime (Df.format (New Date ()));//Get IP address string ip = tcpiputil.getipaddr ( request); String LoginName; String name; String Methodremark = Getmthodremark (point); String methodName = Point.getsignature (). GetName (); String packages = Point.getthis(). GetClass (). GetName (); if (Packages.indexof ("$ $EnhancerByCGLIB $$") >-1) {//assumed to be cglib dynamically generated class try {packages = Packages.substring (0, Packages.indexof ("$$")); catch (Exception ex) {ex.printstacktrace ();}} String operatingcontent = "";//object[] Method_param = null;object object;try {//Method_param = Point.getargs (); Gets the method parameter//String param= (String) point.proceed (Point.getargs ()), Object = Point.proceed ();} catch (Exception e) {//Exception handling log: Log.error (e); throw e;} Syslog.setip (IP); syslog.setclazz (packages);//Package name + method name//Packages + "." + Methodnamesyslog.setmethod (methodName); Syslog.setmessage (Methodremark);//End Time Syslog.setendtime (Df.format (New Date ()));//return result if (object = = null) { Syslog.setresult ("No return Value");} else {Syslog.setresult (object.tostring ());} Logmanager.addlog (SYSLOG); System.out.println ("======log-around before after======"); return object;} @AfterReturning ("Execution (* com.test.web.*.* (..))") public void X () {System.out.println ("-------log-afterreturning-------");} Get the Chinese notes of the method ____ used for the record employmentUser's operation log description public static string Getmthodremark (Proceedingjoinpoint joinpoint) throws Exception {String TargetName = Joinpoint.gettarget (). GetClass (). GetName (); String methodName = Joinpoint.getsignature (). GetName (); object[] arguments = Joinpoint.getargs (); Class Targetclass = Class.forName (targetName); Method[] method = Targetclass.getmethods (); String Methode = ""; for (Method M:method) {if (M.getname (). Equals (MethodName)) {class[] tmpcs = M.getparametertypes (); if (Tmpcs.length = = arguments.length) {Logger Methodcache = m.getannotation (Logger.class);//get token, NULL if not marked if (Methodcache! = null) {Methode = Methodcache.remark ();} Break;}}} return Methode;}}
Next is the cache service class;
Package Com.test.util;public class Logservice {@Autowiredprivate CacheManager logmanager;public void Pointcut () {} public void Logall (Joinpoint point) throws Throwable {System.out.println ("======cache-before======");} public void After () {System.out.println ("=========cache-after=========");} The method runs before and after calling public Object around (Proceedingjoinpoint point) throws Throwable {System.out.println ("====== Cache-around before the beginning of before====== "); HttpServletRequest request = ((servletrequestattributes) requestcontextholder.getrequestattributes ()). GetRequest () ;//Get specific time simpledateformat df = new SimpleDateFormat ("Yyyy-mm-dd HH:mm:ss");//Calendar CA = calendar.getinstance ();//St Ring Operdate = Df.format (Ca.gettime ()); Log SysLog = new log ();//Start Time Syslog.setstarttime (Df.format (New Date ()));//Get IP address string ip = tcpiputil.getipaddr ( request); String LoginName; String name; String Methodremark = Getmthodremark (point); String methodName = Point.getsignature (). GetName (); String packages = Point.getthis (). GetClass (). GetName () if (Packages.indexof ("$ $EnhancerByCGLIB $$") >-1) {//hypothesis is cglib dynamically generated class try {packages = packages.substring (0, packages . IndexOf ("$$"));} catch (Exception ex) {ex.printstacktrace ();}} Object object;try {//Method_param = Point.getargs ();//Get Method Parameters//String param= (String) point.proceed (Point.getargs ()); O Bject = Point.proceed ();} catch (Exception e) {//Exception handling log: Log.error (e); throw e;} Syslog.setip (IP); syslog.setclazz (packages);//Package name + method name//Packages + "." + Methodnamesyslog.setmethod (methodName); Syslog.setmessage (Methodremark);//End Time Syslog.setendtime (Df.format (New Date ()));//return result if (object = = null) { Syslog.setresult ("No return Value");} else {Syslog.setresult (object.tostring ());} Logmanager.addlog (SYSLOG); System.out.println ("======cache-around before after======"); return object;} public void X () {System.out.println ("-------cache-afterreturning-------");}}
The Log service class and the cache service class are not the same in the detailed processing process, this article makes a slight modification on the basis of the log service to simplify the processing. You can use the cache processing and log processing according to your own situation. In the detailed operation of the careful friend may send in today's configuration file in the order of the different services to determine the order of two services run. In other words, the spring AOP run-in action is through the decorator mode to complete, using a similar stack of advanced after-out way to run the service in detail, we must pay attention to AH.
Spring Container Decorator Mode application solution for the free combination of business class and service class