Spring(2)之 (2.2 使用 AspectJ實現 AOP)
在Spring AOP程式設計中:
分離了重複程式碼:關注點
關注點程式碼:產生類即切面類
一、使用 AspectJ實現 AOP(註解方式):
- 導包
spring-aop
spring-core
aspectjrt
aspectjweaver
aopalliance - 配置檔案(開啟代理模式)
開啟註解掃描
<context:component-scan base-package="com.asd"></context:component-scan>
開啟代理模式
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
- 切面類
@Component
@Aspect:說明這是一個切面類
@Before:業務程式碼之前執行
@After:業務程式碼之後執行,無論是否出現異常都執行
@AfterReturning:業務程式碼後執行,若出現異常不執行
@AfterThrowing:業務程式碼後,出現異常執行(即@AfterReturning與@AfterThrowing 兩者不會同時存在)
@Around:環繞業務程式碼,有引數joinPoint:joinPoint.proceed();方法proceed()相當於目標物件業務程式碼中的save(); - 切入點表示式(exection( * * . *(. .)))
exection( * * . *(. .))
exection( 返回型別 類的完全限定名. 方法名(引數))(返回型別前的修飾符如public可寫可不寫)
實現介面的類,Spring預設使用JDK代理;未實現介面的類,Spring預設使用Cglib代理
@Before("execution(public void com.asd.spring.UserDao.save())")
@After("execution(public void com.asd.spring.UserDao.save())")
二、使用 AspectJ實現 AOP(XML 方式):
① 介面實現類(UserDao.java)、未實現類(OrderDao.java)和切面類(MyAop.java)都不需要用註解;②
// eg:
<aop:config>
<!-- 切面類-->
<bean id="aop" class="com.asd.spring.MyAop"></bean>
<!-- 切入點 -->
<aop:pointcut id="pt" expression="execution(* *.*.*(..))"/>
<aop:aspect ref="aop">
<aop:before method="beginTrans" pointcut-ref="pt"/>
<aop:after method="commitTrans" pointcut-ref="pt"/>
<aop:after-returning method="afterReturning" pointcut-ref="pt"/>
<aop:after-throwing method="afterThrow" pointcut-ref="pt"/>
<aop:around method="around" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
eg: 1. 使用 AspectJ實現 AOP(註解方式)
1.1 IUserDao.java
public interface IUserDao{
public void save() throws Exception;
public void update() throws Exception;
}
1.2 UserDao.java
(此目標物件實現介面)
@Component("userDao")
public class UserDao implements IUserDao{
public void save() throws Exception{
System.out.println("----資料已儲存----");
// int i=1/0;
}
public void update() throws Exception{
System.out.println("----資料已修改----");
}
}
1.2(1) OrderDao.java
(新增一個OrderDao,不實現介面)
@Component("orderDao")
public class OrderDao{
public void update() throws Exception{
System.out.println("----修改訂單----");
}
}
1.3 MyAop.java
(① 目標物件提取後形成的單獨類:@Aspect註解表示這是一個切面類;@Before(“execution(public void com.asd.spring.UserDao.save())”) 是切入點表示式;② 若在UserDao.java中出現異常,此時@AfterReturning不執行;③ 為避免重複書寫切入點表示式,可以用@PointCut註解寫一個切入點方法,無需實現;後面註解中只需要引用方法即可,不需要再多次書寫切入點表示式;)
@Component
@Aspect
public class MyAop{
//@PointCut("execution(public void com.asd.spring.UserDao.save())")
@PointCut("execution(* *.*())")
public void pointCut(){
}
//@Before("execution(public void com.asd.spring.UserDao.save())")
@Before("pointCut()")
public void beginTrans(){
System.out.println("開始事務");
}
//@After("execution(public void com.asd.spring.UserDao.save())")
@After("pointCut()")
public void commitTrans(){
System.out.println("提交事務");
}
//@AfterReturning("execution(public void com.asd.spring.UserDao.save())")
@AfterReturning("pointCut()")
public void afterReturning(){
System.out.println("afterReturning");
}
//@AfterThrowing("execution(public void com.asd.spring.UserDao.save())")
@AfterThrowing("pointCut()")
public void afterThrow(){
System.out.println("afterThrow");
}
//@Around("execution(public void com.asd.spring.UserDao.save())")
@Around("pointCut()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("begin");
joinPoint.proceed();
System.out.println("end");
}
}
1.4 bean.xml
(xml檔案中有: xmlns:context、 xmlns:aop、xmlns:tx即context、aop、tx名稱空間, )
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 開啟註解掃描 -->
<context:component-scan base-package="com.asd"></context:component-scan>
<!-- 開啟代理模式 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
Test.java
public class Test{
public static void main(String[] args) {
ApplicationContext applicationContext=new ApplicationContext("bean.xml");
IUserDao userDao=(IUserDao)applicationContext.getBean("userDao");
System.out.println(userDao.getClass());//userDao物件(即實現介面的目標物件)型別
try{
userDao.save();
userDao.update();
}catch(Exception e){
e.printStackTrace();
}
System.out.println("-------------");
OrderDao orderDao=(OrderDao)applicationContext.getBean("orderDao");
System.out.println(orderDao.getClass());//orderDao物件(即沒有實現介面的目標物件)型別
try{
orderDao.update();
}catch(Exception e){
e.printStackTrace();
}
}
}
① MyAop.java切面類中只有 @Before、@After 註解時,執行結果:
② MyAop.java切面類中增加 @AfterReturning 註解後且無異常,執行結果: / 出現異常執行結果:
③ MyAop.java切面類中增加 @AfterThrowing 註解後且出現異常,執行結果:
④ MyAop.java切面類中增加 @Around 註解後執行結果:
⑤ 增加 OrderDao.java 類後,切面類 MyAop.java中切入點表示式方法只限定OrderDao(即未改為全部即 * )註解後執行結果:(沒有執行切入點程式碼)
⑤ 增加 OrderDao.java 類、且在UserDao.java類中新增 update() 方法,切面類 MyAop.java中切入點表示式方法為全部類和方法(即 * )後執行結果:(有執行切入點程式碼)
⑥ 輸出兩個物件userDao物件(實現介面)、orderDao物件(沒實現介面)執行結果:
userDao物件型別:class com.sun.proxy.$Proxy12
orderDao物件型別:class com.asd.spring.OrderDao $ $EnhancerBySpringCGLIB $ $ 87c00f1f
【 可看出實現介面的類Spring預設使用JDK代理,未實現介面的類Spring預設使用Cglib代理 】
二、使用 AspectJ實現 AOP(XML 方式):
(① 介面實現類(UserDao.java)、未實現類(OrderDao.java)和切面類(MyAop.java)都不需要用註解;② 不用註解的方式則xml中不需要開啟註解掃描和開啟代理模式,需要在 xml檔案中生成對應的 bean物件:xml 檔案中有生成UserDao、OrderDao、切面類MyAop物件;可以在< aop:before>標籤中用 pointcut屬性單獨書寫每一個切入點表示式;也可以在< aop:pointcut>用 expression屬性統一書寫切入點表示式, express屬性中可以用 “||”和“or”來寫多個表示式,再在< aop:before>標籤中用 pointcut-ref屬性引用它;)
2.1 IUserDao.java
public interface IUserDao{
public void save() throws Exception;
public void update() throws Exception;
}
2.2 UserDao.java
public class UserDao implements IUserDao{
public void save() throws Exception{
System.out.println("----資料已儲存----");
// int i=1/0;
}
}
2.2(1) OrderDao.java
public class OrderDao{
public void update() throws Exception{
System.out.println("----修改訂單----");
}
}
2.3 MyAop.java
public class MyAop{
public void beginTrans(){
System.out.println("開始事務");
}
public void commitTrans(){
System.out.println("提交事務");
}
public void afterReturning(){
System.out.println("afterReturning");
}
public void afterThrow(){
System.out.println("afterThrow");
}
public void around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("begin");
joinPoint.proceed();
System.out.println("end");
}
}
2.4 bean.xml
(xml 檔案中有生成UserDao、OrderDao、切面類MyAop物件,可以在< aop:before>標籤中用 pointcut屬性單獨書寫每一個切入點表示式;也可以在< aop:pointcut>用 expression屬性統一書寫切入點表示式, express屬性中可以用 “||”和“or”來寫多個表示式,再在< aop:before>標籤中用 pointcut-ref屬性引用它;)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 容器中建立UserDao、OrderDao物件 -->
<bean id="userDao" class="com.asd.spring.UserDao"></bean>
<bean id="orderDao" class="com.asd.spring.OrderDao"></bean>
<!-- 容器中建立切面類物件 -->
<bean id="aop" class="com.asd.spring.MyAop"></bean>
<!-- 切入點 -->
<aop:config>
//<aop:pointcut id="pt" expression="execution(* com.asd.UserDao.save(..))"/>//統一寫切入點表示式,再在下面pointcut-ref引用其id
//<aop:pointcut id="pt" expression="execution(* com.asd.UserDao.save(..)) ||execution(* com.asd.UserDao.update(..))"/>//用“||”和“or”都可以
<aop:pointcut id="pt" expression="execution(* *.*.*(..))"/>
<aop:aspect ref="aop">
//<aop:before method="beginTrans" pointcut="execution(* com.asd.UserDao.save(..))"/>//分開寫
<aop:before method="beginTrans" pointcut-ref="pt"/>
<aop:after method="commitTrans" pointcut-ref="pt"/>
<aop:after-returning method="afterReturning" pointcut-ref="pt"/>
<aop:after-throwing method="afterThrow" pointcut-ref="pt"/>
<aop:around method="around" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
</beans>
Test.java
在這裡插入程式碼片