[color=red][size=large]spring AOP技术[/size][/color]
6.通知应用实例(基于注解)
在前一节,我们应用了前置通知和后置通知,除了这两个通知外,下面接着演示其它通知的应用。
(1)最终通知
在切面类TheInterceptor中增加如下代码即可:略去测试。
@After("anyMethod()")// 最终通知
public void after() {
System.out.println("最终通知");
}
(2)异常通知
为了演示此实例,我们在UseDaoImp中增加如下代码以抛出异常:
int i=1/0;在然后在切面类TheInterceptor中增加如下代码:
@AfterThrowing("anyMethod()") // 例外通知
public void AfterThrowing() {
System.out.println("例外通知");
}
当获取代理对象并调用save方法时会抛出异常,例外通知便会得以执行。
(3)环绕通知
@Around("anyMethod()") //环绕通知
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("进入环绕");
//if(){ // 进行一些判断,再执行环绕
Object result = pjp.proceed();
//}
System.out.println("退出环绕");
return result;
}
注意的是方法的参数及抛出异常类型的固定写法(方法名可以是任意得),另在该方法中必须执行pjp.proceed()才能让环绕通知中的两处打印代码得以执行。即是说要想环绕通知的拦截处理代码起作用必须调用pjp.proceed方法。 补充:环绕通知通常可以用来测试方法的执行时间,在pjp.proceed前获取一个时间,在pjp.proceed方法后再获取一个时间。最后两个时间相减即可得方法执行时间。
(4)传递参数给通知
首先在UseDao接口中增加如下代码:
String add(String name);
然后再在UserDaoImp中实现此方法,代码如下:
public String add(String name) {
System.out.println("add method is called [ " + name+" ]");
return "添加成功";
}
需求:获取调用add方法传递的参数。操作步骤如下:在切面类增加如下代码:
@Before("anyMethod() && args(name)")// 前置通知,只针对UseDaoImp的add方法
public void beforeAdd(String name) {
System.out.println("前置通知:" + name);
}
说明:在前置通知的方法中有一个参数,然后再把此参数作为拦截条件(即是说拦截带有一个String类型参数的方法)。args的名字和beforeAdd方法参数名字相同。
测试代码:
public void advieeTest() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
UserDao ud=(UserDao) ctx.getBean("userDaoImp");
ud.add("xxx");
}
(5)获取方法的返回值
我们知道add方法有一个返回值,我们对此方法进行拦截并获取返回值,在切面类中增加如下代码:
@AfterReturning(pointcut = "anyMethod()", returning = "result")
// 后置通知,监听返回结果,针对UserDaoImp的getUsername()方法
public void afterReturningRes(String result) {
System.out.println("后置通知,返回结果:" + result);
}
说明:afterReturningRes方法的参数就是要返回的参数类型,returning标记的就是的结果,它的取值与该方法参数名相同。 测试代码同(4)。
(6)获取抛出的异常
切面类的增加如下代码:
@AfterThrowing(pointcut="anyMethod",throwing="e")
public void catchException(Exception e){
System.out.println("获取抛出的异常:"+e);
}
throwing的取值和方法的参数名相同,测试代码省略。
7. 通知应用实例(基于XML)
步骤一、复制TheInterceptorX类为TheInterceptorXML,并去掉所有注解。
步骤二、建立beansXML.xml配置文件,内容如下:
<aop:aspectj-autoproxy /><!-- 开启切面编程功能 -->
<bean id="userDaoImp" class="com.asm.dao.impl.UserDaoImp" />
<bean id="aspectBean"
class="com.asm.dao.impl.factory.TheInterceptorXML" />
<aop:config>
<aop:aspect id="asp" ref="aspectBean"> --声明一个切面类
<aop:pointcut id="thecut" --声明一个切入点
expression="execution(* com.asm.dao.impl.UserDaoImp.*(..))" />
<aop:after-returning pointcut-ref="thecut" method="afterReturningRes" returning="result" />
<aop:around pointcut-ref="thecut" method="around"/>
<aop:after-throwing pointcut-ref="thecut" method="catchException" throwing="e"/>
<aop:after pointcut-ref="thecut" method="after" />
<aop:before pointcut-ref="thecut" method="before" />
</aop:aspect>
</aop:config>
测试代码如下:
public void advieeTest() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beansXML.xml");
UserDao ud=(UserDao) ctx.getBean("userDaoImp");
ud.add("xxx");
}
未解决问题:不能成功传参给前置通知。
8.解析切入点表达式
1.格式:execution(返回值 空格 方法选择)。两部分组成,中间一定要有空格。
返回值:可以是*,说明拦截任何方法。Java.lang.String(全名),拦截返回值为String类型的方法。 常用的实例如下:
方法选择:包名[类名].*()。设定要拦截的方法签名。
表达式(省略execution)
说明
(java.lang.String 方法选择略)
拦截返回值为String类型的方法
(!void 方法选择略)
拦截返回值非空的方法
(* com.asm..*.*(..))
拦截com.asm包及子包下每个类的全部方法
(* com.asm.*.*(..))
拦截com.asm包下每个类的全部方法
(* com.asm.User.*(..))
拦截asm包下User类的所有方法
(* com.asm.User.*
(java.lang.String,..))
拦截User类中第一个参数为String,后面参数任一的方法
待增加
待增加
9.总结
面向切面的常见应用(如权限拦截)、spring的aop依赖两种方式实现代理(依被代理的对象是否实现接口而定)、通知概念、基于注解与基于XML两种方式来配置切面、基本步骤(依要拦截的方法来设定切入点,依据业务需求实现拦截通知代码,切面纳入spring容器管理,要被监控的类只能是通过Spring容器获取)、切入点的格式。
6.通知应用实例(基于注解)
在前一节,我们应用了前置通知和后置通知,除了这两个通知外,下面接着演示其它通知的应用。
(1)最终通知
在切面类TheInterceptor中增加如下代码即可:略去测试。
@After("anyMethod()")// 最终通知
public void after() {
System.out.println("最终通知");
}
(2)异常通知
为了演示此实例,我们在UseDaoImp中增加如下代码以抛出异常:
int i=1/0;在然后在切面类TheInterceptor中增加如下代码:
@AfterThrowing("anyMethod()") // 例外通知
public void AfterThrowing() {
System.out.println("例外通知");
}
当获取代理对象并调用save方法时会抛出异常,例外通知便会得以执行。
(3)环绕通知
@Around("anyMethod()") //环绕通知
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("进入环绕");
//if(){ // 进行一些判断,再执行环绕
Object result = pjp.proceed();
//}
System.out.println("退出环绕");
return result;
}
注意的是方法的参数及抛出异常类型的固定写法(方法名可以是任意得),另在该方法中必须执行pjp.proceed()才能让环绕通知中的两处打印代码得以执行。即是说要想环绕通知的拦截处理代码起作用必须调用pjp.proceed方法。 补充:环绕通知通常可以用来测试方法的执行时间,在pjp.proceed前获取一个时间,在pjp.proceed方法后再获取一个时间。最后两个时间相减即可得方法执行时间。
(4)传递参数给通知
首先在UseDao接口中增加如下代码:
String add(String name);
然后再在UserDaoImp中实现此方法,代码如下:
public String add(String name) {
System.out.println("add method is called [ " + name+" ]");
return "添加成功";
}
需求:获取调用add方法传递的参数。操作步骤如下:在切面类增加如下代码:
@Before("anyMethod() && args(name)")// 前置通知,只针对UseDaoImp的add方法
public void beforeAdd(String name) {
System.out.println("前置通知:" + name);
}
说明:在前置通知的方法中有一个参数,然后再把此参数作为拦截条件(即是说拦截带有一个String类型参数的方法)。args的名字和beforeAdd方法参数名字相同。
测试代码:
public void advieeTest() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
UserDao ud=(UserDao) ctx.getBean("userDaoImp");
ud.add("xxx");
}
(5)获取方法的返回值
我们知道add方法有一个返回值,我们对此方法进行拦截并获取返回值,在切面类中增加如下代码:
@AfterReturning(pointcut = "anyMethod()", returning = "result")
// 后置通知,监听返回结果,针对UserDaoImp的getUsername()方法
public void afterReturningRes(String result) {
System.out.println("后置通知,返回结果:" + result);
}
说明:afterReturningRes方法的参数就是要返回的参数类型,returning标记的就是的结果,它的取值与该方法参数名相同。 测试代码同(4)。
(6)获取抛出的异常
切面类的增加如下代码:
@AfterThrowing(pointcut="anyMethod",throwing="e")
public void catchException(Exception e){
System.out.println("获取抛出的异常:"+e);
}
throwing的取值和方法的参数名相同,测试代码省略。
7. 通知应用实例(基于XML)
步骤一、复制TheInterceptorX类为TheInterceptorXML,并去掉所有注解。
步骤二、建立beansXML.xml配置文件,内容如下:
<aop:aspectj-autoproxy /><!-- 开启切面编程功能 -->
<bean id="userDaoImp" class="com.asm.dao.impl.UserDaoImp" />
<bean id="aspectBean"
class="com.asm.dao.impl.factory.TheInterceptorXML" />
<aop:config>
<aop:aspect id="asp" ref="aspectBean"> --声明一个切面类
<aop:pointcut id="thecut" --声明一个切入点
expression="execution(* com.asm.dao.impl.UserDaoImp.*(..))" />
<aop:after-returning pointcut-ref="thecut" method="afterReturningRes" returning="result" />
<aop:around pointcut-ref="thecut" method="around"/>
<aop:after-throwing pointcut-ref="thecut" method="catchException" throwing="e"/>
<aop:after pointcut-ref="thecut" method="after" />
<aop:before pointcut-ref="thecut" method="before" />
</aop:aspect>
</aop:config>
测试代码如下:
public void advieeTest() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beansXML.xml");
UserDao ud=(UserDao) ctx.getBean("userDaoImp");
ud.add("xxx");
}
未解决问题:不能成功传参给前置通知。
8.解析切入点表达式
1.格式:execution(返回值 空格 方法选择)。两部分组成,中间一定要有空格。
返回值:可以是*,说明拦截任何方法。Java.lang.String(全名),拦截返回值为String类型的方法。 常用的实例如下:
方法选择:包名[类名].*()。设定要拦截的方法签名。
表达式(省略execution)
说明
(java.lang.String 方法选择略)
拦截返回值为String类型的方法
(!void 方法选择略)
拦截返回值非空的方法
(* com.asm..*.*(..))
拦截com.asm包及子包下每个类的全部方法
(* com.asm.*.*(..))
拦截com.asm包下每个类的全部方法
(* com.asm.User.*(..))
拦截asm包下User类的所有方法
(* com.asm.User.*
(java.lang.String,..))
拦截User类中第一个参数为String,后面参数任一的方法
待增加
待增加
9.总结
面向切面的常见应用(如权限拦截)、spring的aop依赖两种方式实现代理(依被代理的对象是否实现接口而定)、通知概念、基于注解与基于XML两种方式来配置切面、基本步骤(依要拦截的方法来设定切入点,依据业务需求实现拦截通知代码,切面纳入spring容器管理,要被监控的类只能是通过Spring容器获取)、切入点的格式。