In-depth analysis of Java Web Item53 -- AOP Aspect-Oriented Programming in Spring 1

Source: Internet
Author: User

In-depth analysis of Java Web Item53 -- AOP Aspect-Oriented Programming in Spring 1
I. Basic concepts of AOP and Spring support for AOP1. Basic concepts of AOP

AOP considers the program process from the perspective of running and extracts the aspect of the business processing process. AOP is designed for all steps in the program running and hopes to better combine the steps of the business logic. The AOP framework is not coupled with specific code. The AOP framework can process specific entry points in program execution, rather than coupling with a specific class (that is, without polluting a class, processing the cut points related to this class ). Some AOP terms are as follows:

Section(Aspect): a specific step of business flow running, that is, the focus of the application running process. The focus is usually cross-cutting multiple objects. Therefore, it is often called a cross-cutting concern.

Connection Point(JoinPoint): a specific point in the program execution process, such as a method call or an exception thrown. In Spring AOP, connection points are always called by methods.

Notification(Advice): the notification that the AOP framework executes at a specific entry point. The processing methods include round, before, and after. (AOP is a preface, but most domestic translators always read various translation software and dictionaries while translating computer documents, instead of grasping the knowledge architecture in general. Therefore, it is inevitable that some terms cannot be translated into satisfactory words, and there are also great differences in AOP terms. For Advice, some people translate it into "notifications", while others translate it into "Suggestions "...... In fact, Advice refers to some processing that the AOP framework adds to a specific aspect. Here I also translate it into "notifications", hoping to express the true meaning of Advice)

Entry Point(PointCut): the point where notifications can be inserted. In short, when a connection point meets the execution requirements, the connection point is added with a notification, and the connection point becomes the entry point. For example:

pointcut xxxPointcut():execution(void H*.say*())

Each method is called as a connection point. However, if the method belongs to a class starting with H and the method name starts with "say", the execution of this method will become a starting point. How to use expressions to define the entry point is the core of AOP. Spring uses the AspectJ entry point syntax by default.

Introduction:Add methods or fields to the processed class. Spring allows the introduction of new interfaces to any processed objects

Target object: The object to be notified by the AOP framework, also known as the enhanced object. If the AOP framework is implemented in the runtime era, this object will be a proxy object.

AOP proxy: The objects created by the AOP framework, simply put, proxy is the enhancement to the target objects. In Spring, the AOP proxy can be JDK dynamic proxy or CGLIB proxy. The former is the proxy of the target object that implements the interface, and the latter is the proxy of the target object that does not implement the interface.

Woven(Weaving): the process of adding a notification to the target object and creating an enhanced object (AOP proxy) is woven. There are two ways to implement weaving: compile-time enhancement (such as AspectJ) and runtime enhancement (such as CGLIB ). Like other pure Java AOP frameworks, Spring is woven at runtime.

As mentioned above, the AOP proxy is actually an object dynamically generated by the AOP framework. This object can be used as the target object. The AOP proxy contains all the methods of the target object, but there are differences between the methods in the AOP proxy and the methods of the target object: The AOP method adds notifications in a specific entry point and calls back the methods of the target object.

2. Support for Spring AOP

In Spring, the AOP proxy is generated and managed by the Spring IoC container. The dependency is also managed by the IoC container. Therefore, the AOP proxy can directly use other beans in the container as the target. This relationship can be provided by the dependency injection of the IoC container. By default, Spring supports using JDK dynamic proxy to create an AOP proxy, so that you can create a proxy for any interface implementation.

Spring also supports CGLIB proxy. When proxy classes instead of proxy interfaces are required, Spring automatically switches to CGLIB proxy. However, object-oriented programming is recommended for Spring. Therefore, Business Objects usually implement one or more interfaces. By default, JDK dynamic proxy is used, but CGLIB can also be forcibly used.

Spring AOP is implemented in Java only. It does not require a special compilation process. Spring AOP does not need to control the hierarchy of the Class Loader, so it can run well in all Java Web containers or application servers.

Currently, Spring only supports method calls as the connection point (JoinPoint). If you need to use access and update to the Field as the connection point of the notification (Advice), you can consider using AspectJ.

