Spring Aspect Oriented Programming

Source: Internet
Author: User
Tags naming convention

This article is a basic knowledge analysis of Spring AOP, which does not involve source code analysis, only includes explanations of important concepts in AOP, analysis, and the use of spring AOP.

Spring introduces a simpler yet powerful aspect-oriented programming approach based on XML and ASPECTJ annotations from version 2.0. Before delving into how to use spring for aspect-oriented programming, let's look at some of the important basic concepts in AOP, which are not unique to spring and are literally difficult to understand, but I'll try to illustrate them with examples and popular language.

First of all, what is AOP, what is the use of it, what does it do for our programmers, and I believe that this is the first few questions that all developers of AOP have ever wanted to know. We might use some examples (transactional or authorization authentication, etc.) to explain a little, usually, in one application we create different service classes for different business modules, and most of the time each service class contains save/ Remove, such as different business logic but the same application logic interface (here business logic represents different business requirements, and application logic to represent additions and deletions and other applications such as common logic). However, in most cases we need to have transactional control over these methods, such as opening a transaction before all Save/remove methods are executed, and then committing the transaction after the method executes. At this point, without the support of AOP, we might have to write a bunch of repetitive, no-excitement code for each method (of course we don't mention dynamic proxies here, but spring AOP is implemented by default using dynamic proxies). But with AOP we can avoid this kind of trouble, then what should I do?

In the first step, we need to define our transaction class, which contains the methods of enabling, committing, and so on, which we call a tangent plane (Aspect).

In the second step, the facets are defined, and we need to define the transactional behavior, which is the additional behavior we need to add for the current method, which we call (or enhance) (Advice).

In the third step, we need a definition to determine which methods will be notified (that is, what needs to be handled), and we will use this definition as a point of entry (Pointcut), and each of the processed methods we call a join point.

Through the above steps, we can get a general understanding of these basic concepts, facets, notifications, pointcuts, connection points. If you do not understand, you can understand that first we need to determine which (pointcut) methods need to be processed, then what additional code (notifications) are executed on those methods (connection points), and at what time the code executes (pre-notification ...). ), the final encapsulation notification, the class or interface of the pointcut is our facet). In addition, for notifications, we are usually divided into pre-notification, post-notification, surround notification, and so on, to determine the timing of the notification at the connection point execution is called, specifically we analyze below.

To illustrate, because spring AOP is implemented using the JDK dynamic Proxy and the Cglib proxy, spring AOP can only intercept the execution of the method, and if you need to intercept access or updates to the field, you need an AOP language like ASPECTJ. In addition, Spring can seamlessly integrate ioc,spring AOP and AspectJ AOP.

As mentioned above, spring AOP provides two programming methods based on ASPECTJ annotations and XML, but this article only analyzes how annotations are programmed.

The @aspectj annotation approach refers to the way in which AOP programming is done using Java annotations, which are introduced in the AspectJ project, and spring You can use the ASPECTJ library to interpret these annotations to complete the parsing and matching of pointcuts (@Pointcut), and none of this needs to depend on the ASPECTJ compiler and the facet braid.

In order to use @aspectj annotations, We need to import the Aspectjweaver.jar package and enable the beans automatic proxy, whether or not these beans are cut off by slices, in other words, the automatic proxy detects the beans that are intercepted by the slice, and then automatically generates agents for those beans to complete the enhancement of the corresponding method. We can enable automatic proxy configuration using XML or Java code.

<aop:aspectj-autoproxy/>

Java Way we don't do extra introductions.

Once the preparation is complete, we can then program the slices:

1, example

In an order system, and payment system, we need strict user authentication and logging functions, such as the user to place orders, browse orders, before payment, all need to determine whether the user is logged in, etc., and in the next order, pay the success usually need to log, or send notification, and these functions are relatively repetitive, We can regard it as a facet to be used wherever it is needed without repeat yourself. Now that the demand is set, we start coding.

Here are the contents of our applicationcontext.xml, we use annotations to configure the beans, and enable spring package automatic scanning, if this configuration, you can read my other articles about spring:

