配置Spring AOP面向切面编程

一. AOP一些概念

Aspect( 切面 ): 指横切性关注点的抽象即为切面, 它与类相似, 只是两者的关注点不一样, 类是对物体特征的抽象, 而切面横切性关注点的抽象.
joinpoint( 连接点 ): 指那些被拦截到的点. 在spring中, 这些点指的是方法, 因为spring只支持方法类型的连接点, 实际上joinpoint还可以是field或类构造器)
Pointcut( 切入点 ): 指我们要对那些joinpoint进行拦截的定义.
Advice( 通知 ): 指拦截到joinpoint之后所要做的事情就是通知. 通知分为前置通知、后置通知、异常通知、最终通知、环绕通知.
Target( 目标对象 ): 代理的目标对象。
Weave( 织入 ): 指将aspects应用到target对象并导致proxy对象创建的过程称为织入.
Introduction( 引入 ): 在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.


二. 基于注解声明切面 

使用注解配置aop会是代码非常简洁:

① 引入Jar包

aspectjrt.jar

aspectjweaver.jar

cglib-nodep-2.1_3.jar

commons-logging.jar

spring.jar


② 业务类: PersonServiceImpl

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. @Service("personServiceImpl")   
  2. public class PersonServiceImpl {  
  3.   
  4.     public String save(String name) {  
  5.         // throw new RuntimeException("我爱例外");  
  6.         System.out.println("我是save()方法");  
  7.         return "success";  
  8.     }  
  9.   
  10. }  

③ AOP切面类

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. @Aspect  
  2. @Component  
  3. public class MyInterceptor {  
  4.   
  5.     @SuppressWarnings("unused")  
  6.     @Pointcut("execution (* com.zdp.service.impl.PersonServiceImpl.*(..))")   // 拦截PersonServiceImpl类下的所有方法  
  7.     private void anyMethod() {  
  8.     } // 声明一个切入点  
  9.   
  10.     @Before("anyMethod() && args(name)")  
  11.     public void doAccessCheck(String name) {  
  12.         System.out.println("前置通知:" + name);  
  13.     }  
  14.   
  15.     @AfterReturning(pointcut = "anyMethod()", returning = "result")  
  16.     public void doAfterReturning(String result) {  
  17.         System.out.println("后置通知:" + result);  
  18.     }  
  19.   
  20.     @After("anyMethod()")  
  21.     public void doAfter() {  
  22.         System.out.println("最终通知");  
  23.     }  
  24.   
  25.     @AfterThrowing(pointcut = "anyMethod()", throwing = "e")  
  26.     public void doAfterThrowing(Exception e) {  
  27.         System.out.println("例外通知:" + e);  
  28.     }  
  29.   
  30.     @Around("anyMethod()")  
  31.     public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {  
  32.         System.out.println("进入方法");  
  33.         Object result = pjp.proceed();  
  34.         System.out.println("退出方法");  
  35.         return result;  
  36.     }  
  37. }  

④ 配置文件beans.xml

[html]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.        xmlns:context="http://www.springframework.org/schema/context"   
  5.        xmlns:aop="http://www.springframework.org/schema/aop"        
  6.        xsi:schemaLocation="http://www.springframework.org/schema/beans  
  7.            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
  8.            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd  
  9.            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">  
  10.         <context:component-scan base-package="com.zdp"/>  
  11.         <aop:aspectj-autoproxy/>   
  12. </beans>  

⑤ 测试类

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. public class SpringAOPTest {  
  2.     @Test  
  3.     public void testSave() {  
  4.         ApplicationContext cxt = new ClassPathXmlApplicationContext("beans.xml");  
  5.         PersonServiceImpl psi = (PersonServiceImpl) cxt.getBean("personServiceImpl");  
  6.         psi.save("zhangsan");  
  7.     }  
  8. }  

测试结果:

        前置通知:zhangsan
        进入方法
        我是save()方法
        后置通知:success
        最终通知
        退出方法


注意: 以上只是一个测试AOP注解, 没有写接口PersonService, 所以无法使用动态代理, 所以要引入CGLIB包.


三. 基于配置声明切面 

① 引入jar包

aspectjrt.jar

aspectjweaver.jar

cglib-nodep-2.1_3.jar

commons-logging.jar

spring.jar


② 业务类: PersonServiceImpl

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. public class PersonServiceImpl {  
  2.       
  3.     public String getPersonName(Integer id) {  
  4.         System.out.println("我是getPersonName()方法");  
  5.         return "xxx";  
  6.     }  
  7.       
  8. }  

