In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/01 Report--
This article introduces the knowledge of "how to activate @ AspectJ support". Many people will encounter this dilemma in the operation of actual cases, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!
Aspect-oriented programming (AOP) complements object-oriented programming (OOP) by providing another way of thinking about program structure. The key unit of modularization in OOP is the class, while modularity is the aspect in AOP. Aspects enable modularization of concerns, such as transaction management, across multiple types and objects. (this concern is often referred to as "cross-domain" concern in the AOP literature.)
One of the key components of Spring is the AOP framework. Although the Spring IoC container does not rely on AOP (which means you don't need to use AOP if you don't want to use AOP), AOP complements Spring IoC and provides a very powerful middleware solution.
Spring AOP with AspectJ pointcut
Spring provides a simple and powerful way to write custom aspects using schema-based methods or @ AspectJ annotation styles. Both styles provide suggestions for fully typed and use the AspectJ pointcut language while still using Spring AOP for weaving.
This chapter discusses schema-based and @ AspectJ-based AOP support. Lower-level AOP support is discussed in the next chapter.
AOP is used in the Spring framework to:
Provide declarative enterprise services. The most important of these services is declarative transaction management.
Let users implement custom aspects and supplement their use of OOP with AOP.
If you are only interested in generic declarative services or other prepackaged declarative middleware services (such as pooling), you do not need to use Spring AOP directly, and you can skip most of this chapter.
5.1 AOP concept
Let's first define some major AOP concepts and terms. These terms are not specific to Spring. Unfortunately, the AOP terminology is not particularly intuitive. However, it will be even more confusing if you use Spring's own terminology.
Aspect: modularization of concerns involving multiple categories. Transaction management is a good example of crosscutting concerns in enterprise Java applications. In Spring AOP, aspects are achieved through the use of regular classes (schema-based methods) or regular classes annotated with @ Aspect annotations (@ AspectJ style).
Join point: a point in the execution of a program, such as the execution of a method or the handling of an exception. In Spring AOP, join points always represent the execution of methods.
Notification: the action taken by a section at a specific join point. Different types of notifications include: "around", "before" and "after" notifications. (notification types are discussed later. Many AOP frameworks, including Spring, model notifications as interceptors and maintain a series of interceptors around the join point.
Pointcut: indicates a matching join point. The notification is associated with a pointcut expression and runs at any join point that matches that pointcut (for example, executing a method with a specific name). The concept of join points matched by pointcut expressions is at the core of AOP, and by default, Spring uses the AspectJ pointcut expression language.
Introduction: declare other methods or fields on a type. Spring AOP allows you to introduce new interfaces (and corresponding implementations) to any notification object. For example, you can use the introduction to make Bean implement the IsModified interface to simplify caching. (the introduction is called inter-type declaration in the AspectJ community. )
Target object: an object notified by one or more aspects. Also known as "notification object". Because Spring AOP is implemented using a run-time proxy, this object is always a proxy object.
AOP proxy: an object created by the AOP framework that implements aspect conventions (notifying method execution, etc.). In Spring Framework, AOP agents are JDK dynamic agents or CGLIB agents.
Weaving: an object that links aspects to other application types or objects to create notifications. This can be done at compile time (for example, using the AspectJ compiler), at load time, or at run time. Like other pure Java AOP frameworks, Spring AOP performs weaving at run time.
Spring AOP includes the following types of notifications:
Advance notification: a notification that runs before the connection point but cannot prevent the execution flow from advancing to the connection point (unless it throws an exception).
Post notification: a notification to run after the connection point completes normally (for example, if a method returns without throwing an exception).
Post exception notification: the notification that will be executed if the method exits because an exception is thrown.
Final notification: regardless of how the connection point exits (normal or abnormal return), the notification will be executed.
Surround notifications: notifications around connection points, such as method calls. This is the most powerful notification. Surround notifications can perform custom behavior before and after a method call. It is also responsible for choosing whether to continue to the join point or to simplify the execution of the notification by returning its own return value or throwing an exception.
Surround notifications are the most common notifications. Because Spring AOP, like AspectJ, provides a variety of notification types, we recommend that you use the weakest suggestion type to implement the desired behavior. For example, if you only need to update the cache with the return value of the method, it is best to use a post notification rather than a surround notification, although the same thing can be done around the notification. Using the most specific notification types provides a simpler programming model and reduces the likelihood of errors. For example, you don't need to call the proceed () method on the JoinPoint used to surround notifications, so you won't fail.
All notification parameters are statically typed, so you can use the appropriate type (for example, the type of value returned from method execution) rather than the notification parameters of the object array.
The concept of join points matched by pointcuts is the key to AOP, which is different from the old technology that only provides interception. The pointcut makes the target of the notification independent of the object-oriented hierarchy. For example, you can apply surround notifications that provide declarative transaction management to a set of methods that span multiple objects, such as all business operations in the service layer.
5.2 AOP capabilities and goals
Spring AOP is implemented in pure Java. No special compilation process is required. Spring AOP does not need to control the hierarchy of class loaders, so it is suitable for use in Servlet containers or application servers.
Spring AOP currently supports only method execution join points (notification of method execution on Spring Bean). Although you can add support for field interception without breaking the core Spring AOP API, field interception is not implemented. If you need to notify fields to access and update connection points, consider using a language such as AspectJ.
Spring AOP's AOP approach is different from most other AOP frameworks. The goal is not to provide the most complete implementation of AOP (although Spring AOP is quite powerful). Instead, the goal is to provide tight integration between AOP implementations and Spring IoC to help solve common problems in enterprise applications.
So, for example, the AOP functionality of Spring Framework is often used in conjunction with the Spring IoC container. Configure aspects by using regular bean definition syntax (although this allows for powerful "automatic proxy" functionality). This is a key difference from other AOP implementations. It is not easy or efficient to do something with Spring AOP, such as notifying very fine-grained objects (usually domain objects). In this case, AspectJ is the best choice. However, our experience is that Spring AOP provides an excellent solution to most of the problems in enterprise Java applications that AOP can solve.
Spring AOP has never tried to compete with AspectJ to provide a comprehensive AOP solution. We believe that both agent-based frameworks (such as Spring AOP) and mature frameworks (such as AspectJ) are valuable and are complementary rather than competitive. Spring seamlessly integrates Spring AOP and IoC with AspectJ to support all the features of AOP in a consistent Spring-based application architecture. This integration does not affect Spring AOP API or AOP Alliance API. Spring AOP is still backward compatible. See the next chapter to discuss Spring AOP API.
One of the central purposes of the Spring framework is non-intrusiveness. This is the idea that you should not be forced to introduce framework-specific classes and interfaces into your business or domain model. However, in some places, Spring Framework does give you the option of introducing Spring Framework-specific dependencies into the code base. The reason for providing such options is that, in some cases, it may become easier to read or code specific features in this way. However, the Spring framework almost always gives you a choice: you are free to make informed decisions about which options are most appropriate for your particular use case or scenario.
One choice related to this chapter is which AOP framework (and which AOP style) to choose. You can choose AspectJ and or Spring AOP. You can also choose the @ AspectJ annotation style method or the Spring XML configuration style method. This chapter chooses to introduce the @ AspectJ style method first, which does not mean that Spring prefers the @ AspectJ annotation style to the Spring XML configuration style. (note: writing examples in AspectJ does not show that Spring prefers AspectJ annotation programming).
For a more complete discussion of the "context" of each style, see choosing the AOP declaration style to use.
5.3 AOP Agent
Spring AOP defaults to the standard JDK dynamic proxy for AOP proxies. This makes it possible to proxy any interface (or set of interfaces).
Spring AOP can also use the CGLIB proxy. This is required for proxy classes rather than interfaces. By default, CGLIB is used if the business object does not implement the interface. Because it is a good habit to program interfaces rather than classes, business classes typically implement one or more business interfaces. In some cases (which may be rare), you need to notify a method that is not declared on the interface, or you need to pass the proxy object to the method as a concrete type, you can force the use of CGLIB.
It is important to master the fact that Spring AOP is agent-based. See understanding the AOP Agent for a full understanding of the actual meaning of this implementation detail.
5.4 @ AspectJ support
AspectJ is a style that declares aspects as annotated regular Java classes. The @ AspectJ style was introduced by the AspectJ project in the AspectJ 5 release. Spring uses the library provided by AspectJ for pointcut resolution and matching to interpret the same annotations as AspectJ 5. However, the AOP runtime is still pure Spring AOP and does not depend on the AspectJ compiler or weaver.
The full AspectJ language can be used with the AspectJ compiler and weaver, and the use of AspectJ in Spring Applications is discussed.
5.4.1 activate @ AspectJ support
To use @ AspectJ facets in Spring configuration, you need to enable Spring support to configure Spring AOP based on @ AspectJ facets and automatically proxy Bean based on whether these facets are notified. By automatic proxy, we mean that if Spring determines one or more aspects to notify a bean, it automatically generates a proxy for that bean to intercept method calls and ensure that notifications are executed on demand.
You can use XML or Java-style configurations to enable @ AspectJ support. In either case, you need to make sure that AspectJ's Aspectjweaver.jar library is on the application's classpath (version 1.8 or later). The library is available in the lib directory of the AspectJ distribution or from the Maven Central repository.
Activate @ AspectJ through Java configuration
To enable @ AspectJ support through Java @ Configuration, add the @ EnableAspectJAutoProxy annotation, as shown in the following example:
@ Configuration@EnableAspectJAutoProxypublic class AppConfig {}
Activate @ AspectJ through XML configuration
Enable @ AspectJ support through a XML-based configuration, using elements, as shown in the following example:
Suppose you use the architectural support described in the XML Schema-based configuration. For information about how to import tags in the aop namespace, see AOP schema.
5.4.2 declare a section
When @ AspectJ support is enabled, Spring automatically detects any bean defined by classes that use @ AspectJ aspects (annotated with @ Aspect) in the application context and is used to configure Spring AOP. The next two examples show the minimum definition required for a less useful section.
The first of the two examples shows a regular bean definition in the context of an application that points to a bean class with @ Aspect annotations:
The second of these two examples shows the NotVeryUsefulAspect class definition, which is annotated with org.aspectj.lang.annotation.Aspect annotations
Package org.xyz;import org.aspectj.lang.annotation.Aspect;@Aspectpublic class NotVeryUsefulAspect {}
Aspects (classes annotated with @ Aspect) can have methods and fields, just like any other class. They can also include pointcuts, notifications, and incoming (inter-type) declarations.
Automatic detection of section by component scanning
You can register aspect classes as regular bean in Spring XML configuration, or you can automatically detect them through classpath scanning-just like any other bean managed by Spring. Note, however, that the @ Aspect annotation is not sufficient for automatic detection in the classpath. To do this, you need to add a separate @ Component annotation (or conditional custom stereotype annotation according to the rules of Spring's component scanner).
Provide notice to other aspects?
In Spring AOP, the section itself cannot be the target of notification for other aspects. The @ Aspect annotation on the class marks it as an aspect, so it is excluded from the automatic proxy.
5.4.3 declare the entry point
Pointcuts identify join points of interest, enabling us to control when notifications are executed. Spring AOP only supports join points for method execution in Spring Bean, so you can think of pointcuts as matching method execution on Spring Bean. The pointcut declaration consists of two parts: a signature containing the name and any parameters, and a pointcut expression that precisely determines the execution of the method we are interested in. In AOP's @ AspectJ annotation style, the general method definition provides a pointcut signature and uses the @ Pointcut annotation to indicate a pointcut expression (the method used as a pointcut signature must have a void return type). An example may help to clarify the difference between a pointcut signature and a pointcut expression. The following example defines a pointcut named anyOldTransfer that matches any execution named transfer method:
@ Pointcut ("execution (* transfer (..)") / / pointcut expression private void anyOldTransfer () {} / / pointcut method signature
The pointcut expression that forms the value of the @ Pointcut annotation is a regular AspectJ 5 pointcut expression.
Supported pointcut indicator
Spring AOP supports the following AspectJ pointcut indicator (PCD) used in pointcut expressions:
Execution: used to match the join point that the method executes. This is the main pointcut indicator to use when using Spring AOP.
Within: restricts the matching of join points within certain types (the execution of methods declared within matching types when using Spring AOP).
This: restricts matches to join points (execution of methods when using Spring AOP), where bean references (Spring AOP proxies) are instances of a given type.
Target: restricts matches to join points (execution of methods when using Spring AOP), where the target object (the agent's application object) is an instance of a given type.
Args: restricts matches to join points (execution of methods when using Spring AOP), where parameters are instances of a given type.
Target: restricts matches to join points (execution of methods when using Spring AOP), where the class that executes the object has comments of a given type.
Args: restricts matching join points (execution of methods when using Spring AOP), where the runtime type of the actual parameter passed has an annotation of the given type.
Within: restrict matching to join points in a type with a given annotation (when using Spring AOP, the execution of a method declared in the type with the given annotation).
Annotation: the topic that restricts the match point to the join point (the method being executed in Spring AOP) has the join point with the given annotation.
Other entry points
The full AspectJ pointcut language supports other pointcut indicators that Spring does not support: call, get, set, preinitialization,staticinitialization, initialization, handler, adviceexecution, withincode, cflow, cflowbelow, if, @ this and @ withincode. Using these pointcut indicators in pointcut expressions interpreted by Spring AOP causes IllegalArgumentException to be thrown.
The set of pointcut indicators supported by Spring AOP may be extended in future releases to support more AspectJ pointcut indicators.
Because Spring AOP restricts matching to only methods performing join points, the definition of pointcut indicators in the previous discussion is narrower than what can be found in the AspectJ programming guide. In addition, AspectJ itself has type-based semantics, and at the execution join point, both this and target refer to the same object: the object that executes the method. Spring AOP is an agent-based system that distinguishes between the proxy object itself (bound to this object) and the target object behind the proxy (bound to the target).
Because Spring's AOP framework is based on the nature of the agent, calls within the target object are not intercepted by definition. For JDK proxies, only public interface method calls on the proxy can be intercepted. With CGLIB, public and protected method calls on the proxy are intercepted (even methods that are visible in the package if necessary). However, common interactions through proxies should usually be designed through public signatures.
Note that the pointcut definition usually matches any interception method. If the pointcut is strictly set to public use only, even if there may be a non-public interaction through the proxy in the CGLIB proxy scenario, it needs to be defined accordingly.
If your interception needs to include method calls or even constructors in the target class, consider using Spring-driven native AspectJ weaving instead of Spring's proxy-based AOP framework. This constitutes AOP usage patterns with different characteristics, so be sure to be familiar with weaving before making a decision.
Spring AOP also supports other PCD named bean. With PCD, you can limit the matching of connection points to a specific named Spring Bean or a set of named Spring Bean (when using wildcards). Bean PCD has the following form:
Bean (idOrNameOfBean)
The idOrNameOfBean tag can be the name of any Spring bean. Limited wildcard support for using the * character is provided, so if you have established some naming conventions for Spring bean, you can write bean PCD expressions to select them. Like other pointcut indicators, bean PCD can be associated with & & (and), | (or), and! The negative operator is used together.
Bean PCD is supported only in Spring AOP, not in native AspectJ weaving. It is an Spring-specific extension of the standard PCD defined by AspectJ and therefore does not apply to the aspects declared in the @ Aspect model.
Bean PCD runs at the instance level (built on the concept of Spring bean names), not just at the type level (where weaving-based AOP is limited). Instance-based pointcut indicators are a special feature of Spring's agent-based AOP framework and are tightly integrated with Spring bean factories, so specific bean can be naturally and directly identified by name.
Combined pointcut expression
You can use & &, | | and! Combines pointcut expressions. You can also refer to pointcut expressions by name. The following example shows three pointcut expressions:
@ Pointcut ("execution (public * *)") private void anyPublicOperation () {} / / 1@Pointcut ("within (com.xyz.someapp.trading..*)") private void inTrading () {} / / 2@Pointcut ("anyPublicOperation () & & inTrading ()") private void tradingOperation () {} / / 3
If the method execution join point represents the execution of any public method, the anyPublicOperation matches.
If there is a method execution in the transaction module, the inTrading matches.
If the method executes on behalf of any public method in the transaction module, the tradingOperation matches.
The best practice is to build more complex pointcut expressions from smaller named components, as shown earlier. When referencing pointcuts by name, regular Java visibility rules are applied (you can see the same type of private pointcut, protected pointcut in the hierarchy, public pointcut anywhere, etc.). Visibility does not affect pointcut matching.
Share common pointcut definition
In enterprise applications, developers usually want to reference application modules and specific sets of operations from multiple aspects. We recommend defining a SystemArchitecture facet for this purpose to capture common pointcut expression intentions. Such a section is usually similar to the following example:
Package com.xyz.someapp;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;@Aspectpublic class SystemArchitecture {/ * * A join point is in the web layer if the method is defined * in a type in the com.xyz.someapp.web package or any sub-package * under that. * / @ Pointcut ("within (com.xyz.someapp.web..*)") public void inWebLayer () {} / * * A join point is in the service layer if the method is defined * in a type in the com.xyz.someapp.service package or any sub-package * under that. * / @ Pointcut ("within (com.xyz.someapp.service..*)") public void inServiceLayer () {} / * * A join point is in the data access layer if the method is defined * in a type in the com.xyz.someapp.dao package or any sub-package * under that. * / @ Pointcut ("within (com.xyz.someapp.dao..*)") public void inDataAccessLayer () {} / * * A business service is the execution of any method defined on a service * interface. This definition assumes that interfaces are placed in the * "service" package, and that implementation types are in sub-packages. * * If you group service interfaces by functional area (for example, * in packages com.xyz.someapp.abc.service and com.xyz.someapp.def.service) then * the pointcut expression "execution (* com.xyz.someapp..service.*.* (..)" * could be used instead. * * Alternatively, you can write the expression using the 'bean' * PCD, like so "bean (* Service)". (This assumes that you have * named your Spring service beans in a consistent fashion.) * / @ Pointcut ("execution (* com.xyz.someapp..service.*.* (..)") Public void businessService () {} / * * A data access operation is the execution of any method defined on a * dao interface. This definition assumes that interfaces are placed in the * "dao" package, and that implementation types are in sub-packages. * / @ Pointcut ("execution (* com.xyz.someapp.dao.*.* (..)") Public void dataAccessOperation () {}}
You can refer to the pointcut defined on this pointcut wherever you need a pointcut expression. For example, to make the service layer transactional, you can write the following:
The and elements are discussed in schema-based AOP support. Transaction elements are discussed in transaction management.
Example
Spring AOP users probably use the execution pointcut indicator most often. The format of the execution expression is as follows:
Execution (modifiers-pattern? Ret-type-pattern declaring-type-pattern?name-pattern (param-pattern) throws-pattern?)
Except for the return type pattern (ret-type-pattern in the previous code snippet), everything except the name pattern (name-pattern) and the parameter pattern (param-pattern) is optional. The return type pattern determines what the return type of the method must be to match the join point. Most commonly used as a return type mode. It matches any return type. The standard type name matches only if the method returns a given type. The name pattern matches the method name. You can use the wildcard character as all or part of the name pattern. If you specify the declaration type mode, add it after it. Add it to the name pattern component. The parameter pattern is a little more complex: () matches methods without parameters, while (..) Matches any number of parameters (zero or more). (*) the pattern matches the method that takes a parameter of any type. (*, String) matches the method that takes two parameters. The first can be of any type, while the second must be a string. For more information, see the language semantics section of the AspectJ programming guide.
The following example shows some common pointcut expressions:
Execution of any public method:
Execution (public * *)
Execution of any method whose name begins with set:
Execution (* set* (..))
Execution of any method defined by the AccountService interface:
Execution (* com.xyz.service.AccountService.* (..))
Execution of any method defined in the service package:
Execution (* com.xyz.service. *. * (..))
Execution of any method defined in the service package or one of its child packages:
Execution (* com.xyz.service. . *. * (..)
Any connection point in the service package (methods are executed only in Spring AOP):
Within (com.xyz.service.*)
Any connection point in the service package or one of its child packages (methods are executed only in Spring AOP):
Within (com.xyz.service..*)
The agent implements any connection point of the AccountService interface (methods are executed only in Spring AOP):
This (com.xyz.service.AccountService)
This is usually used in the form of bindings. For information about how to make the proxy object available in the notification body, see the "declaring notifications" section
The target object implements any connection point of the AccountService interface (methods are executed only in Spring AOP):
Target (com.xyz.service.AccountService)
Target is usually used in the form of bindings. For information about how to make the target object available in the body of the proposal, see the Declaration Notification section.
Any join point that takes a single parameter and the parameter passed at run time is Serializable (the method is executed only in Spring AOP):
Args (java.io.Serializable)
Args is usually used in the form of bindings. For information about how to make method parameters available in the notification body, see the "declaring notifications" section.
Note that the pointcut given in this example is different from execution (* (java.io.Serializable)). If the argument passed at run time is Serializable, the args version matches; if the method signature declares a parameter of type Serializable, the version match is performed.
The target object has any join point with the @ Transactional annotation (method execution only in Spring AOP):
@ target (org.springframework.transaction.annotation.Transactional)
You can also use @ target in the binding form. For information about how to make the annotation object available in the body of the suggestion, see the "declaration notification" section.
The declaration type of the target object has any join point of the @ Transactional annotation (method execution only in Spring AOP):
@ within (org.springframework.transaction.annotation.Transactional)
You can also use @ within in the binding form. For information about how to make the annotation object available in the notification body, see the "declaring notifications" section.
Any join point that executes a method with @ Transactional annotations (method execution only in Spring AOP):
@ annotation (org.springframework.transaction.annotation.Transactional)
You can also use @ annotation in the binding form. For information about how to make the annotation object available in the notification body, see the "declaring notifications" section.
Any join point that takes a single parameter (method execution only in Spring AOP), and the runtime type of the passed parameter has the @ Classified annotation:
@ args (com.xyz.security.Classified)
You can also use @ args in the binding form. See the "Declaration Notification" section on how to make the annotation objects in the notification object available.
Any connection point on the Spring bean named tradeService (the method is executed only in Spring AOP):
Bean (tradeService)
Any join point on the Spring Bean that has a name that matches the wildcard expression * Service (the method is executed only in Spring AOP):
Bean (* Service)
Write a good connection point
During compilation, AspectJ processes pointcuts to optimize matching performance. It is a time-consuming process to examine the code and determine whether each join point (static or dynamic) matches a given pointcut. (dynamic matching means that the match cannot be fully determined from the static analysis, and the code is tested to determine whether there is an actual match when the code is run.) When a pointcut declaration is first encountered, AspectJ rewrites it as the best form of the matching process. What does this mean? Basically, pointcuts are rewritten in DNF (disjunctive normal form) and the components of pointcuts are sorted so that the cheaper (least expensive) components are checked first. This means that you don't have to worry about understanding the performance of the various pointcut indicators and can provide them in any order in the pointcut declaration.
However, AspectJ can only use what is told. In order to get the best matching performance, you should consider what they are trying to achieve and minimize the matching search space in the definition. Existing indicators naturally fall into one of three categories: homogeneity, scope, and context:
The Kinded indicator selects specific types of connection points: execution, get, set, call, and handler.
The Scoping indicator selects a set of join points of interest (possibly of multiple types): within and withincode
The Contextual indicator matches (and optionally binds) by context: this, target, and @ annotation
Writing the right pointcut should include at least the first two types (Kinded and Scoping). You can include context indicators to match according to the connection point context, or you can bind that context for use in notifications. It is possible to provide only identifiers for Kinded or only identifiers for Contextual, but weaving performance (time and memory used) may be affected due to additional processing and analysis. Scoping specifiers match very quickly, and using them means that AspectJ can very quickly eliminate groups of join points that should not be processed further. A good entry point should include one as much as possible.
Reference code: com.liyong.ioccontainer.starter.AopIocContiner
5.4.4 Declaration Notification
The notification is associated with a pointcut expression and runs before, after, or around the execution of a method that matches the pointcut. A pointcut expression can be a simple reference to a named pointcut or a pointcut expression declared in the appropriate place.
Advance notice
You can use the @ Before annotation to declare advance notifications in a section:
Import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;@Aspectpublic class BeforeExample {@ Before ("com.xyz.myapp.SystemArchitecture.dataAccessOperation ()") public void doAccessCheck () {/ /...}}
If you use an in-place pointcut expression, you can rewrite the previous example as the following example:
Import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;@Aspectpublic class BeforeExample {@ Before ("execution (* com.xyz.myapp.dao.*.* (..)") Public void doAccessCheck () {/ /...}}
Return to notification
When the matching method returns normally, the return notification runs. You can use the @ AfterReturning annotation to declare:
Import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.AfterReturning;@Aspectpublic class AfterReturningExample {@ AfterReturning ("com.xyz.myapp.SystemArchitecture.dataAccessOperation ()") public void doAccessCheck () {/ /...}}
You can have multiple notification statements (and other members) in the same section. In these examples, we show only a single notification declaration and the effect of each of these notifications.
Sometimes you need to access the actual value returned in the notification body. You can bind the return value in the form of @ AfterReturning to get the access, as shown in the following example:
Import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.AfterReturning;@Aspectpublic class AfterReturningExample {@ AfterReturning (pointcut= "com.xyz.myapp.SystemArchitecture.dataAccessOperation ()", returning= "retVal") public void doAccessCheck (Object retVal) {/ /...}}
The name used in the return property must correspond to the parameter name in the advice method. When the method performs a return, the return value is passed to the notification method as the corresponding parameter value. Returning also restricts matching to only method execution that returns a value of the specified type (in this case Object, which matches any return value).
Note that when using post-return notification, it is not possible to return a completely different reference.
Exception post notification
Runs when the matching method exits by throwing an exception after the exception notification is thrown. You can declare using the @ AfterThrowing annotation, as shown in the following example:
Import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.AfterThrowing;@Aspectpublic class AfterThrowingExample {@ AfterThrowing ("com.xyz.myapp.SystemArchitecture.dataAccessOperation ()") public void doRecoveryActions () {/ /...}}
In general, you want the notification to run only when a given type of exception is thrown, and you usually need to access the exception thrown in the notification body. You can use the throwing attribute to restrict the match (if necessary) (otherwise, use Throwable as the exception type) and bind the thrown exception to the notification parameter. The following example shows how to do this:
Import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.AfterThrowing;@Aspectpublic class AfterThrowingExample {@ AfterThrowing (pointcut= "com.xyz.myapp.SystemArchitecture.dataAccessOperation ()", throwing= "ex") public void doRecoveryActions (DataAccessException ex) {/ /...}}
The name used in the throwing property must correspond to the parameter name in the notification method. When the exit method is executed by throwing an exception, the exception is passed to the notifying method as the corresponding parameter value. Throwing also restricts matching to methods of the specified type (in this case, DataAccessException).
Final notice
When the matching method exits, the notification (eventually) runs. Declare it by using the @ After annotation. You must then prepare notifications to handle normal and abnormal return conditions. It is usually used to release resources and similar purposes. The following example shows the use of the final notification:
Import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.After;@Aspectpublic class AfterFinallyExample {@ After ("com.xyz.myapp.SystemArchitecture.dataAccessOperation ()") public void doReleaseLock () {/ /...}}
Surround notification
The last type of notification is surround notification. The surround notification runs "around" during the execution of the matching method. It has the opportunity to perform work before and after method execution, and to determine when, how, and even whether the method is actually executed. Surround notifications are typically used if you need to share state before and after method execution in a thread-safe manner (for example, start and stop timers). Always use the least capable notification to meet your requirements (that is, do not surround the notification when the notification can advance the notification).
Declare the surround notification by using the @ Around annotation. The first parameter of the notification method must be of type ProceedingJoinPoint. In the body of the notification, calling proceed () on ProceedingJoinPoint causes the underlying (real execution method) method to execute. The proceed method can also be passed in Object []. The values in the array are used as parameters when the method is executed.
When called with Object [], the behavior of proceed is slightly different from the proceed notified by around compiled by the AspectJ compiler. For surround notifications written in the traditional AspectJ language, the number of parameters passed to proceed must match the number of parameters passed to the surround notification (rather than the number of parameters used by the underlying join point), and the given parameter location replaces the original value at the join point of the entity to which the value is bound (don't worry, if it doesn't make sense now). Spring takes a simpler approach and is better suited to its proxy-based, execution-only semantics. If you compile the @ AspectJ aspect written for Spring and use parameters in the AspectJ compiler and weaver for processing, you only need to be aware of this difference. There is a way to be 100% compatible between Spring AOP and AspectJ and is discussed in the following section on notification parameters.
The following example shows how to use surround notifications:
Import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.ProceedingJoinPoint;@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;}
The value returned around the notification is the return value seen by the caller of the method. For example, if a simple cache aspect has a value, it can return a value from the cache, and if not, call proceed (). Note that in the body that surrounds the notification, proceed may be called once, multiple times, or not at all. All of this is legal.
Notification parameter
Spring provides fully typed notifications, which means you can declare the required parameters in the notification signature (as we saw earlier in the return and throw examples) instead of using the Object [] array all the time. We will describe how to make parameters and other contextual values available to notify the principal later in this section. First, let's take a look at how to write a generic notification to understand how the notification is currently notified.
Get the current JoinPoint
Any notification method can declare a parameter of type org.aspectj.lang.JoinPoint as its first parameter. Note that the surround notification declares the ProceedingJoinPoint type as the first parameter, which is a subclass of JoinPoint. The JoinPoint interface provides many useful methods:
GetArgs (): returns method parameters.
GetThis (): returns the proxy object.
GetTarget (): returns the target object.
GetSignature (): returns a description of the method used by the notification.
ToString (): prints useful descriptions of all notification methods.
For more details, see javadoc.
Pass parameters to notification
We have seen how to bind returned values or outliers (after returning and after raising a notification). To make parameter values available to the notification body, you can use the binding form of args. If you use a parameter name instead of a type name in an args expression, the value of the corresponding parameter is passed as the parameter value when the notification is invoked. An example should make this more clear. Suppose you want to notify the execution of the DAO operation that takes the Account object as the first parameter, and you need to access the account in the notification body. You can write the following:
@ Before ("com.xyz.myapp.SystemArchitecture.dataAccessOperation () & & args (account,..)") public void validateAccount (Account account) {/ /...}
Args (account,..) of pointcut expression Part of it has two uses. First, it restricts matching to only those methods that take at least one parameter and whose parameters passed to that parameter are Account instances. Second, it makes the actual Account object available for notification through the account parameter.
Another way to write this is to declare a pointcut, provide the Account object value when it matches a join point, and then reference the named pointcut from the notification. As follows:
@ Pointcut ("com.xyz.myapp.SystemArchitecture.dataAccessOperation () & & args (account,..)") private void accountDataAccessOperation (Account account) {} @ Before ("accountDataAccessOperation (account)") public void validateAccount (Account account) {/ /.}
Proxy objects (this), target objects (target), and annotations (@ within,@target,@annotation and @ args) can all be bound in a similar manner. The next two examples show how to match the execution of a method that uses @ Auditable annotations and extract the audit code:
The first of these two examples shows the definition of the @ Auditable annotation:
Retention (RetentionPolicy.RUNTIME) @ Target (ElementType.METHOD) public @ interface Auditable {AuditCode value ();}
The second of these two examples shows a notification that matches the execution of the @ Auditable method:
@ Before ("com.xyz.lib.Pointcuts.anyPublicMethod () & & @ annotation (auditable)") public void audit (Auditable auditable) {AuditCode code = auditable.value (); / /.}
Notification parameters and generics
Spring AOP can handle generics used in class declarations and method parameters. Suppose you have the following generic types:
Public interface Sample {void sampleGenericMethod (T param); void sampleGenericCollectionMethod (Collection param);}
You can limit the interception of method types to certain parameter types by typing the advice parameter in the parameter type of the method you want to intercept:
@ Before ("execution (*.. Sample+.sampleGenericMethod (*)) & & args (param)") public void beforeSampleMethod (MyType param) {/ / Advice implementation}
This method does not apply to generic collections. Therefore, you cannot define pointcuts in the following ways:
@ Before ("execution (*.. Sample+.sampleGenericCollectionMethod (*)) & & args (param)") public void beforeSampleMethod (Collection param) {/ / Advice implementation}
In order to make this work effective, we will have to examine each element of the collection, which is unreasonable because we cannot decide what to do with null normally. To achieve a similar goal, you must type parameters into Collection and manually check the type of the element.
Determine the parameter name
The parameter binding in the notification call depends on the matching of the name used in the pointcut expression with the parameter name declared in the notification and pointcut method signature.
Parameter names cannot be obtained through Java reflection, so Spring AOP uses the following strategy to determine parameter names:
If the user has explicitly specified a parameter name, the specified parameter name is used. Both notifications and pointcut annotations have an optional argNames attribute that you can use to specify the parameter name of the annotated method. These parameter names are available at run time. The following example shows how to use the argNames property:
Before (value= "com.xyz.lib.Pointcuts.anyPublicMethod () & & target (bean) & & @ annotation (auditable)", argNames= "bean,auditable") public void audit (Object bean, Auditable auditable) {AuditCode code = auditable.value (); / /. Use code and bean}
If the first parameter is of type JoinPoint, ProceedingJoinPoint, or JoinPoint.StaticPart, you can ignore the name of the parameter from the value of the argNames property. For example, if you modify the previous notification to receive the connection point object, the argNames property does not need to include it:
Before (value= "com.xyz.lib.Pointcuts.anyPublicMethod () & & target (bean) & & @ annotation (auditable)", argNames= "bean,auditable") public void audit (JoinPoint jp, Object bean, Auditable auditable) {AuditCode code = auditable.value (); / /. Use code, bean, and jp}
The special handling given to the first parameter of the JoinPoint, ProceedingJoinPoint, and JoinPoint.StaticPart types is particularly convenient for notification instances that do not collect any other join point context. In this case, you can omit the argNames attribute. For example, the following notification does not need to declare the argNames attribute:
@ Before ("com.xyz.lib.Pointcuts.anyPublicMethod ()") public void audit (JoinPoint jp) {/ /. Use jp}
Using the 'argNames' property is a bit clumsy, so if the' argNames' property is not specified, Spring AOP looks for debugging information for the class and tries to determine the parameter name from the local variable table. This information exists as long as the class has been compiled with debug information (at least-g:vars). The consequences of compiling when this flag is enabled are: (1) your code is slightly easier to understand (reverse engineering), (2) the size of the class file is slightly larger (usually insignificant), and (3) the compiler does not apply the optimization to delete unused local variables. In other words, by enabling the flag, you should not encounter any difficulties.
If the AspectJ compiler (ajc) has compiled the @ AspectJ aspect even without debugging information, there is no need to add the argNames attribute because the compiler retains the required information.
If the code is compiled without necessary debugging information, Spring AOP will try to infer the pairing of binding variables to parameters (for example, if only one variable is bound in the pointcut expression and the advice method accepts only one parameter, the pairing is obvious). If the binding of the variable is ambiguous given the available information, an AmbiguousBindingException is thrown.
If all of the above policies fail, IllegalArgumentException is thrown.
Proceed parameter
As we mentioned earlier, we will describe how to write a proceed call with parameters that are always valid in Spring AOP and AspectJ. The solution is to ensure that the notification signature binds each method parameter sequentially. The following example shows how to do this:
Around ("execution (List find* (..)) & &" + "com.xyz.myapp.SystemArchitecture.inDataAccessLayer () & &" + "args (accountHolderNamePattern)") public Object preProcessQueryPattern (ProceedingJoinPoint pjp, String accountHolderNamePattern) throws Throwable {String newPattern = preProcess (accountHolderNamePattern); return pjp.proceed (new Object [] {newPattern});}
In many cases, this binding is done anyway (as shown in the example above).
Notification order
What happens when multiple notifications want to run on the same connection point? Spring AOP follows the same priority rules as AspectJ to determine the order in which notifications are executed. The notification with the highest priority runs first on entry (therefore, given two before notifications, the notification with the highest priority runs first). The notification with the highest priority runs last as it comes out of the connection point (therefore, given two after notifications, the notification with the highest priority comes second).
When two notifications defined in different aspects need to run on the same join point, the order of execution is undefined unless otherwise specified. You can control the order of execution by specifying a priority. By implementing the org.springframework.core.Ordered interface in the aspect class or annotating it with Order annotations, this can be done through the regular Spring method. Given two sections, the section that returns a lower value from Ordered.getValue () (or annotated value) has a higher priority
When two notifications defined in the same aspect need to be run on the same join point, the order is undefined (because the declaration order cannot be retrieved through the reflection of the java compiled class). Consider decomposing such notification methods into a notification method for each join point in each aspect class, or refactoring notification fragments into separate aspect classes that can be sorted at the aspect level.
5.4.5 introduction
The introduction (called inter-type declaration in AspectJ) enables declared objects that have been notified to implement a given interface and to provide an implementation of that interface on behalf of those objects.
You can use the @ DeclareParents annotation for introduction. This annotation is used to declare that the matching type has a new parent class (and therefore a name). For example, given an interface named UsageTracked and an implementation of that interface named DefaultUsageTracked, the following aspect declares that all implementers of the service interface also implement the UsageTracked interface (for example, exposing statistics through JMX):
Aspectpublic class UsageTracking {@ DeclareParents (value= "com.xzy.myapp.service.*+", defaultImpl=DefaultUsageTracked.class) public static UsageTracked mixin; @ Before ("com.xyz.myapp.SystemArchitecture.businessService () & & this (usageTracked)") public void recordUsage (UsageTracked usageTracked) {usageTracked.incrementUseCount ();}}
The interface to be implemented is determined by the type of annotated field. The value attribute of the @ DeclareParents annotation is a schema of type AspectJ. Any bean that matches the type implements the UsageTracked interface. Note that in the before notification in the previous example, the service bean can be used directly as the implementation of the UsageTracked interface. If you access bean programmatically, you should write the following:
UsageTracked usageTracked = (UsageTracked) context.getBean ("myService")
Reference code: com.liyong.ioccontainer.starter.AopDeclareParentsIocContiner
5.4.6 Section instantiation model
This is an advanced theme. If you are just starting to use AOP, you can safely skip it until later.
By default, there is an instance of each aspect in the application context. AspectJ calls this the singleton instantiation model. You can use the bean lifecycle to define aspects. Spring supports AspectJ's perthis and pertarget instantiation models (percflow,percflowbelow and pertypewithin are not currently supported).
You can declare the perthis section by specifying perthis in the @ Aspect annotation. Consider the following example:
@ Aspect ("perthis (com.xyz.myapp.SystemArchitecture.businessService ())") public class MyAspect {private int someState; @ Before (com.xyz.myapp.SystemArchitecture.businessService ()) public void recordServiceUsage () {/ /...}}
In the previous example, the purpose of the "perthis" clause is to create a facet instance for each unique service object that performs the business service (each join point that matches the pointcut expression is bound to the unique object of "this"). The aspect instance is created when the method is first called on the service object. When the service object is out of range, the section will be out of range. None of the notifications in the section instance are executed until the section instance is created. Once a section instance is created, the notification declared in it is executed at the matching join point, but only if the service object is associated with the section. For more information about each clause, see the AspectJ programming guide.
The pertarget instantiation model works exactly the same as perthis, but it creates a section instance for each unique target object at matching join points.
5.4.7 AOP example
Now that you know how all the components work, we can put them together to do something useful.
Sometimes the execution of a business service may fail due to concurrency problems (for example, deadlock failure). If you retry the operation, you are likely to succeed in the next attempt. For business services that are suitable for retry in this case (no idempotent operation that needs to be returned to the user to resolve the conflict), we want to retry the operation transparently to prevent the client from seeing the PessimisticLockingFailureException. This is a requirement that clearly spans multiple services in the service layer, so it is well suited to be implemented through aspects.
Because we want to retry the operation, we need to use surround notification so that proceed can be called multiple times. The following listing shows the implementation of the basic aspect:
@ Aspectpublic class ConcurrentOperationExecutor implements Ordered {private static final int DEFAULT_MAX_RETRIES = 2; private int maxRetries = DEFAULT_MAX_RETRIES; private int order = 1; public void setMaxRetries (int maxRetries) {this.maxRetries = maxRetries;} public int getOrder () {return this.order;} public void setOrder (int order) {this.order = order } @ Around ("com.xyz.myapp.SystemArchitecture.businessService ()") public Object doConcurrentOperation (ProceedingJoinPoint pjp) throws Throwable {int numAttempts = 0; PessimisticLockingFailureException lockFailureException; do {numAttempts++; try {return pjp.proceed ();} catch (PessimisticLockingFailureException ex) {lockFailureException = ex }} while (numAttempts
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.