<context:component-scan base-package= "AOP"/>//package name on the AOP bar Easy <CONTEXT:ANNOTATION-CONFIG/><AOP: Aspectj-autoproxy/>

Here are our OrderService and Paymentservice interfaces and implementations:

Package Aop;//interfacespublic interface OrderService {public void Save ();p ublic void Read ();} Public interface Payservice {public void Save ();} Implementationsimport org.springframework.stereotype.Component; @Component ("OrderService") public class Orderserviceimpl implements OrderService {@Overridepublic void Save () {System.out.println ("Order saved.");} @Overridepublic void Read () {System.out.println ("order read.");}} @Component ("Payservice") public class Payserviceimpl implements Payservice {@Overridepublic void Save () { System.out.println ("Pay saved.");}

The service interface is defined and we need to define our facets below, which is the intercept rule, which is the tangent pointcut:

Import Org.aspectj.lang.annotation.pointcut;import org.springframework.stereotype.Component; @Componentpublic Class Pointcuts {@Pointcut ("Execution (* Aop.*.save ())") public void Notice () {} @Pointcut ("Execution (* aop.*.* ())") public void Securitycheck () {}}

The above defines two tangent point AOP. Pointcuts.notice () and AOP. Pointcuts.securitycheck (), specifying which methods require notice interception and Securitycheck interception, respectively. The next step is to define what additional actions are performed on the intercepted method, which is our notification.

