-1,通知(advice):通知定义了切面是什么时候以及何时用的。除了描述切面的工作,通知还决定了合适解决。Spring切面可以用5中类型的通知。
Before:在方法调用之前使用。
After:在方法完成之后调用通知,无论方法是否执行成功。
After-returning:在方法执行成功后调用。
After-throwing:在方法抛出异常后调用。
Around:通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义行为。
-2,切点(pointcut):一个或多个连接点。
-3,连接点(join point):应用在执行过程中能够插入切面的点。
-4,切面(Aspect):切面是通知和切点的结合,通知和切点共同定义了关于切面的全部内容。
-5,引入(Introduction):引入允许我们向现有的类添加新的方法或属性。
2,Spring借助AspectJ的切点表达式语言来定义Spring切面
-1,arg() :限制连接点匹配参数为制定类型的执行方法。
-2,@args() :限制连接点匹配参数由制定注解标注的执行方法。
-3,execution():用于匹配是连接点的执行方法。
-4,this():限制连接点匹配AOP代理的Bean引用为制定类型的类。
-5,target():限制连接点匹配目标对象为制定类型的类。
-6,@target():限制连接点匹配特定的执行对象,这些对象对应的类要具备制定注解。
-7,within():限制连接点匹配指定的类型。
-8,@within():限制连接点匹配制定注解的类型。
-9,@annotation:限制匹配带有制定注解连接点。
3,编写切点:
<aop:config>
<aop:aspect ref="audience">
<aop:before
pointcut="execution(* chp02.springdol.Perform.perform(..))"
method="takeSeat" />
<aop:before
pointcut="execution(* chp02.springdol.Perform.perform(..))"
method="turnOffCellPhone" />
<aop:after-returning
pointcut="execution(* chp02.springdol.Perform.perform(..))"
method="applaud" />
<aop:after-throwing
pointcut="execution(* chp02.springdol.Perform.perform(..))"
method="demandRefund" />
</aop:aspect>
</aop:config>
package chp04.aop;
/**
* 类描述:观众类,测试AOP
*
* @author: Jing
* History: Jan 7, 2015 3:33:35 PM Jing Created.
*
*/
public class Audience {
public void takeSeat(){
System.out.println("The audience is taking their seats.");
}
public void turnOffCellPhone(){
System.out.println("The audience is turning off their cellphone!");
}
public void applaud(){
System.out.println("CLAP CLAP CLAP CLAP CLAP ");
}
public void demandRefund(){
System.out.println("Boo! we want our money back!");
}
}
package chp04.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import chp02.springdol.Perform;
/**
* 类描述:
*
* @author: Jing
* History: Jan 8, 2015 4:52:20 PM Jing Created.
*
*/
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("chp04/aop/spring.xml");
Perform perform = (Perform) ctx.getBean("juggler");
perform.perform();
}
}
输出结果
The audience is taking their seats.
The audience is turning off their cellphone!
Juggler perform(),beanBags : 3
CLAP CLAP CLAP CLAP CLAP
因为以上涉及到的切点都相同,我们可以将切点配置抽取,如下:
<aop:config>
<aop:aspect ref="audience">
<aop:pointcut id="perform"
expression="execution(* chp02.springdol.Perform.perform(..))" />
<aop:before pointcut-ref="perform" method="takeSeat" />
<aop:before pointcut-ref="perform"
method="turnOffCellPhone" />
<aop:after-returning pointcut-ref="perform"
method="applaud" />
<aop:after-throwing pointcut-ref="perform"
method="demandRefund" />
</aop:aspect>
</aop:config>
声明环绕通知
环绕通知java处理代码:
/**
*
* 方法说明:环绕通知
*
* Author: Jing Create Date: Jan 9, 2015 10:44:37 AM
*/
public void watchPerformance(ProceedingJoinPoint joinPoint) {
try {
System.out.println("The audience is taking their seats.");
System.out.println("The audience is turning off their cellphone!");
long start = System.currentTimeMillis();
joinPoint.proceed();
long end = System.currentTimeMillis();
System.out.println("CLAP!CLAP!CLAP!CLAP!");
System.out.println("The perform took " + ( end - start) + " s");
} catch (Throwable e) {
System.out.println("Exception, we want our money back! ");
}
}
环绕通知XML配置:
<aop:config>
<aop:aspect ref="audience">
<aop:pointcut id="perform2"
expression="execution(* chp02.springdol.Perform.perform(..))" />
<aop:around pointcut-ref="perform2"
method="watchPerformance" />
</aop:aspect>
</aop:config>
为通知传递参数:
package chp04.aop;
/**
* 类描述:测试通知参数
*
* @author: Jing
* History: Jan 9, 2015 11:00:32 AM Jing Created.
*
*/
public interface MindReader {
void interceptThoughts(String thoughts);
String getThoughts();
}
package chp04.aop;
/**
* 类描述:
*
* @author: Jing
* History: Jan 9, 2015 2:13:29 PM Jing Created.
*
*/
public class Magician implements MindReader{
private String thoughts;
public String getThoughts() {
return thoughts;
}
public void setThoughts(String throughts) {
this.thoughts = throughts;
}
@Override
public void interceptThoughts(String throughts) {
System.out.println("intercept Thoughts");
this.thoughts = throughts;
}
}
package chp04.aop;
/**
* 类描述:
*
* @author: Jing
* History: Jan 9, 2015 2:26:51 PM Jing Created.
*
*/
public interface Thinker {
void thinkOfSomething(String thoughts);
public String getThoughts();
}
package chp04.aop;
/**
* 类描述:
*
* @author: Jing
* History: Jan 9, 2015 2:27:48 PM Jing Created.
*
*/
public class Volunteer implements Thinker {
private String thoughts;
@Override
public void thinkOfSomething(String thoughts) {
this.thoughts = thoughts;
}
public String getThoughts() {
return thoughts;
}
}
<bean id="volunteer" class="chp04.aop.Volunteer" />
<bean id="magician" class="chp04.aop.Magician" />
<aop:config>
<aop:aspect ref="magician">
<aop:pointcut id="thinking" expression="execution(* chp04.aop.Thinker.thinkOfSomething(String)) and args(thoughts)"/>
<aop:before pointcut-ref="thinking" method="interceptThoughts" arg-names="thoughts"/>
</aop:aspect>
</aop:config>
package chp04.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 类描述:
*
* @author: Jing
* History: Jan 8, 2015 4:52:20 PM Jing Created.
*/
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("chp04/aop/spring.xml");
// Volunteer volunteer = (Volunteer) ctx.getBean("volunteer");
// volunteer.thinkOfSomething("Thinking the world!");
Thinker volunteer = (Thinker) ctx.getBean("volunteer");//因为AOP配置,此处必须转换为接口
volunteer.thinkOfSomething("Thinking the world!");
System.out.println(volunteer.getThoughts());
}
}
4,通过切面引入新功能。
package chp04.aop;
/**
* 类描述:其他功能接口
*
* @author: Jing
* History: Jan 9, 2015 3:15:40 PM Jing Created.
*
*/
public interface Contestant {
void receiveAward();
}
package chp04.aop;
/**
* 类描述:接口实现
*
* @author: Jing
* History: Jan 9, 2015 3:25:47 PM Jing Created.
*
*/
public class GraciousContestant implements Contestant{
@Override
public void receiveAward() {
System.out.println("Auto Add method");
}
}
<bean id="graciousContestant" class="chp04.aop.GraciousContestant" />
<aop:config>
<aop:aspect>
<aop:declare-parents types-matching="chp04.aop.Thinker+"
implement-interface="chp04.aop.Contestant"
delegate-ref="graciousContestant" />
<!--default-impl="chp04.aop.GraciousContestant"/> 此处同delegate-ref 目的一致,声明对应接口的默认实现 -->
</aop:aspect>
</aop:config>
package chp04.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 类描述:
*
* @author: Jing
* History: Jan 8, 2015 4:52:20 PM Jing Created.
*/
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("chp04/aop/spring.xml");
Contestant volunteer = (Contestant) ctx.getBean("volunteer");
volunteer.receiveAward();
}
}
5,基于注解的配置
package chp04.aop;
import org.aspectj.lang.ProceedingJoinPoint;
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;
/**
* 类描述:观众类,测试AOP
*
* @author: Jing History: Jan 7, 2015 3:33:35 PM Jing Created.
*
*/
@Aspect
public class Audience {
@Pointcut("execution(* chp02.springdol.Perform.perform(..))")
/**
* 定义切点
*/
public void perform(){
}
@Before("perform()")
public void takeSeat() {
System.out.println("The audience is taking their seats.");
}
@Before("perform()")
public void turnOffCellPhone() {
System.out.println("The audience is turning off their cellphone!");
}
@AfterReturning("perform()")
public void applaud() {
System.out.println("CLAP CLAP CLAP CLAP CLAP ");
}
@AfterThrowing("perform()")
public void demandRefund() {
System.out.println("Boo! we want our money back!");
}
/**
*
* 方法说明:环绕通知
*
* Author: Jing Create Date: Jan 9, 2015 10:44:37 AM
*/
public void watchPerformance(ProceedingJoinPoint joinPoint) {
try {
System.out.println("The audience is taking their seats.");
System.out.println("The audience is turning off their cellphone!");
long start = System.currentTimeMillis();
joinPoint.proceed();
long end = System.currentTimeMillis();
System.out.println("CLAP!CLAP!CLAP!CLAP!");
System.out.println("The perform took " + ( end - start) + " s");
} catch (Throwable e) {
System.out.println("Exception, we want our money back! ");
}
}
}
配置文件启用注解API
<aop:aspectj-autoproxy />
环绕通知:
/**
*
* 方法说明:环绕通知
*
* Author: Jing Create Date: Jan 9, 2015 10:44:37 AM
*/
@Around("perform()")
public void watchPerformance(ProceedingJoinPoint joinPoint) {
try {
System.out.println("The audience is taking their seats.");
System.out.println("The audience is turning off their cellphone!");
long start = System.currentTimeMillis();
joinPoint.proceed();
long end = System.currentTimeMillis();
System.out.println("CLAP!CLAP!CLAP!CLAP!");
System.out.println("The perform took " + ( end - start) + " s");
} catch (Throwable e) {
System.out.println("Exception, we want our money back! ");
}
}