一、如何使用XML配置开发AOP
基础知识
<aop:aspect> :用于定义切面类。
<aop:before> :用于定义前置通知。
<aop:after> :用于定义后置通知。
<aop:after-throwing> :用于定义异常通知。
<aop:after-returning> :用于定义返回通知。
<aop:around> :用于定义环绕通知。
被代理的对象
//被代理的对象
public class UserService{
//连接点(被拦截的方法)
public void printUser(User user) {
System.out.println("name:"+user.getName()+" age:"+user.getAge());
}
}
切面类
public class UserAspect {
public void before(){
System.out.println("before...");
}
public void after(){
System.out.println("after...");
}
public void afterReturning(){
System.out.println("afterReturning...");
}
public void afterThrowing(){
System.out.println("afterThrowing...");
}
}
application-cfg.xml
<!-- aop -->
<bean id="userService" class="aop.UserService"></bean>
<bean id="userAspect" class="aop.UserAspect"></bean>
<aop:config><!-- 顶层aop配置元素 -->
<aop:aspect ref="userAspect"><!-- 引用userAspect作为切面 -->
<!-- 定义通知 -->
<aop:before method="before"
pointcut="execution( * aop.UserService.printUser(..))" />
<aop:after method="after"
pointcut="execution( * aop.UserService.printUser(..))" />
<aop:after-returning method="afterReturning"
pointcut="execution( * aop.UserService.printUser(..))" />
<aop:after-throwing method="afterThrowing"
pointcut="execution( * aop.UserService.printUser(..))" />
</aop:aspect>
</aop:config>
测试
ApplicationContext ioc=new ClassPathXmlApplicationContext("application-cfg.xml");
UserService userService=(UserService) ioc.getBean("userService");
User user=new User();
user.setName("李四");
user.setAge(20);
userService.printUser(user);
结果
before...
name:李四 age:20
after...
afterReturning...
可以发现在XML中所有通知拦截的方法都是采用了同一个正则式去匹配,代码产生了很多冗余,因此可以通过定义一个切点,然后在别的通知上引用它。
<!-- aop -->
<bean id="userService" class="aop.UserService"></bean>
<bean id="userAspect" class="aop.UserAspect"></bean>
<aop:config><!-- 顶层aop配置元素 -->
<!-- 引用userAspect作为切面 -->
<aop:aspect ref="userAspect">
<!-- 定义切点 -->
<aop:pointcut expression="execution( * aop.UserService.printUser(..))"
id="pointcut" />
<!-- 定义通知 -->
<!-- pointcut-ref 引用切点 -->
<aop:before method="before" pointcut-ref="pointcut" />
<aop:after method="after" pointcut-ref="pointcut" />
<aop:after-returning method="afterReturning"
pointcut-ref="pointcut" />
<aop:after-throwing method="afterReturning"
pointcut-ref="pointcut" />
</aop:aspect>
</aop:config>
有时候我们希望给通知传递参数 比如给后置通知传递参数可以这样写
public class UserAspect {
//...
public void after(User user){
System.out.println("after..."+user.getName());
}
//...
}
//...
<aop:after method="after" pointcut="execution( * aop.UserService.printUser(..)) and args(user)" />
//...
在使用注解开发AOP时中引入参数使用&&,
- @Before("execution( * aop.UserServiceImpl.printUser(..))&&args(user)")
但是在使用XML时候不能这样写,在XML中用and ,&在XML中有特殊的含义
二、定义多个切面
上面只是定义了一个切面,那么如何定义多个切面呢
首先定义第一个切面
package aop;
//切面1
public class UserAspect1 {
public void before(){
System.out.println("before1...");
}
public void after(){
System.out.println("after1...");
}
public void afterReturning(){
System.out.println("afterReturning1...");
}
public void afterThrowing(){
System.out.println("afterThrowing1...");
}
}
后面两个切面和第一个类似,分别是UserAspect2、UserAspect3
在xml中只需要引用各个切面即可。
<!-- aop -->
<bean id="userService" class="aop.UserService"></bean>
<bean id="userAspect1" class="aop.UserAspect1"></bean>
<bean id="userAspect2" class="aop.UserAspect2"></bean>
<bean id="userAspect3" class="aop.UserAspect3"></bean>
<aop:config>
<!-- 引用userAspect1作为切面 -->
<aop:aspect ref="userAspect1">
<!-- 定义切点 -->
<aop:pointcut expression="execution( * aop.UserService.printUser(..))"
id="pointcut" />
<!-- 定义通知 -->
<!-- pointcut-ref 引用切点 -->
<aop:before method="before" pointcut-ref="pointcut" />
<aop:after method="after" pointcut-ref="pointcut" />
<aop:after-returning method="afterReturning"
pointcut-ref="pointcut" />
<aop:after-throwing method="afterReturning"
pointcut-ref="pointcut" />
</aop:aspect>
<!-- 引用userAspect2作为切面 -->
<aop:aspect ref="userAspect2">
<!-- 定义切点 -->
<aop:pointcut expression="execution( * aop.UserService.printUser(..))"
id="pointcut" />
<!-- 定义通知 -->
<!-- pointcut-ref 引用切点 -->
<aop:before method="before" pointcut-ref="pointcut" />
<aop:after method="after" pointcut-ref="pointcut" />
<aop:after-returning method="afterReturning"
pointcut-ref="pointcut" />
<aop:after-throwing method="afterReturning"
pointcut-ref="pointcut" />
</aop:aspect>
<!-- 引用userAspect3作为切面 -->
<aop:aspect ref="userAspect3">
<!-- 定义切点 -->
<aop:pointcut expression="execution( * aop.UserService.printUser(..))"
id="pointcut" />
<!-- 定义通知 -->
<!-- pointcut-ref 引用切点 -->
<aop:before method="before" pointcut-ref="pointcut" />
<aop:after method="after" pointcut-ref="pointcut" />
<aop:after-returning method="afterReturning"
pointcut-ref="pointcut" />
<aop:after-throwing method="afterReturning"
pointcut-ref="pointcut" />
</aop:aspect>
</aop:config>
测试
ApplicationContext ioc=new ClassPathXmlApplicationContext("application-cfg.xml");
UserService userService=(UserService) ioc.getBean("userService");
User user=new User();
user.setName("李四");
user.setAge(20);
userService.printUser(user);
执行结果
before1...
before2...
before3...
name:李四 age:20
after3...
afterReturning3...
after2...
afterReturning2...
after1...
afterReturning1...
在使用xml配置多个切面时每个切面通知的执行顺序和它们在xml文件中的先后顺序有关。