Import Org.aspectj.lang.annotation.afterreturning;import Org.aspectj.lang.annotation.aspect;import Org.springframework.stereotype.Component, @Aspect @componentpublic class Noticeaspect {@AfterReturning (pointcut= " Aop. Pointcuts.notice () ") public void Notice () {System.out.println (" The Users have been noticed. ");}

This class has a @aspect annotation that indicates that the class is a facet, where the method defined has a @afterreturning method, which indicates that the corresponding method is a post-notification, and that it has a pointcut property that references the slice defined above to determine which methods are intercepted. OK, so a simple cut-off programming is done, we look at the startup method:

Import Org.springframework.context.applicationcontext;import Org.springframework.context.support.classpathxmlapplicationcontext;public class Main {public static void Main (String [] args) {ApplicationContext context = new Classpathxmlapplicationcontext ("/application.xml"); OrderService OrderService = (OrderService) context.getbean ("OrderService"); Orderservice.save ();//orderservice.read (); Payservice Payservice = (payservice) context.getbean ("Payservice");p Ayservice.save ();}}

The result of the final operation is:

Order saved. Users have been noticed.pay saved. Users have been noticed.

The above code can be said to be the simplest AOP, the following we will be in-depth analysis of the aspects of AOP.

2, Slice (@Aspect)

The facets in Spring AOP can be seen as a regular class that needs to be @aspect annotated, which can contain declarations such as slices, notifications, etc., in the example above, we declare the post notification in the slice. You can declare the slices, how to do it, how to look at your personal habits, and the structure of your system, and the business logic needs to be decided.

3, sliced (@Pointcut)

The purpose of slicing is to determine when the notification of our declaration is executed. The life of a slice consists of two parts: 1) A slice signature consisting of a name and any parameter, 2) a slice expression. In the annotation method in spring AOP, the signature of the slice is the signature of the regular method definition, as in the previous example

@Pointcut ("Execution (* Aop.*.save ())")//Slice expression public void notice () {}//slice signature

Note: The method that is signed as a slice must be a void return value.

Spring AOP currently supports only the slice identifiers defined in partial AspectJ, and here is the complete list of support:

Execution-The primary usage of the slice definition, which is used to match the execution of the method connection point. Within-restricts the matching of connection points to a particular type this-restricts the type of the AOP proxy to a specific type target-restricts the type of the target object to a particular type args-the parameter of the qualified connection point is certain type @target- A qualified target object is a specific type with an annotation @args-the parameter type that qualifies the connection point has a specific annotation @within-the match of the connection point is limited to a type with a specific annotation @annotation-the object that executes the connection point is limited to a particular type

The following are identifiers that spring AOP has not yet implemented call, get, set, preinitialization, staticinitialization, initialization, handler, adviceexecution, withincode, cflow, cflowbelow, if, @this , and @withincode If you unintentionally use these tiles that are not yet supported, spring throws illegalargumentexception.

As mentioned earlier, spring AOP is a proxy-based implementation, so we use target to represent the Proxied object (that is, the orderserviceimpl of the example above), and this represents the proxy object (that is, spring in the example above is to intercept objects that are automatically created by the proxy object. Detailed analysis to read articles about dynamic agents for Java)

In addition, Spring supports bean slices to limit the matching of connection points within the specified bean. Use the following:

Bean (Idornameofbean)

Where Idornameofbean can be the name or ID of any spring bean and supports the * wildcard character, so if your project follows a good naming convention, you can easily write powerful bean slices.

When we write slices again, we usually use a few tips:

A, slice expression supports percent-percent, | | And!.

B, a slice expression supports a reference to a slice signature.

C, we can use common slices for unified management (refer to the above example)

public class Pointcuts {@Pointcut ("Execution (public * * (..))") The public method is sliced publicly void publicoperation () {} @Pointcut ("Within" (Aop.service. *) "public void Notice () {} @Pointcut (" Publicoperation () && notice () ") public void Noticepublic () {}}

With these tips, we can combine a variety of complex slices. It is also important to note that when you reference a tile signature, you need to follow the visibility constraints of a regular Java method, as you can access the private slice definition in a type. The following is a list of possible enterprise development tiling organization scenarios provided by spring:

package com.xyz.someapp;import org.aspectj.lang.annotation.aspect;import  Org.aspectj.lang.annotation.Pointcut, @Aspectpublic  class SystemArchitecture {     //is used to match slices of the web layer, matching methods      @Pointcut ("Within (Com.xyz.someapp.web) in the classes defined in the web and its child packages. *) ")     public void inweblayer ()  {}    //ibid., Used to match the slice      @Pointcut of the service layer ("Within (com.xyz.someapp.service. *) ")     public void inservicelayer ()  {}    //to match the DAO layer      @Pointcut ("Within (Com.xyz.someapp.dao. *) ")     public void indataaccesslayer ()  {}    //the following slice expression , assuming that our package structure is     //com.aop.app.order.service...    // com.aop.app.pay.service...    //The slice matches the execution of all methods of all classes under these service packs     @ Pointcut ("Execution (* com.xyz.someapP.. Service.*.* (..)) ")     public void businessservice ()  {}    // Match execution      @Pointcut of all Methods under DAO package ("Execution (* com.xyz.someapp.dao.*.* (..))")     public void dataaccessoperation ()  {}}

This allows you to refer to these slice definitions anywhere.

Execution-expression

Execution is the most commonly used slice identifier, and it is necessary to parse the format of the slice expression:

Execution (Modifiers-pattern ret-type-pattern declaring-type-pattern? Name-pattern (Param-pattern) Throws-pattern?)

As can be seen in the above expression, except for the return value type (Ret-type-pattern), first name (Name-pattern), parameter (Param-pattern), the other parts are optional. Where Ret-type-pattern determines the return value of the connection point, in most cases we use the * wildcard class to match all the return values. Name-pattern is used to match the method name, and we can use * as the whole or part of the method name.

For Param-pattern: () matches a method with no parameters, (..) A method that matches any number of parameters, (*) matches a method with an arbitrary parameter, (*, String) a method that matches two parameters, the first parameter is any type, and the second argument is a String type. Here are some common slice expressions:

Execution (Public * * (..)) Execution (* set* (..)) Execution (* com.xyz.service.accountservice.* (..)) Execution (* com.xyz.service.*.* (..)) Execution (* com.xyz.service). *.*(..)) Within (com.xyz.service.*) within (Com.xyz.service. *) This (com.xyz.service.AccountService) target (com.xyz.service.AccountService) args (java.io.Serializable) @target ( org.springframework.transaction.annotation.Transactional) @within ( org.springframework.transaction.annotation.Transactional) Bean (*service)

We do not analyze each other, I believe you can understand the meaning of these expressions.

4, notice (@Advice)

Understand the slices, let's get back to the notice. Typically, notifications are used in conjunction with slices and are executed before and after the method that matches the slice. The slices here can be either simple references to other slices (through a slice signature) or a slice expression.

As mentioned above, spring supports pre-notifications, surround notifications, afterreturning notifications, after notifications, exception-throwing notifications, which we'll describe individually.

4,1 Pre-notification (@Before)
@Aspectpublic class beforeadvice{@Before ("AOP.    Pointcuts.notice () ")//reference to another pointcut definition.    public void before () {//...} @Before ("Execution (* AOP). Orderservice.* ()) "public void Before1 () {//...}}

Both of the preceding notification definitions are feasible, and the before and before1 two methods are executed before the execution of the matching connection point.

4,2 afterreturning Notice
 @Aspectpublic  class afterreturningexample  {         @AfterReturning (" Com.xyz.myapp.SystemArchitecture.dataAccessOperation () ")     public void  Doaccesscheck ()  {                 // ...    }     @AfterReturning (         pointcut= "Com.xyz.myapp.SystemArchitecture.dataAccessOperation ()",         returning= "RetVal")     public void  Doaccesscheck (Object retval)  {                 // ...    }} 

The above is the two instance of the Afterreturning notification, where in the second instance we can access the results returned after the connection point method executes by using the returning property in the @afterreturning annotation.

4,3 afterthrowing Notice
 @Aspectpublic  class afterthrowingexample  {         @AfterThrowing (" Com.xyz.myapp.SystemArchitecture.dataAccessOperation () ")     public void  Dorecoveryactions ()  {                 // ...    }     @AfterThrowing (         pointcut= "Com.xyz.myapp.SystemArchitecture.dataAccessOperation ()",         throwing= "ex")     public void  Dorecoveryactions (Dataaccessexception ex)  {                 // ...    }} 

The afterthrowing notification executes after an exception is thrown in the matching connection point method, and you can capture the exception instance thrown in the connection point as in the second instance.

bis after (finally) Advice
@Aspectpublic class Afterfinallyexample {@After ("com.xyz.myapp.SystemArchitecture.dataAccessOperation ()") Publi c void Doreleaselock () {//...}}

After notifications are executed regardless of the execution result of the connection point method.

4,5 Around Advice

The surround notification, as its name implies, is executed before and after the connection point, and can determine whether the connection point is executed, and usually surround notifications are used in scenarios where the data needs to be shared before and after the connection point is executed. But spring suggests not to use around notifications blindly, but rather to use the simplest type of notification that meets your needs. such as before, afterreturning and so on.

The AROUND notification is declared through the @advice annotation, and the first parameter of the notification method must be proceedingjoinpoint. The instance's proceed () is then called in the method body to invoke the connection point method, and proceed () can also accept the object[] parameter, where each element acts as a parameter to the connection point method.

@Aspectpublic class Aroundexample {@Around ("Com.xyz.myapp.SystemArchitecture.businessService ()") Public Object Dobasicprofiling (Proceedingjoinpoint pjp) throws Throwable {//start stopwatch Object retVal = PJP.                Proceed ();    Stop stopwatch return retVal; }}
4,6 passing parameters for notifications

As mentioned earlier in the Afterreturning notification and afterthrowing notifications can be accessed through the parameters of the return value or exception instance, but sometimes we may need to in the notification method to access the connection point method variables, such as we need to intercept a method containing the user parameter , and you want to manipulate the user instance in the notification, then we can do this:

@Before ("com.xyz.myapp.SystemArchitecture.dataAccessOperation () && args (user,..)") public void validate (user user) {//...} or @pointcut ("com.xyz.myapp.SystemArchitecture.dataAccessOperation () && args (user,..)") private void accountdataaccessoperation (user user) {} @Before ("Accountdataaccessoperation (user)") public void Validate (User user) {    // ...}

Args (user, ...) is part of the slice expression, which defines that the connection point should have at least one parameter and should be of type user, and it can make the user instance available as a parameter to the notification method.


This is basically the end of the article, Spring AOP Common concepts are also basic analysis, of course, there are many not mentioned, but which is beyond the positioning of this article, and the above should also be able to deal with the daily development of most of the needs of the work.

Welcome to discuss, shoot bricks


Spring Aspect Oriented Programming

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.