Spring 在XML中声明切面/AOP
Posted gccbuaa
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring 在XML中声明切面/AOP相关的知识,希望对你有一定的参考价值。
在Spring的AOP配置命名空间中,我们能够找到声明式切面选择。看以下:
<aop:config> <!-- AOP定义開始 --> <aop:pointcut/> <!-- 定义切入点 --> <aop:advisor/> <!-- 定义AOP通知器 --> <aop:aspect> <!-- 定义切面開始 --> <aop:pointcut/> <!-- 定义切入点 --> <aop:before/> <!-- 前置通知 --> <aop:after-returning/> <!-- 后置返回通知 --> <aop:after-throwing/> <!-- 后置异常通知 --> <aop:after/> <!-- 后置通知(无论通知的方法是否运行成功) --> <aop:around/> <!-- 围绕通知 --> <aop:declare-parents/> <!-- 引入通知 --> </aop:aspect> <!-- 定义切面结束 --> </aop:config> <!-- AOP定义结束 -->
一、声明切面
切面就是包括切入点和通知的对象,在Spring容器中将被定义为一个Bean。Schema方式的切面须要一个切面支持Bean,该支持Bean的字段和方法提供了切面的状态和行为信息,并通过配置方式来指定切入点和通知实现。
切面使用<aop:aspect>标签指定,ref属性用来引用切面支持Bean。
切面支持Bean“aspectSupportBean”跟普通Bean全然一样使用。切面使用“ref”属性引用它。
二、 声明切入点
切入点在Spring中也是一个Bean。Bean定义方式能够有非常三种方式:
1)在<aop:config>标签下使用<aop:pointcut>声明一个切入点Bean,该切入点能够被多个切面使用。对于须要共享使用的切入点最好使用该方式,该切入点使用id属性指定Bean名字。在通知定义时使用pointcut-ref属性通过该id引用切入点。expression属性指定切入点表达式:
<aop:config> <aop:pointcut expression="execution(* cn.com.ztz.spring.service.ShowServiceImpl.*(..))" id="pointcut"/> <aop:aspect ref="audienceAspect" > <aop:before pointcut-ref="pointcut" method="taskSeats"/> </aop:aspect> </aop:config>2)在<aop:aspect>标签下使用<aop:pointcut>声明一个切入点Bean,该切入点能够被多个切面使用,但一般该切入点仅仅被该切面使用,当然也能够被其它切面使用,但最好不要那样使用,该切入点使用id属性指定Bean名字,在通知定义时使用pointcut-ref属性通过该id引用切入点。expression属性指定切入点表达式:
<aop:config> <aop:aspect ref="audienceAspect" > <aop:pointcut expression="execution(* cn.com.ztz.spring.service.ShowServiceImpl.*(..))" id="pointcut"/> <aop:before pointcut-ref="pointcut" method="taskSeats"/> </aop:aspect> </aop:config>
3)匿名切入点Bean。能够在声明通知时通过pointcut属性指定切入点表达式,该切入点是匿名切入点,仅仅被该通知使用:
<aop:config> <aop:aspect ref="audienceAspect" > <aop:before pointcut="execution(* cn.com.ztz.spring.service.ShowServiceImpl.*(..))" method="taskSeats"/> </aop:aspect> </aop:config>
三、 声明通知
package cn.com.ztz.spring.service; public interface ShowService { public void show(); }
package cn.com.ztz.spring.service; public class ShowServiceImpl implements ShowService{ @Override public void show() { showBefore(); //showError();//异常測试 showEnd(); } public void showBefore(){ System.out.println("showBefore============"); } public void showError(){ System.out.println("showError============"); throw new RuntimeException(); } public void showEnd(){ System.out.println("showEnd==============="); } }
package cn.com.ztz.spring.service; public class AudienceAspect { public void taskSeats(){ System.out.println("等候节目開始==="); } public void applaud(){ System.out.println("鼓掌========="); } public void demandRefund(){ System.out.println("退钱离场======"); } }
<bean id="showService" class="cn.com.ztz.spring.service.ShowServiceImpl"/> <bean id="audienceAspect" class="cn.com.ztz.spring.service.AudienceAspect"/> <aop:config> <aop:pointcut id="pointcut" expression="execution(* cn.com.ztz.spring.service.ShowServiceImpl.*(..))"/> <aop:aspect ref="audienceAspect" > <aop:before pointcut-ref="pointcut" method="taskSeats"/> <aop:after-returning pointcut-ref="pointcut" method="applaud"/> <aop:after-throwing pointcut-ref="pointcut" method="demandRefund"/> </aop:aspect> </aop:config>
public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); ShowService hs = ctx.getBean("showService", ShowService.class); System.out.println("======================================"); hs.show(); System.out.println("======================================"); }控制台输出结果:
等候节目開始===
showBefore============
showEnd===============
鼓掌=========
======================================
四、 为通知传递參数
public interface ShowService { public void showBefore(String param); }
public class ShowServiceImpl implements ShowService{ public void showBefore(String param){ System.out.println("showBefore============"); } }
<pre name="code" class="java">public class AudienceAspect { public void taskSeats(String param){ System.out.println(param+",等候节目開始==="); } }
<bean id="showService" class="cn.com.ztz.spring.service.ShowServiceImpl"/> <bean id="audienceAspect" class="cn.com.ztz.spring.service.AudienceAspect"/> <aop:config> <aop:aspect ref="audienceAspect" > <aop:before pointcut="execution(* cn.com.ztz.spring.service.ShowServiceImpl.*(..)) and args(param)" method="taskSeats(java.lang.String)" arg-names="param"/> </aop:aspect> </aop:config>
public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); ShowService hs = ctx.getBean("showService", ShowService.class); System.out.println("======================================"); hs.showBefore("张三"); System.out.println("======================================"); }控制台输出结果:
张三,等候节目開始===
showBefore============
======================================
五、 声明围绕通知
围绕着在切入点选择的连接点处的方法所运行的通知。围绕通知很强大,能够决定目标方法是否运行,什么时候运行,运行时是否须要替换方法參数,运行完成是否须要替换返回值,可通过<aop:aspect>标签下的<aop:around >标签声明:public interface ShowService { public void showAround(String param); }
public class ShowServiceImpl implements ShowService{ public void showAround(String param){ System.out.println("showAround============"+param); } }
public class AudienceAspect { public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable { System.out.println("around before advice==========="); Object retVal = pjp.proceed(new Object[] {"around"}); System.out.println("around after advice==========="); return retVal; } }
<bean id="showService" class="cn.com.ztz.spring.service.ShowServiceImpl"/> <bean id="audienceAspect" class="cn.com.ztz.spring.service.AudienceAspect"/> <aop:config> <aop:aspect ref="audienceAspect" > <aop:around pointcut="execution(* cn.com.ztz.spring.service.ShowServiceImpl.*(..))" method="aroundAdvice"/> </aop:aspect> </aop:config>
public static void main(String[] args) { <span style="white-space:pre"> </span>ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); ShowService hs = ctx.getBean("showService", ShowService.class); System.out.println("======================================"); hs.showAround("张三"); System.out.println("======================================"); }控制台输出结果:
around before advice===========
showAround============around
around after advice===========
======================================
六、引入
它们可以不用直接改动对象或类的定义可以为对象或类添加新的方法。不幸的是。java不是动态的语言,一旦编译完毕了。我们非常难再为该类加入新的功能了。
<aop:declare-parents
types-matching="AspectJ语法类型表达式"
implement-interface=引入的接口"
default-impl="引入接口的默认实现"
delegate-ref="引入接口的默认实现Bean引用"/>
public interface DeclareService { public void declare(); }
public class DeclareServiceImpl implements DeclareService { @Override public void declare() { System.out.println("declare====================="); } }
<bean id="showService" class="cn.com.ztz.spring.service.ShowServiceImpl"/> <bean id="declareService" class="cn.com.ztz.spring.service.DeclareServiceImpl"/> <aop:config> <aop:aspect> <aop:declare-parents types-matching="cn.com.ztz.spring.service.ShowServiceImpl+" implement-interface="cn.com.ztz.spring.service.DeclareService" delegate-ref="declareService"/> </aop:aspect> </aop:config>
public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); DeclareService hs = ctx.getBean("showService", DeclareService.class); System.out.println("======================================"); hs.declare(); System.out.println("======================================"); }
我们获得还是showService的Bean,执行下測试方法输出结果:
declare=====================
======================================