The Spring implementation AOP framework is different from other frameworks. Spring does not provide the most complete AOP implementation (although Spring AOP has this capability), but focuses on the integration between AOP implementation and Spring IoC, it helps solve common problems in enterprise-level development. Therefore, Spring is usually used together with the IoC container, and Spring has never competed with AspectJ by providing a comprehensive AOP solution. Spring AOP adopts a proxy-based AOP implementation scheme, while AspectJ adopts an enhanced solution during compilation.

Spring can seamlessly integrate Spring AOP, IoC, and AspectJ. Yes, all AOP applications are fully integrated into the Spring-based framework. Such integration will not affect Spring AOP APIs or AOP Alliance APIs, spring AOP maintains downward compatibility and allows you to use Spring AOP APIs directly to complete AOP programming.

Once we have mastered the concept of AOP, it is not difficult to find that it is very easy to program AOP. Throughout AOP programming, programmers are required to participate in only three parts:

Define Common Business Components

Defines PointCut. A single PointCut may cross multiple business components.

Define the notification (Advice) to notify the handling actions when the AOP framework is woven to common business components in a timely manner.

The first part is the most common thing. The second and third parts are the key to AOP: once an appropriate entry point and notification are defined, the AOP framework will automatically generate a proxy, and the method of the AOP proxy is roughly as follows:

Proxy object method = notification + proxy object Method

Spring 1. x uses its own aop api to define the entry point and notification. The program can directly use the Spring aop api to define the entry point and notification. However, this method seems outdated, we recommend that you use the AspectJ method to define the entry point and notification. In this method, Spring still has the following two options to define the entry point and notification:

Annotation-based configuration method: Use annotations such as @ Aspect and @ Pointcut to mark the entry point and notification

XML-based configuration file

2. Annotation-Based Configuration

AspectJ allows annotations to be used to define cut points, entry points, and notifications. The Spring framework can identify and generate AOP proxies based on these annotations. Spring only uses the same annotation as AspectJ 5, but does not use the AspectJ compiler or the Weaver. SpringAOP is still used at the underlying layer, and the AOP proxy is dynamically generated at runtime, therefore, you do not need to add additional compilation or support for the AspectJ feeder. AspectJ is enhanced during compilation, so AspectJ needs to use its own compiler to compile Java files, and also needs to be woven into the machine.

To enable Spring's support for @ AspectJ aspect configuration and ensure that the target Bean in the Spring container is automatically enhanced by one or more aspect, the following content must be configured in the Spring configuration file (lines 4th, 9, 10, and 15 ):

<code class=" hljs xml"><!--{cke_protected}{C}%3C!%2D%2D%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%2D%2D%3E--><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" xsi:schemalocation="    http://www.springframework.org/schema/beans     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd    http://www.springframework.org/schema/aop     http://www.springframework.org/schema/aop/spring-aop-3.0.xsd    http://www.springframework.org/schema/context        http://www.springframework.org/schema/context/spring-context-3.0.xsd"><!--{cke_protected}{C}%3C!%2D%2D%20%E5%90%AF%E5%8A%A8%40AspectJ%E6%94%AF%E6%8C%81%20%2D%2D%3E--><aop:aspectj-autoproxy></aop:aspectj-autoproxy></beans></code>

The so-called automatic enhancement means that Spring will determine whether to enhance the specified Bean on one or more sides, and then automatically generate the corresponding proxy accordingly, this allows the notification to be called when appropriate. If you do not want to use the XML Schema configuration method, add the following snippet to the Spring configuration file to enable @ AspectJ support (That is, the precedingAnd select one of the following ways to create Bean to enable @ AspectJ support):


  

The above configuration is a Bean post-processor which will generate an AOP proxy for the Bean in the container.

To enable @ AspectJ support in Spring applications, you also need to add two AspectJ libraries: aspectweaver under the used class loading path. jar and aspectjrt. jar, directly use the two Jar files under the lib directory under the AspectJ installation path. Of course, you can also find them in the lib/aspectj path of the Spring extract folder. The project content is as follows:

1. Define the slice Bean

When @ AspectJ support is enabled, Spring will automatically identify the Bean and process the Bean as a plane as long as we configure a Bean with @ AspectJ annotation in the Spring container. The following is an example:

@Aspectpublic class LogAspect {}

The partition class (the class modified with @ Aspect) can have methods and attribute definitions like other classes, and may also include the definition of the entry point and notification. When weAfter @ Aspect is used to modify a Java class, Spring will not treat the Bean as a component Bean. Therefore, after the Spring container detects that a Bean is labeled with @ AspectJ, the post-processing Bean responsible for automatic enhancement ignores the Bean and does not notify the Bean.

