一、如何使用XML配置开发AOP
被代理的对象
//被代理的对象 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: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="afterReturning" 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> <!-- 引用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)")
二、定义多个切面
上面只是定义了一个切面,那么如何定义多个切面呢
首先定义第一个切面
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文件中的先后顺序有关。