AspectJ是1個基于Java語言的AOP框架
Spring2.0以后新增了對AspectJ切點表達式支持
@AspectJ 是AspectJ1.5新增功能,通過JDK5注解技術,允許直接在Bean類中定義切面,所以可使用xml方式和注解方式來開發AOP
新版本Spring框架,建議使用AspectJ方式來開發AOP
aspectj有5種通知
before( Formals )
前置通知(在方法履行前履行,如果通知拋出異常,禁止方法運行)
after( Formals ) returning [ ( Formal ) ]
后置通知(方法正常返回后履行,如果方法中拋出異常,通知沒法履行
必須在方法履行后才履行,所以可以取得方法的返回值。)
after( Formals ) throwing [ ( Formal ) ]
異常停止(方法拋出異常后履行,如果方法沒有拋出異常,沒法履行)
after( Formals )
終究通知(方法履行終了后履行,不管方法中是不是出現異常,類似try-catch-finally里面的finally塊)
around( Formals )
環繞通知( 方法履行前后分別履行,可以禁止方法的履行,必須手動履行目標方法)
在xml中對應:
導入的jar包:
1.aop同盟規范
2.spring aop實現
3.aspect規范
4.spring aspect實現
編寫進程:
1.目標類:實現+接口
2.切面類:編寫多個通知
3.aop編程,將通知利用到目標類
4.測試
目標類:
接口
public interface UserService {
public boolean addUser();
public void updateUser();
public void deleteUser();
}
實現
public class UserServiceImpl implements UserService {
@Override
public boolean addUser() {
System.out.println("UserServiceDaoImpl addUser");
return true;
}
@Override
public void updateUser() {
//測試拋出異常通知
// int i=1/0;
System.out.println("UserServiceDaoImpl updateUser");
}
@Override
public void deleteUser() {
System.out.println("UserServiceDaoImpl deleteUser");
}
}
切面類
5種通知對方法的方法名稱沒有限制,但是方法的格式有限制。方法的格式會在xml配置中給出。
public class MyAspect {
//前置通知
public void before(JoinPoint joinPoint){
System.out.println("MyAspect-before");
}
//終究通知
public void after(JoinPoint joinPoint){
System.out.println("MyAspect-after");
}
//環繞通知
public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("MyAspect-around-前");
Object obj=joinPoint.proceed();//履行目標方法
System.out.println("MyAspect-around-后");
return obj;
}
//后置通知
public void afterReturning(JoinPoint joinPoint,Object ret){
System.out.println("MyAspect-afterReturning "+joinPoint.getSignature().getName()+"\t"+ret);
}
//異常通知
public void afterThrowing(JoinPoint joinPoint,Throwable e){
System.out.println("MyAspect-afterThrowing "+e.getMessage());
}
}
spring配置
<?xml version="1.0" encoding="UTF⑻"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 創建目標類 -->
<bean id="userServiceId" class="com.scx.xmlproxy.test.UserServiceImpl"></bean>
<!-- 創建切面類(通知) -->
<bean id="myAspectId" class="com.scx.xmlproxy.test.MyAspect"></bean>
<!-- aop編程-->
<aop:config proxy-target-class="true">
<aop:aspect ref="myAspectId">
<aop:pointcut expression="execution(* com.scx.xmlproxy.test.*.*(..))" id="myPointCut"/>
<!-- 前置通知
<aop:before method="before" pointcut-ref="myPointCut"/>
方法格式(參數1)
參數1:連接點描寫
method:方法名
pointcut:切入點表達式
pointcut-ref:切入點援用
-->
<!-- 終究通知
<aop:after method="after" pointcut-ref="myPointCut"/>
方法格式(參數1)
參數1:連接點描寫
-->
<!-- 環繞通知
<aop:around method="around" pointcut-ref="myPointCut"/>
方法格式(參數1)
參數:org.aspectj.lang.ProceedingJoinPoint
-->
<!-- 后置通知
<aop:after-returning method="afterReturning" returning="ret" pointcut-ref="myPointCut"/>
方法格式(參數1,參數2)
參數1:連接點描寫
參數2:類型Object,參數名 returning="ret" 配置的
-->
<!--
拋出異常
<aop:after-throwing method="afterThrowing" pointcut-ref="myPointCut" throwing="e"/>
方法格式(參數1,參數2)
參數1:連接點描寫對象
參數2:取得異常信息,類型Throwable ,參數名由throwing="e" 配置
-->
</aop:aspect>
</aop:config>
</beans>
測試:
測試時,最好只履行1個通知,否則結果會和想象的不1樣orz.
@org.junit.Test
public void testProxy(){
String xmlPath="com/scx/xmlproxy/test/applicationContext.xml";
ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath);
UserService userService=(UserService) applicationContext.getBean("userServiceId");
userService.addUser();
userService.updateUser();
userService.deleteUser();
}
測試結果:
前置通知:
后置通知:
異常通知:
為了出現異常我在實現類的updateUser方法里面里面添加了int i = 1 /0;
這行代碼
結果如圖所示輸出了除0的異常
這時候候我們修改成終究通知。運行結果:
我們發現updateUser方法沒有由于異常輸出,但是終究通知輸出了。
環繞通知:
注解小例子在寫篇文章給出~