Spring AOP is built on a dynamic agent basis, so spring's support for AOP is limited to method interception.
By wrapping facets in the proxy class, spring weaves the slices into spring-managed beans at run time. as shown in 4.3, the proxy class encapsulates the target class and intercepts calls to the notified method and forwards the call to the true target bean. When the agent intercepts a method call, the tangent logic is executed before the target bean method is called. Spring does not create a proxy object until the bean that needs to be proxied is applied. If you are using ApplicationContext, spring will create the Proxied object when ApplicationContext loads all the beans from the beanfactory. Because the spring runtime creates a proxy object, we do not need a special compiler to weave into the facets of spring AOP.
Figure 4.3 Spring's facets are implemented by the proxy class that wraps the target object. The proxy class handles the invocation of the method, executes additional facet logic, and invokes the target method
Spring uses ASPECTJ's pointcut expression language to define spring facets
ASPECTJ indicator |
Describe |
Arg () |
Limit the connection point matching parameter to the execution method of the specified type |
@args () |
To restrict the execution of connection point matching parameters that are annotated by the specified annotations |
Execution () |
To match is the execution method of the connection point |
This () |
Restrict connection points matching the bean reference for the AOP agent to a class of the specified type |
Target |
Restrict connection points to a class of the specified type for the target object |
@target () |
Restrict connection points to match specific execution objects that correspond to classes that have annotations of the specified type |
Within () |
Restricting connection points to match a specified type |
@within () |
Restricts the connection point to match the type that is indicated by the specified annotation (when using spring AOP, the method is defined in the class labeled by the specified annotation) |
@annotation |
Qualifying a connection point with the specified annotations |
When you try to use ASPECTJ other indicators in spring, the illegalargument-exception exception is thrown.
When we look at these spring-supported indicators as shown above, be aware that only the execution indicator is actually performing the match, while the other indicators are used to limit the match. This means that the execution indicator is the most important indicator we use when writing a pointcut definition. Based on this, we use other indicators to limit the tangent points that are matched.
1. Write the tangency point:
Package Concert; Public Interface Performance { void perform ();}
Performance can represent any type of live performance, such as a stage play, movie, or concert. Let's say we want to write a notification that performance's perform () method triggers. Figure 4.4 shows a pointcut expression that sets the call to trigger a notification when the perform () method executes.
We use the execution () indicator to select the performance perform () method. The method expression begins with the "*" sign, indicating that we do not care about the type of the return value of the method. We then specify the fully qualified class name and the method name. For a list of method parameters, we use two dots (.. ) indicates that the tangent point is to select any perform () method, regardless of the method's entry parameter.
Now suppose we need to configure the pointcut to match only the concert package. In this scenario, you can use the within () indicator to limit the match, as shown in 4.5.
Note that we use the "&&" operator to connect the execution () and within () indicators together to form a relationship (and) (the tangent must match all the indicators). Similarly, we can use the "| | |" operator to identify or (or) the relationship, and use "!" operator to identify a non-(not) operation.
Because "&" has a special meaning in XML, we can use and instead of "&&" when describing pointcuts in spring's XML configuration. Similarly, or and not can be used instead of the ' | | ' and "!".
1.1 Selecting the Bean in the tangent point
In addition to the indicators listed in Table 4.1, Spring introduces a new bean () indicator that allows us to identify beans using the bean's ID in a pointcut expression. The Bean () uses the bean ID or bean name as a parameter to restrict the pointcut to match only a particular bean.
For example, consider the following tangency: Here we want to apply the notification when the perform () method of the performance is executed, but the ID of the qualified bean is Woodstock.
Execution (* concert. Performance.perform. ()) and Bean ('Woodstock')
In some scenarios, it might make sense to qualify a pointcut for a specified bean, but we can also use non-action to apply notifications to beans other than a specific ID: In this scenario, the notifications for the slices are woven into all the beans with the ID Woodstock
Execution (* concert. Performance.perform. ()) and!bean ('Woodstock')
Now that we've covered the basics of writing pointcuts, let's take a look at how to write notifications and use them to declare slices.
2. Create a slice using annotations:
If there is no audience for a show, it cannot be called a performance. Right? From the point of view of performance, the audience is very important, but to the function of the performance itself, it is not the core, this is a separate focus. Therefore, it is wiser to define an audience as a facet and apply it to a performance.
If there is no audience for a show, it cannot be called a performance. Right? From the show.
Perspective, the audience is very important, but to the function of the performance itself, it is not
Is the core, which is a separate concern. Therefore, the audience is defined as a slice and
It is wiser to apply it to the show.
Audience class: Viewing the facets of a performance
PackageConcert;Importorg.aspectj.lang.annotation.AfterReturning;Importorg.aspectj.lang.annotation.AfterThrowing;ImportOrg.aspectj.lang.annotation.Aspect;ImportOrg.aspectj.lang.annotation.Before; @Aspect Public classAudience {@Before ("Execution (* * concert. Performance.perform. ())") Public voidSilencecellphones () {//before the showSYSTEM.OUT.PRINTLN ("Silencing cell phones"); } @Before ("Execution (* * concert. Performance.perform. ())") Public voidTakeseats () {//before the showSystem.out.println ("Taking seats"); } @AfterReturning ("Execution (* * concert. Performance.perform. ())") Public voidApplause () {//after the showSystem.out.println ("Clap clap clap!!!"); } @AfterThrowing ("Execution (* * concert. Performance.perform. ())") Public voidDemandrefund () {//after the showSystem.out.println ("demanding a refund"); }}
The audience class is annotated with @aspectj annotations. This note indicates that audience is not just a pojo, but a facet. The methods in the audience class use annotations to define the specific behavior of the facets.
Audience has four ways to define what an audience might do when they watch a performance. Before the show, the audience is seated (takeseats) and the phone is muted (silencecellphones ()). If the show is wonderful, the audience should applaud (applause ()). However, if the performance does not meet the expectations of the audience, the audience will request a refund (Demandrefund ()).
As you can see, these methods use notification annotations to indicate when they should be called. ASPECTJ provides five annotations to define a notification, as shown in the table.
Annotations |
Notification |
@After |
The notification method invokes the target method after it returns or throws an exception. |
@AfterReturning |
The notification method is called after the target method returns |
@AfterThrowing |
The notification method invokes the target method after it throws an exception. |
@Around |
The notification method encapsulates the target method. |
@Before |
The notification method executes before the target method call |
Audience uses three of the first five annotations. Both the Takeseats () and the Silence cellphones () methods use @before annotations to indicate that they should be called before the show begins. The applause () method uses the @afterreturning annotation, which is called after a successful return of the show. The Demandrefund () method adds a @afterthrowing annotation, which indicates that it executes after an exception is thrown.
You may have noticed that all of these annotations are given a pointcut expression as its value, and the tangent expressions of the four methods are the same. In fact, they can be set to different pointcut expressions, but here, this pointcut expression will satisfy the requirements of all notification methods. Let's take a closer look at this. The pointcut expression that is set to the notification annotation, we find it fires when the performance perform () method executes.
The same tangent-point expression we repeated four times, which is really not a glorious thing. This repetition makes people feel something is wrong. This is a good scenario if we define this tangent once and then reference it every time we need it. , &NB Sp , &NB Sp , &NB Sp , &NB Sp , &NB Sp , fortunately, we can To do this: @Pointcut annotations in a good way, we can do this: @Pointcut annotations define a reusable pointcut within a @aspectj facet.    The new audience, now it uses the @pointcut.
Package Concert;Importorg.aspectj.lang.annotation.AfterReturning;Importorg.aspectj.lang.annotation.AfterThrowing;ImportOrg.aspectj.lang.annotation.Aspect;ImportOrg.aspectj.lang.annotation.Before;Importorg.aspectj.lang.annotation.Pointcut; @Aspect Public classAudience {@Pointcut ("Execution (* * concert. Performance.perform. (..))") Public voidperformace () {} @Before ("Performace ()") Public voidSilencecellphones () {//before the showSYSTEM.OUT.PRINTLN ("Silencing cell phones"); } @Before ("Performace ()") Public voidTakeseats () {//before the showSystem.out.println ("Taking seats"); } @AfterReturning ("Performace ()") Public voidApplause () {//after the showSystem.out.println ("Clap clap clap!!!"); } @AfterThrowing ("Performace ()") Public voidDemandrefund () {//after the showSystem.out.println ("demanding a refund"); }}
In audience, the performance () method uses the @pointcut annotation. The value set for the @pointcut annotation is a pointcut expression, as it was previously set on the notification annotations. By adding @pointcut annotations on the performance () method, we actually extend the pointcut expression language so that you can use performance () in any pointcut expression, and if not, you need to use that longer pointcut expression in these places. We now replace the long expression in all notification annotations with performance (). The actual content of the performance () method is not important, where it should actually be empty. In fact, the method itself is only an identity, for @pointcut annotations attached. It is important to note that the audience class is still a pojo except for annotations and performance () methods that do not actually operate. We are able to invoke its method as it does with other Java classes, and its methods are independent of unit testing, which makes no difference from other Java classes. Audience is just a Java class, except that it uses annotations to indicate that it will be used as a tangent.
Like other Java classes, it can be assembled as a bean in spring:
@Bean Public Audience Audience () { returnnew audience ();}
If you use Javaconfig, you can enable automatic proxy functionality at the class level of the configuration class by using @enableaspectjautoproxy annotations. If you use XML, then you need to use the <aop:aspectj-autoproxy> element in the Springaop namespace.
Whether you're using Javaconfig or XML,ASPECTJ, automatic proxies Create a proxy for the bean that uses @aspect annotations, which surrounds the bean that matches all tangent points of that slice. In this case, a proxy will be created for Concertbean, and the notification method in the audience class will be executed before and after the perform () call.
What we need to keep in mind is that spring's ASPECTJ automatic proxy uses only @aspectj as a guide to creating slices, and the facets are still agent-based. In essence, it remains a spring-based proxy facet. This is important because it means that although @aspectj annotations are used, we are still limited to the invocation of proxy methods. If you want to take advantage of all the capabilities of ASPECTJ, we must use ASPECTJ at runtime and do not rely on spring to create a proxy-based slice. So far, our facets have been defined with different notification methods to implement both pre-and post-notification. Another kind of notification: Surround notification (around advice). Surround notifications are different from other types of notifications, so it's worth taking some time to describe how to write them.
To create a surround notification:
Surround notification is the most powerful type of notification. It allows you to write the logic that will be notified of the target method is completely wrapped up. In fact, it's like writing both a pre-notification and a post-notification in a notification method. To illustrate the surround notification, we rewrite audience facets. This time, we use a surround notification instead of several different pre-and post-notification notifications.
PackageConcert;ImportOrg.aspectj.lang.ProceedingJoinPoint;ImportOrg.aspectj.lang.annotation.Around;ImportOrg.aspectj.lang.annotation.Aspect;Importorg.aspectj.lang.annotation.Pointcut; @Aspect Public classAudience {@Pointcut ("Execution (* * concert. Performance.perform. (..))") Public voidperformace () {} @Around ("Performace ()") Public voidWatchperformace (proceedingjoinpoint JP) {Try{System.out.println ("Silencing cell Phones"); System.out.println ("Taking seats"); Jp.proceed (); System.out.println ("Clap clap Clap!!!"); } Catch(Throwable e) {System.out.println ("Demanding a refund"); } }}
Here, @Around annotations indicate that the Watchperformance () method will be the wrapping notification for the performance () tangent point. In this notice, the audience will be muted and seated before the performance, and will applaud after the show. As before, if the show fails, the audience will ask for a refund.
As you can see, the effect of this notification is the same as the previous pre-notification and post-notification. However, they are now in the same method, not as scattered in four different notification methods as before.
The first thing you notice about this new notification method is that it accepts proceedingjoinpoint as a parameter. This object is necessary because you want to invoke the method that is notified in the notification. You can do anything in the notification method, and when you want to give control to the method being notified, it needs to call Proceedingjoinpoint's proceed () method.
It is important to note that you should not forget to call the proceed () method. If this method is not tuned, then your notification will actually block the call to the method being notified. It is possible that this is the effect you want, but more of the situation is that you want to execute the notification method at a certain point.
Interestingly, you can block access to the notified method by not calling the proceed () method, similar to which you can make multiple calls to the notification. One scenario to do this is to implement the retry logic, which is to repeat the attempt after the notified method fails.
------The above content is extracted to "spring combat", mainly used for later browsing. Thanks for viewing, mutual encouragement
Concert
Spring AOP Learning Grooming (Spring in action) (i): Spring AOP