2. Use Before notification

When @ Before is used to mark a method in a face-cutting class, this method will be used as a Before notification. When you use @ Before annotation, you usually need to specify a value attribute value, which specifies a pointcut expression (either an existing pointcut or a pointcut expression ), specifies the entry points to which the notification will be woven. Example:

Package com. abc. advice; import org. aspectj. lang. annotation. aspect; import org. aspectj. lang. annotation. before; @ Aspectpublic class BeforeAdviceTest {// match com. abc. the method starting with before in the class under service @ Before ("execution (* com. abc. service. *. before *(..)) ") public void permissionCheck () {System. out. println ("simulated permission check ");}}

The above program uses @ Aspect to modify the BeforeAdviceTest class, which indicates that this class is a face-cutting class and defines a permissionCheck method in the veneer. This method has no special features, however, because @ Before is used to mark this method, this method is converted into a Before notification. In this @ Before annotation, the entry point expression is directly specified, and the execution of the method starting with before is used as the entry point in the class under the com. abc. service package. Assume that we have a class in com. abc. service:

Package com. abc. service; import org. springframework. stereotype. component; @ Componentpublic class AdviceManager {// This method will be matched to public void BeforeAdviceTest class permissionCheck () {System. out. println ("method: beforeAdviceTest ");}}

From the code above, this AdviceManager is a pure Java class, and it has no idea who will enhance it, I don't know how to enhance it. formally, the AdviceManager class's "Ignorance" is the biggest charm of AOP: The target class can be infinitely enhanced.

Configure the automatic search Bean component in the Spring configuration file and configure the automatic search for the partition class. SpringAOP automatically enhances the Bean component. The following is the Spring configuration file code:

<code class=" hljs xml"><!--{cke_protected}{C}%3C!%2D%2D%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%2D%2D%3E--><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" xsi:schemalocation="        http://www.springframework.org/schema/beans         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd        http://www.springframework.org/schema/aop         http://www.springframework.org/schema/aop/spring-aop-3.0.xsd        http://www.springframework.org/schema/context        http://www.springframework.org/schema/context/spring-context-3.0.xsd">    <!--{cke_protected}{C}%3C!%2D%2D%20%E5%90%AF%E5%8A%A8%40AspectJ%E6%94%AF%E6%8C%81%20%2D%2D%3E-->    <aop:aspectj-autoproxy>    <!--{cke_protected}{C}%3C!%2D%2D%20%E6%8C%87%E5%AE%9A%E8%87%AA%E5%8A%A8%E6%90%9C%E7%B4%A2Bean%E7%BB%84%E4%BB%B6%EF%BC%8C%E8%87%AA%E5%8A%A8%E6%90%9C%E7%B4%A2%E5%88%87%E9%9D%A2%E7%B1%BB%20%2D%2D%3E-->    <context:component-scan base-package="com.abc.service,com.abc.advice">        <context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect">    </context:include-filter></context:component-scan></aop:aspectj-autoproxy></beans></code>

The main program is very simple. Get AdviceManager Bean through the Spring container and call beforeAdvice OF Bean:

package com.abc.main;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.abc.service.AdviceManager;@SuppressWarnings("resource")public class AOPTest {    public static void main(String[] args) {        ApplicationContext context =             new ClassPathXmlApplicationContext("applicationContext.xml");        AdviceManager manager = context.getBean(AdviceManager.class);        manager.beforeAdvice();    }}

Run the main program and you will see the following results:

Before notification can only be woven into the enhancement Before the target method is executed. If Before notification is used, the execution of the target method is ignored. Therefore, Before processing cannot prevent the execution of the target method. Before notification execution, the target method has not been given the execution opportunity, so Before notification cannot access the returned value of the target method.

3. Use AfterReturning notification

Similar to the use of the @ Before annotation, @ AfterReturning is used to mark an AfterReturning notification. The processing will be woven after the target method is completed normally. When @ AfterReturning is used, two attributes can be specified:

Pointcut/value: These two attributes have the same effect and are used to specify the cut-in expression corresponding to the start point. Likewise, it can be an existing or directly defined starting point. When the pointcut attribute is specified, the value attribute value will be overwritten.

Returning: Specifies a return value parameter name. The notification-defining method can use this parameter to access the return value of the target method.

Add AfterReturningAdviceTest under the com. abc. advice package. This class defines an AfterReturning notification:

Package com. abc. advice; import org. aspectj. lang. annotation. afterReturning; import org. aspectj. lang. annotation. aspect; @ Aspectpublic class AfterReturningAdviceTest {// match com. abc. the method starting with afterReturning in the class under service @ AfterReturning (returning = "returnValue", pointcut = "execution (* com. abc. service. *. afterReturning (..)) ") public void log (Object returnValue) {System. out. println ("target method return value:" + returnValue); System. out. println ("simulate logging... ");}}

Add the following content to the AdviceManager class:

// Match the public String AfterReturningAdviceTest's log method with the public String afterReturning () {System. out. println ("method: afterReturning"); return "afterReturning method ";}

As shown in the preceding program, a returning attribute is specified when @ AfterReturning annotation is used in the program. The returned value of this attribute is returnValue, this indicates that the parameter named returnValue can be used in the log of the enhancement method. This parameter indicates the return value of the target method. In the main method of AOPTest, add the statements that call this method and run the test class. The following results are displayed:

@ AfterReturning the parameter name specified by the returning attribute of the annotation must correspond to a parameter name in the notification. After the target method is executed, the return value is passed as the corresponding parameter to the notification method.

Note that the @ AfterReturning attribute has an additional function, it can be used to limit the matching of the entry point to a method with the corresponding return value type. Assume that the returnValue type of the preceding log method is String, then this entry point only matches com. abc. service. all methods whose return value is String in the impl package. Of course, if the returned value type of the preceding log method is Object, this indicates that the entry point can match any returned value method. In addition, although AfterReturning notifies you That the returned value of the target method can be accessed, it cannot change the returned value.

4. Use AfterThrowing notification

@ AfterThrowing annotation can be used to mark an AfterThrowing notification, which is mainly used to handle exceptions not handled by Chen Xu. You can specify two attributes when using this annotation:

Pointcut/value: These two attributes have the same effect and are used to specify the cut-in expression corresponding to the start point. Likewise, it can be an existing or directly defined starting point. When the pointcut attribute is specified, the value attribute value will be overwritten.

Throwing: Specifies a return value parameter name. The notification-defined method can use this parameter to access the exception object thrown in the target method.

Add AfterThrowingAdviceTest under the com. abc. advice package. This class defines an AfterThrowing notification:

Package com. abc. advice; import org. aspectj. lang. annotation. afterThrowing; import org. aspectj. lang. annotation. aspect; @ Aspectpublic class AfterThrowingAdviceTest {@ AfterThrowing (throwing = "ex", pointcut = "execution (* com. abc. service. *. afterThrow *(..)) ") public void handleException (Throwable ex) {System. out. println ("the target method throws an exception:" + ex); System. out. println ("simulated Exception Handling ");}}

Add the following content to the AdviceManager class:

// The handleException method of AfterThrowingAdviceTest matches public void afterThrowing () {System. out. println ("method: afterThrowing"); try {int a = 10/0;} catch (ArithmeticException AE) {System. out. println ("arithmetic exception handled");} String s = null; System. out. println (s. substring (0, 3 ));}

As shown in the preceding program, a throwing attribute is specified when @ AfterThrowing annotation is used in the program. The value of this attribute is ex, this indicates that an object named ex can be used in the log of the enhancement method. This parameter indicates the exception object thrown by the target method. Run the test class and you can see the following results:

Note that if an exception has been processed within the program, Spring AOP will not handle the exception. Only when the target method throws an unprocessed exception, the exception will be passed to the notification method as the corresponding form parameter.Similar to AfterReturning, the parameter type of the correct method can be limited to a cut point that matches only the exception of the specified type-if the parameter type of the preceding handleException method is NullPointerException, if the target method only throws ArithmaticException, Spring AOP will not handle this exception. Of course, if the parameter type of handleException is Throwable, all exceptions are matched.

From the test results, it can be seen that although AfterThrowing can handle exceptions of the target method, it is different from catch: catch means that the exception is fully handled, if a new exception is not thrown in the catch Block, the method can end normally. AfterThrowing cannot completely handle the exception although it handles the exception, this exception will still be propagated to the upper-level caller (in this example, It is JVM, and the program will be terminated ).

5. Use After notification

Spring also provides an After notification, which has the same advantages as AfterReturning, but also has the following differences:

AfterReturning notification will be woven only after the target method is completed correctly

After notification will be woven into the target method no matter how it ends (correct or abnormal)

Because of this feature, After notification must be prepared to handle both normal and abnormal responses. This notification is usually used to release resources. Annotate a method with the @ After annotation to convert the method to the After notification. To use the @ After annotation, You need to specify a value attribute to specify the entry point of the notification. It can be an existing entry point or a start point expression.

Add AfterAdviceTest under the com. abc. advice package. This class defines an After notification:

@ Aspectpublic class AfterAdviceTest {@ After (value = "execution (* com. abc. servie. impl. *. afterAdvice *(..)) ") public void releaseResource () {System. out. println ("simulate releasing database connections ");}}

Add the following content to the AdviceManager class:

// The public void AfterAdvice () {System. out. println ("method: afterAdvice") will be matched by the releaseResource method of afterAdvice ");}

An After notification is defined above. No matter how the target method of the entry point ends, the notification will be woven. The test result is as follows:

6. Use Around und notification

@ Around annotation is used to mark the Around notification, which is approximately equal to the sum of Before notification and AfterReturning notification. The Around notification can be woven into the enhancement action Before the target method is executed, you can also attach the enhancement action after the target method.

Unlike @ Before and @ AfterReturning, @ Around can even decide when to execute the target method, how to execute it, or even completely stop the execution of the target method. @ Around: you can modify the parameter values of the target method or the return values of the target method.

@ Around is powerful, but usually needs to be used in a thread-safe environment. Therefore, if you use a common @ Before and @ AfterReturning, you can solve the problem, there is no need to use @ Around. If you need to share a certain data status before and after the target method is executed, you should consider using @ Around. In particular, you need to use notifications to prevent the target method from being executed, or you can only use @ Around to change the parameters of the target method and the returned values after execution.

As you can imagine, when @ Around is used, you also need to specify a value attribute, which is still used to specify the entry point. In addition, when defining an round notification, the first parameter of the method must be of the ProceedingJoinPoint type (that is, at least one parameter is included). In the notification method, the ProceedingJoinPoint proceed () is called () method to execute the target method -- this is the key to fully controlling the execution time of the target method and how to execute the method. If the proceed () method is not called in the notification method body, the target method is not executed.

When calling the proceed () method, you can also pass in an Object [] Object. The value in this array is passed in as the real parameter of the execution method. Therefore, we can use this parameter to modify the parameter value of the method.

Add the AroundAdviceTest under the com. abc. advice package. This class defines an und notification:

Package com. abc. advice; import org. aspectj. lang. proceedingJoinPoint; import org. aspectj. lang. annotation. around; import org. aspectj. lang. annotation. aspect; @ Aspectpublic class AroundAdviceTest {@ Around (value = "execution (* com. abc. service. *. around *(..)) ") public Object process (ProceedingJoinPoint point) throws Throwable {System. out. println ("enhanced processing before simulated execution of the target method: the transaction starts... "); // modify the target method parameter String [] params = new String [] {" param1 "}; // execute the target method, and save the returned Object returnValue = point after the target method is executed. proceed (params); System. out. println ("enhanced processing after Simulated execution of the target method: the transaction ends... "); // return the modified return value return" actual return value of the method: "+ returnValue +", which is the suffix of the returned value ";}}

The above defines an AroundAdviceTest section, which contains an und notification: process () method. The first line of code in this method is used to simulate the processing before calling the target method, the second row modifies the first parameter of the target method, and then calls the target method. It simulates the processing after calling the target method and modifies the return value. As mentioned above, through this process method, we can add notifications similar to @ Before and @ AfterReturning to determine when to execute the target method and modify the parameter values of the target method, you can also modify the return value of the target method. You can do whatever you want!

Add the following content to the AdviceManager class:

// The process method of AroundAdvice matches public String aroundAdvice (String param1) {System. out. println ("method: aroundAdvice"); return param1 ;}

Add a method call to com. abc. main. AOPTest to trigger the cut point:

String result = manager. aroundAdvice ("param1"); System. out. println ("Return Value:" + result );

Run the test class and the result is as follows:

Note that when the ProceedingJoinPoint proceed () method is called, the input Object [] parameter value will be used as the parameter of the target method, if the length of the array is different from the number of parameters of the target method, or the type of the array element does not match the parameter type of the target method, an exception occurs.

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.