最近在系统中需要实现用户某些操作添加积分, 希望实现对系统现有的代码进行最小嵌入,因此使用Spring AOP的切面编程将很好实现该需求,达到最小耦合度。在Spring AOP中的通知都是针对方法层级进行通知,相对与Struct中针对类层级通知,具有更好的灵活性。
/*方法拦截*/ MethodInterceptor /*返回拦截*/ AfterReturningAdvice /*事件拦截*/ HandlerInterceptor MethodInvocation
- Spring对AOP的支持具有以下4种情况:
1、经典的基于代理的AOP(各版本Spring)
2、@AspectJ注解驱动的切面(仅Spring 2.0);
3、纯POJO切面(仅Spring2.0);
4、注入式AspectJ切面(各版本Spring)
- 在spring aop中有以下四种通知类型,本次使用的是after returning advice方式的通知。
1、before advice 在方法执行前执行。
2、after returning advice 在方法执行后返回一个结果后执行
3、after throwing advice 在方法执行过程中抛出异常后执行
4、around advuce 综合执行以上三种情况
- 典型Spring AOP编程的三个步骤
1、创建通知:实现通知的这几个接口,并实现其中的方法
a)org.springframework.aop.MethodBeforeAdvice
b)org.springframework.aop.AfterReturningAdvice
c)org.springframework.aop.ThrowsAdvice
d)org.aopalliance.intercept.MethodInterceptor
e)org.springframework.aop.IntroductionInterceptor
2、定义切点和通知者:在Spring配制文件中配置这些信息
3、使用ProxyFactoryBean来生成代理
- 创建通知advice
- 定义切入点pointcut和通知
要想实现Spring AOP 仅仅针对某一指定的方法进行切面编程,而不是针对所有的方法进行切面编程,那么需要指定切入点(pointcut) ,pointcut通过制定方法名进行拦截方法,同时pointcut必须advisor进行关联。pointcut可以通过指定完全方法名或通过正则表达式进行匹配方法。
- 定义一个通过完全方法名匹配方法的切入点
<bean id="namePointCut" class="org.springframework.aop.support.NameMatchMethodPointcut"> <property name="mappedName" value="insertTestStudent" /> </bean>
org.springframework.aop.support.NameMatchMethodPointcut:表示该切点通过直接通过完全方法名匹配方法的,property中的value就是完整的方法名。
- 通过正则表达式匹配方法
<bean id="addGuideIntegralAfterTesting" class="org.springframework.aop.support.JdkRegexpMethodPointcut"> <property name="pattern" value=".*insertTestStudent"/> </bean>
结合通知者advisor
<bean id="audienceAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"> <property name="advice" ref="audienceAdvice" /> <property name="pointcut" ref="performancePointcut" /> </bean>
org.springframework.aop.support.DefaultPointcutAdvisor是个通知者类,他只是把通知关联给切入点
- 联合切入点
联合切入点是比较特殊的正则表达式切入点,他同时结合了切入点和通知者
<bean id="addGuideIntegralAfterTesting" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice" ref="guideIntegralAfterAdvice" /> <property name="patterns"> <list> <value>.*insertTestStudent</value> </list> </property> </bean>
- AspectJ 切点
从AspectJ里定义切点的方式就可以看出AspectJ的切点语言是一种真正的切点表达语言。 类org.springframework.aop.aspectj.AspectJExpressionPointcut被用来定义AspectJ切点表达式
<bean id="performancePointcut" class="org.springframework.aop.aspectj.AspectJExpressionPointcut"> <property name="expression" value="execution(* Performer+.perform(..))" /> </bean>
通过使用DefaultPointcutAdvisor把切入点和通知者结合起来。我们可以利用特殊的通知者,把切点表达式定义为通知者的一个属性。对于AspectJ表达式来说,使用的通知者类是org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor:
<bean id="audienceAdvisor" class="org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor"> <property name="advice" ref="audienceAdvice" /> <property name="expression" value="execution(* Performer+.perform(..))" /> </bean>
通知者把通知与切点关联起来,从而完整地定义一个切面。
- Spring 代理
切面在Spring里是以代理方式实现的,所以仍然需要代理目标Bean才能让通知者发挥作用,以下有两种方式显示代理,一通过ProxyFactoryBean方式或者通过自动代理。
<!--定义个联合代理--> <bean id="addIntegralAutoProxyAop" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames"> <list> <!--需要监听的接口--> <value>guideStudentService</value> </list> </property> <property name="interceptorNames"> <list> <!-- 与第一个bean的id相匹配 --> <value>addGuideIntegralAfterTesting</value> </list> </property> </bean>
- ProxyFactoryBean代理
Spring的ProxyFactoryBean是个工厂Bean,用于生成一个代理,把一个或多个通知者应用到Bean
<bean id="duke" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="dukeTarget" /> <property name="interceptorNames"> <list> <value>audienceAdvisor</value> </list> </property> </bean>
- 自动代理
1、基于Spring上下文里声明的通知者Bean的基本自动代理”:通知者的切点表达式用于决定哪个Bean和哪个方法要被代理。
2、基于@AspectJ注解驱动切面的自动代理”:切面里包含的通知里指定的切点将用于选择哪个Bean和哪个方法要被代理。
<!--定义个联合代理--> <bean id="addIntegralAutoProxyAop" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames"> <list> <!--需要监听的接口--> <value>guideStudentService</value> </list> </property> <property name="interceptorNames"> <list> <!-- 与第一个bean的id相匹配 --> <value>addGuideIntegralAfterTesting</value> </list> </property> </bean>
- 完整的配置信息
<!-- 定义通知advice --> <bean id="guideIntegralAfterAdvice" class="com.rrtong.interceptors.GuideIntegralAfterAdvice" /> <!-- 定义pointcut和通知者advisor的联合切入点和通知者 --> <bean id="addGuideIntegralAfterTesting" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <!-- 引用通知接口的实现类 --> <property name="advice" ref="guideIntegralAfterAdvice" /> <!-- 正则表达式匹切入点方法名 --> <property name="patterns"> <list> <value>.*insertTestStudent</value> </list> </property> </bean> <!-- 定义自动代理 --> <bean id="addIntegralAutoProxyAop" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames"> <list> <value>guideStudentService</value> </list> </property> <property name="interceptorNames"> <list> <value>addGuideIntegralAfterTesting</value> </list> </property> </bean>
- 通知Advice
- 连接点Joinpoint
joinpoint就是程序执行过程中能够插入到切面的一个点,这个点就是方法被调用时,异常抛出时,甚至字段被编辑时。切面代码通过这个点插入到程序的一般流程中,从而添加新的行为。
- 切入点Pointcut
pointcut作用就是缩小切面通知范围
- 切面Aspect
- 目标Target
- 代理Proxy
- 织入Weaving
- 参考资料
http://blog.csdn.net/sin90lzc/article/details/7486145
http://blog.163.com/zzf_fly/blog/static/209589158201382314454298/
http://blog.csdn.net/topwqp/article/details/8695180