1、Spring AOP相关描述
基于Schmeade的AOP从Spring2.0之后通过“aop”命名空间来定义切面(Aspect)、切入点(Pointcut)、增强(Advice)。
在Spring配置文件中,所有AOP相关定义都必须放在<aop:config>标签下,该标签有<aop:pointcut>、<aop:advisor>、<aop:aspect>标签,配置顺序不可改变。
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
1)、aop:pointcut:用来定义切入点,加入增强的位置
2)、aop:advisor:用来定义只有一个通知和一个切入点的切面
3)、aop:aspect:用来定义切面,内部可以有多个切入点和增强(前置通知、后置通知、异常...)
4)、aop:aspect与aop:advisor不同之处就在于advisor只能声明一个切入点和一个增强。
<aop:advisor advice-ref="" pointcut=""/>
2、定义业务Bean:
package com.sxit;
public class HelloWorldService {
public void say(String a,String b){
System.out.println("我说....................");
}
public void look() throws Exception{
System.out.println("我看.....................");
}
}
3、定义切面:
package com.sxit;
/**
* 切面类
*/
public class HelloWorldAspect {
//方法执行前执行
public void before(){
System.out.println("before:------------------->>>");
}
//方法执行完执行(不抛异常的情况下)
public void after(){
System.out.println("after======");
}
//方法执行完执行(抛异常的情况下也执行,相当于finaaly)
public void returnFinally(){
System.out.println("returnFinally");
}
//方法抛出异常时执行
public void exception(Exception e){
System.out.println("exception"+e);
}
}
4、配置xml:
1)、首先先声明业务Bean和切面Bean
<!-- 切面Bean -->
<bean id="helloWorldAspect" class="com.sxit.HelloWorldAspect" />
<!-- 业务Bean -->
<bean id="helloWorldService" class="com.sxit.HelloWorldService" />
2)、使用<aop:config>标签按顺序的写切入点、切面
3)、定义切入点:
<aop:pointcut id="onePointcut" expression="execution(* com.sxit..*.*(..))"/>
4)、定义切面:
<aop:aspect id="oneAspect" ref="helloWorldAspect">
<aop:before pointcut-ref="onePointcut" method="before"/>
</aop:aspect>
5、测试类:
public class Test {
public static void main(String[] args){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloWorldService hello = (HelloWorldService)ac.getBean("helloWorldService");
hello.look();
}
}
6、前置通知:在目标对象方法执行前切入增强逻辑,使用<aop:before>标签声明
1)、前置通知格式:<aop:before pointcut="切入点表达式" pointcut-ref="如果已配置pointcut,这里写某个切入点的Bean Id" method="增强类中方法" arg-names="增强方法参数名"/>
2)、配置:
<aop:before pointcut-ref="onePointcut" method="before"/>
3)、打印信息:
before:------------------->>>
我说....................
4)、这里pointcut和point-ref任选一个,如果使用外部已经声明好的切入点,则直接使用point-ref引用,如果没有,则自己声明一个内部通知。method参数是指切入增强的具体方法。
5)、这里再来看下args的功能:先在切面类中加入一个带参数的before方法对应业务Bean中的say方法。
public void before2(String aa,String bb){
System.out.println("before:------------------->>>"+aa+"===="+bb);
}
6)、修改切点表达式:这里的aa,bb用来匹配目标类中对应参数名方法
<aop:pointcut id="onePointcut" expression="execution(* com.sxit..*.*(..)) and args(aa,bb)"/>
7)、修改前置通知:这里arg-names是增强方法中与目标方法同名参数
<aop:aspect id="oneAspect" ref="helloWorldAspect">
<aop:before pointcut-ref="onePointcut" method="before2" arg-names="aa,bb"/>
</aop:aspect>
8)、args中参数名和个数和arg-names中保持一致就是了。
7、后置异常通知:方法执行抛出异常时会调用增强中对应方法,使用<aop:after-throwing>标签
1)、配置,这里需要加上一个throwing,这里与增强Bean中异常参数名一致
<aop:after-throwing pointcut-ref="onePointcut" method="exception" throwing="e"/>
2)、增强Bean
//方法抛出异常时执行
public void exception(Exception e){
System.out.println("exception"+e);
}
3)、修改业务Bean,使look方法运行时抛出异常
public void look() throws Exception{
System.out.println("我看.....................");
throw new Exception();
}
4)、测试类:
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloWorldService hello = (HelloWorldService)ac.getBean("helloWorldService");
try {
hello.look();
} catch (Exception e) {
}
5)、运行结果:
我看.....................
exception java.lang.Exception
8、后置返回通知:方法执行完后切入增强,抛出异常则不执行,使用<aop:after-returning>
1)、配置方式:这里的returning是增强方法中参数的名字
<aop:after-returning pointcut-ref="onePointcut" method="after" returning="o"/>
2)、业务Bean中增加一个方法:用来把返回值传递给切面Bean
public int sb(){
System.out.println("sb+++");
int sb = 2;
return sb;
}
3)、修改切面Bean after方法:这里的参数o就是配置文件中的returning
public void after(Object o){
System.out.println("after======"+o);
}
4)、打印信息:
sb+++
after======2
9、后置最终通知,在切入点方法返回时,不论是否抛出异常均切入增强,使用<aop:after>标签声明
1)、配置:
<aop:after pointcut-ref="onePointcut" method="returnFinally" arg-names=""/>
2)、打印信息:
我看.....................
returnFinally
3)、抛出异常也会切入增强:
<aop:aspect id="oneAspect" ref="helloWorldAspect">
<aop:after-throwing pointcut-ref="onePointcut" method="exception" throwing="ew"/>
<aop:after pointcut-ref="onePointcut" method="returnFinally" arg-names=""/>
</aop:aspect>
public void look() throws Exception{
System.out.println("我看.....................");
throw new Exception();
}
hello.look();
4)、打印信息:
我看.....................
exception java.lang.Exception
returnFinally
10、环绕通知:在切入点前后均能执行的通知,它可以决定目标方法是否执行,何时执行,执行时是否替换方法参数,执行完是否需要替换返回值,可通过<aop:around>来声明:
1)、新增环绕通知实现:
public Object around(ProceedingJoinPoint pjp){
System.out.println("环绕start-----");
Object result = null;
try {
result = pjp.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("环绕end-----");
return result;
}
2)、配置:
<aop:around pointcut-ref="onePointcut" method="around"/>
3)、打印信息:
环绕start-----
我看.....................
环绕end-----
参考自:http://jinnianshilongnian.iteye.com/blog/1418598
http://ch-space.iteye.com/blog/493956