Spring By example -- aop
Spring AOP essentials
1. ProxyFactoryBean is used for declaring AOP
2. ProxyFactory is for programming AOP
3. AspectJFactoryBean is for AspectJ integration
4. For interface, JDK proxy is used
5. For class, CGLib is used
6. Ref InvocationHandler
Defining AOP terminology
ADVICE
In AOP terms, the job of an aspect is called advice.
Spring aspects can work with five kinds of advice:
Before—The advice functionality takes place before the advised method is invoked.
After—The advice functionality takes place after the advised method completes, regardless of the outcome.
After-returning—The advice functionality takes place after the advised method successfully completes.
After-throwing—The advice functionality takes place after the advised method throws an exception.
Around—The advice wraps the advised method, providing some functionality before and after the advised method is invoked.
JOIN POINTS
A join point is a point in the execution of the application where an aspect can be plugged in. This point could
be a method being called, an exception being thrown, or even a field being modified.
These are the points where your aspect’s code can be inserted into the normal flow of
your application to add new behavior.
POINTCUTS
Pointcuts help narrow down the join points advised by an aspect.
If advice defines the what and when of aspects, then pointcuts define the where. A pointcut definition matches one or more join points at which advice should be woven.
ASPECTS
An aspect is the merger of advice and pointcuts. Taken together, advice and point-cuts define everything there is to know about an aspect—what it does and where and when it does it.
INTRODUCTIONS
An introduction allows you to add new methods or attributes to existing classesv
WEAVING
Weaving is the process of applying aspects to a target object to create a new proxied object. The aspects are woven into the target object at the specified join points. The weaving can take place at several points in the target object’s lifetime:
Compile time—Aspects are woven in when the target class is compiled. This requires a special compiler. AspectJ’s weaving compiler weaves aspects this way.
Classload time—Aspects are woven in when the target class is loaded into the
JVM. This requires a special ClassLoader that enhances that target class’s byte-code before the class is introduced into the application. AspectJ 5’s load-time weaving (LTW) support weaves aspects in this way.
Runtime—Aspects are woven in sometime during the execution of the application. Typically, an AOP container will dynamically generate a proxy object that will delegate to the target object while weaving in the aspects. This is how Spring AOP aspects are woven.
Spring’s AOP support
SPRING ADVICE IS WRITTEN IN JAVA
SPRING ADVISES OBJECTS AT RUNTIME
SPRING ONLY SUPPORTS METHOD JOIN POINTS
Selecting join points with pointcuts
In Spring AOP, pointcuts are defined using AspectJ’s pointcut expression language.
Spring leverages AspectJ’s pointcut expression language for defining Spring aspects.
args() Limits join point matches to the execution of methods whose arguments are instances of the given types
@args() Limits join point matches to the execution of methods whose arguments are annotated with the given annotation types
execution() Matches join points that are method executions
this() Limits join point matches to those where the bean reference of the AOP proxy is of a given type
target() Limits join point matches to those where the target object is of a given type
@target() Limits matching to join points where the class of the executing object has an annotation of the given type
within() Limits matching to join points within certain types
@within() Limits matching to join points within types that have the given annotation (the execution of methods declared in types with the given annotation when using Spring AOP)
@annotation Limits join point matches to those where the subject of the join point has the
given annotation
Writing pointcuts
Selecting the Instrument’s play() method with an AspectJ pointcut expression
execution(*com.springinaction.springidol.Instrument.play()) and bean(eddie)
execution(*com.springinaction.springidol.Instrument.play()) and !bean(eddie)
Declaring aspects in XML
Spring’s AOP configuration elements simplify declaration of POJO-based aspects.
<aop:advisor> Defines an AOP advisor.
<aop:after> Defines an AOP after advice (regardless of whether the advised method returns successfully).
<aop:after-returning> Defines an AOP after-returning advice.
<aop:after-throwing> Defines an AOP after-throwing advice.
<aop:around> Defines an AOP around advice.
<aop:aspect> Defines an aspect.
<aop:aspectj-autoproxy> Enables annotation-driven aspects using @AspectJ.
<aop:before> Defines an AOP before advice.
<aop:config> The top-level AOP element. Most <aop:*> elements must be contained within <aop:config>.
<aop:declare-parents> Introduces additional interfaces to advised objects that are transparently implemented.
<aop:pointcut> Defines a pointcut.
public classAudience{
public voidtakeSeats(){
System.out.println("Theaudienceistakingtheirseats.");
}
public voidturnOffCellPhones(){
System.out.println("Theaudienceisturningofftheircellphones");
}
public voidapplaud(){
System.out.println("CLAPCLAPCLAPCLAPCLAP");
}
public voiddemandRefund(){
System.out.println("Boo!Wewantourmoneyback!");
}
}
<bean id="audience" class="com.springinaction.springidol.Audience"/>
<aop:config> <aop:aspect ref="audience"> <aop:before pointcut= "execution(* com.springinaction.springidol.Performer.perform(..))" method="takeSeats"/> <aop:before pointcut= "execution(* com.springinaction.springidol.Performer.perform(..))" method="turnOffCellPhones"/> <aop:after-returning pointcut= "execution(* com.springinaction.springidol.Performer.perform(..))" method="applaud"/> <aop:after-throwing pointcut= "execution(* com.springinaction.springidol.Performer.perform(..))" method="demandRefund"/> </aop:aspect> </aop:config>
Defining a named pointcut to eliminate redundant pointcut definitions
<aop:config> <aop:aspect ref="audience"> <aop:point cutid="performance"expression= "execution(* com.springinaction.springidol.Performer.perform(..))" /> <aop:before pointcut-ref="performance" method="takeSeats" /> <aop:before pointcut-ref="performance" method="turnOffCellPhones"/> <aop:after-returning pointcut-ref="performance" method="applaud" /> <aop:after-throwing pointcut-ref="performance" method="demandRefund" /> </aop:aspect> </aop:config>
Declaring around advice
public voidwatchPerformance(ProceedingJoinPointjoinpoint){
try {
System.out.println("Theaudienceistakingtheirseats.");
System.out.println("Theaudienceisturningofftheircellphones");
longstart=System.currentTimeMillis();
joinpoint.proceed();
longend=System.currentTimeMillis(); System.out.println("CLAPCLAPCLAPCLAPCLAP");
System.out.println("Theperformancetook"+(end-start)
+ "milliseconds.");
} catch(Throwablet){
System.out.println("Boo!Wewantourmoneyback!");
}
}
<aop:config> <aop:aspectref="audience"> <aop:pointcutid="performance2"expression= "execution(* com.springinaction.springidol.Performer.perform(..))" /> <aop:around pointcut-ref="performance2" method="watchPerformance()"/> </aop:aspect> </aop:config>
Passing parameters to advice
package com.springinaction.springidol;
public interface MindReader{
void interceptThoughts(Stringthoughts);
String getThoughts();
}
package com.springinaction.springidol;
public class Magician implements MindReader{
privateStringthoughts;
public voidinterceptThoughts(Stringthoughts){
System.out.println("Interceptingvolunteer'sthoughts");
this.thoughts=thoughts;
}
public StringgetThoughts(){
returnthoughts;
}
}
package com.springinaction.springidol;
public interface Thinker{
void thinkOfSomething(Stringthoughts);
}
package com.springinaction.springidol;
public class Volunteer implements Thinker{
privateStringthoughts;
public voidthinkOfSomething(Stringthoughts){
this.thoughts=thoughts;
}
public StringgetThoughts(){
returnthoughts;
}
}
<aop:config> <aop:aspect ref="magician"> <aop:pointcut id="thinking" expression="execution(* com.springinaction.springidol.Thinker.thinkOfSomething(String)) and args(thoughts)"/> <aop:before pointcut-ref="thinking" method="interceptThoughts" arg-names="thoughts" /> </aop:aspect> </aop:config>
@Test
public voidmagicianShouldReadVolunteersMind(){
volunteer.thinkOfSomething("QueenofHearts");
assertEquals("QueenofHearts",magician.getThoughts());
}
Introducing new functionality with aspects
Annotating aspects
A key feature introduced in AspectJ 5 is the ability to use annotations to create aspects.
Prior to AspectJ 5, writing AspectJ aspects involved learning a Java language extension.
But AspectJ’s annotation-oriented model makes it simple to turn any class into an
aspect by sprinkling a few annotations around. This new feature is commonly referred
to as @AspectJ.
package com.springinaction.springidol;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public classAudience{
@Pointcut(
"execution(* com.springinaction.springidol.Performer.perform(..))")
public voidperformance(){
}
@Before("performance()")
public voidtakeSeats(){
System.out.println("Theaudienceistakingtheirseats.");
}
@Before("performance()")
public voidturnOffCellPhones(){
System.out.println("Theaudienceisturningofftheircellphones");
}
@AfterReturning("performance()")
public voidapplaud(){
System.out.println("CLAPCLAPCLAPCLAPCLAP");
}
@AfterThrowing("performance()")
public voiddemandRefund(){
System.out.println("Boo!Wewantourmoneyback!");
}
}
<aop:aspectj-autoproxy/> <aop:aspectj-autoproxy/>
Annotating around advice
@Around("performance()")
public voidwatchPerformance(ProceedingJoinPointjoinpoint){
try {
System.out.println("Theaudienceistakingtheirseats.");
System.out.println("Theaudienceisturningofftheircellphones");
longstart=System.currentTimeMillis();
joinpoint.proceed();
longend=System.currentTimeMillis();
System.out.println("CLAPCLAPCLAPCLAPCLAP");
System.out.println("Theperformancetook"+(end-start)
+ "milliseconds.");
} catch(Throwablet){
System.out.println("Boo!Wewantourmoneyback!");
}
}
Passing arguments to annotated advice
package com.springinaction.springidol;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public classMagicianimplementsMindReader{
privateStringthoughts;
@Pointcut("execution(*com.springinaction.springidol."
+ "Thinker.thinkOfSomething(String))&&args(thoughts)")
public voidthinking(Stringthoughts){
}
@Before("thinking(thoughts)")
public voidinterceptThoughts(Stringthoughts){
System.out.println("Interceptingvolunteer'sthoughts:"+thoughts);
this.thoughts=thoughts;
}
public StringgetThoughts(){
returnthoughts;
}
}
Annotating introductions
package com.springinaction.springidol;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
@Aspect
public classContestantIntroducer{
@DeclareParents(
value="com.springinaction.springidol.Performer+",
defaultImpl=GraciousContestant.class)
public staticContestantcontestant;
}
Injecting AspectJ aspects
上一篇: 【ML】K近邻算法(2)
下一篇: An Example of ANTLR