③ AOP切面类

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. public class MyInterceptor {  
  2.     public void doAccessCheck() {  
  3.         System.out.println("前置通知");  
  4.     }  
  5.   
  6.     public void doAfterReturning() {  
  7.         System.out.println("后置通知");  
  8.     }  
  9.   
  10.     public void doAfter() {  
  11.         System.out.println("最终通知");  
  12.     }  
  13.   
  14.     public void doAfterThrowing() {  
  15.         System.out.println("例外通知");  
  16.     }  
  17.   
  18.     public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {  
  19.         System.out.println("进入方法");  
  20.         Object result = pjp.proceed();  
  21.         System.out.println("退出方法");  
  22.         return result;  
  23.     }  
  24. }  

④ 配置文件beans.xml

[html]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.        xmlns:context="http://www.springframework.org/schema/context"   
  5.        xmlns:aop="http://www.springframework.org/schema/aop"        
  6.        xsi:schemaLocation="http://www.springframework.org/schema/beans  
  7.            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
  8.            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd  
  9.            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">  
  10.         <aop:aspectj-autoproxy/>   
  11.         <bean id="personServiceImpl" class="com.zdp.service.impl.PersonServiceImpl" />  
  12.         <bean id="aspetbean" class="com.zdp.spring.MyInterceptor" />  
  13.         <aop:config>  
  14.             <aop:aspect id="asp" ref="aspetbean">  
  15.                 <aop:pointcut id="mycut" expression="execution(* com.zdp.service..*.*(..))"/>  
  16.                 <aop:before pointcut-ref="mycut" method="doAccessCheck"/>  
  17.                 <aop:after-returning pointcut-ref="mycut" method="doAfterReturning"/>  
  18.                 <aop:after-throwing pointcut-ref="mycut" method="doAfterThrowing"/>  
  19.                 <aop:after pointcut-ref="mycut" method="doAfter"/>  
  20.                 <aop:around pointcut-ref="mycut" method="doBasicProfiling"/>  
  21.             </aop:aspect>  
  22.         </aop:config>  
  23. </beans>  

⑤ 测试类

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. public class SpringAOPTest {  
  2.   
  3.     @Test   
  4.     public void interceptorTest(){  
  5.         ApplicationContext cxt = new ClassPathXmlApplicationContext("beans.xml");  
  6.         PersonServiceImpl psi = (PersonServiceImpl)cxt.getBean("personServiceImpl");  
  7.         psi.getPersonName(1);  
  8.     }  
  9. }  

测试结果:

        前置通知
        进入方法
        我是getPersonName()方法
        后置通知
        最终通知
        退出方法


四. 切入点表达式

表达式格式:

* execution(
                       * 1. modifiers-pattern?         修饰符模式
                                                                         * 方法使用的修饰符
                       * 2. ret-type-pattern            返回类型模式(必须) 
                                                                         * 返回类型模式决定了方法的返回类型必须一次匹配一个连接点
                                                                         * 你会使用的最频繁的返回类型模式是*,它代表匹配任意的返回类型
                       * 3. declaring-type-pattern? 声明类型模式
                                                                         * 方法所在类的全路径
                       * 4. name-pattern                  名字模式(必须)
                                                                         * 名字模式匹配的是方法名,你可以使用*通配符作为所有或者部分命名模式
                                                                            saveUser  -- 方法必须是saveUser
                                                                            save* -- 方法以save开头
                       * 5. param-pattern                 参数模式(必须)
                                                                         * ()匹配一个不接受任意参数的方法
                                                                         * (..)匹配一个接受任意数量参数的方法(零个或者更多)
                                                                         * (*)匹配一个接受任何类型的参数的方法
                                                                         * 模式(*,String)匹配一个接受两个参数的方法,第一个可以是任意类型,第二个则必须是String类型
                       * 6. throws-pattern?              异常模式
)


表达式例子:

1. 任意公共方法的执行: execution(public * *(..))
2. 任何一个名字以“set”开始的方法的执行: execution(* set*(..))
3. AccountService接口定义的任意方法的执行:execution(* com.xyz.service.AccountService.*(..))
4. 在service包中定义的任意方法的执行:execution(* com.xyz.service.*.*(..))
5. 在service包或其子包中定义的任意方法的执行:execution(* com.xyz.service..*.*(..))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值