spring心得10--使用Aspectj進行AOP開發介紹及案例分析
1.使用Aspectj進行AOP開發
使用aspectjs的操作步驟:
1)新增類庫:aspectjrt.jar和aspectjweaver.jar
2)新增aop schema.
3)定義xml元素:<aop:aspectj-autoproxy>
4)編寫java類,並用@Aspect註解成通知
AspectJ支援 5 種型別的通知註解:
@Before: 前置通知, 在方法執行之前執行
@After: 後置通知, 在方法執行之後執行
@AfterReturning: 返回通知, 在方法返回結果之後執行
@AfterThrowing: 異常通知, 在方法丟擲異常之後
@Around: 環繞通知, 圍繞著方法執行
配置成普通bean元素即可;下面簡單介紹這幾種通知的術語和使用方式,後面會通過案例分析的方式來剖解aspectjs通知程式設計。
前置通知:@Before
@Aspect
public class AudienceAdvice {
@Before("execution(* WelcomeService.*(..))")
public void takeSeats(){..}
@Before("execution(* WelcomeService.*(..))")
public void turnOffCellphone(JoinPoint jp){..}
JoinPoint引數可訪問連線點細節,切入方法名和引數等.
jp.getTarget()//目標物件
jp.getThis()//當前的代理物件
jp.getArgs();//方法呼叫引數
jp.getSignature().getName()//方法簽名
後置通知:@After
@After("execution(* *..WelcomeService.*(..))")
public void applaud(){..}
後置通知在目標方法執行完成之後執行.一個切面aspect包含很多通知.後置通知表明目標方法執行完之後,不論是否拋異常,都會織入該通知.
返回通知:@AfterReturning
方法返回後通知只在目標方法返回以後執行,若拋異常不執行.
@AfterReturning(pointcut="",returning="res")
public void xxx(Joinput jp,Object res)
在AfterReturning通知中可接收到返回值.res即是用來接收返回值的物件.
環繞通知:@Around
@Around("execution(* *..WelcomeService.*(..))")
public void around(ProceedingPointCut jp){..}
注意:可以控制目標方法是否呼叫,以及返回完全不同的物件,要慎用.
指定優先順序:
@Aspect
@Order(0)
public class xxx{...}
加上@Order註解可以指定加入切面的優先順序(先後順序,值越小,優先順序越高)
典型Aspectj切入點表示式定義:
execution(* cn.itcast.WelcomeServiceImpl.*(..))
execution(public * *..WelcomeServiceImpl.*(..))
execution(public void *..WelcomeServiceImpl.*(*))
execution(public void *..*Service.*(double,double))..
切入點表示式運算(&& || !)
@Pointcut("execution(..) || execution(..)")
重用切入點定義
將切入點註解到一個空的方法體上,其它地方引用即可.
//定義切入點
@Pointcut("execution(* *..WelcomeService.*(..))")
public void performPoint(){}
@Before("performPoint()")
@After("performPoint()")
引入通知:
@Aspect
public class MyAspectjIntroduction {
@DeclareParents(value="*..*Service*", defaultImpl=ModifyDateImpl.class)
private ModifyDate md ;
}
value:指定哪些類可以應用該屬性
defaultImpl:指定介面的實現類
使用pojo+xml開發aop
基於註解的aspectj宣告優先於xml配置.
基於xml的配置是spring專有的.aspectj得到越來越多的支援,
具備更好的重用性.
2.Aspectj案例分析
下面通過兩個案例分別來闡釋兩種不同方法使用aspectj開發的專案;
首先列出這兩種方式都用到的目標抽象介面和抽象介面的實現類目標類UserService和UserServiceImpl;以及引用通知需要的介面和實現類
UserService.java
package www.csdn.spring.proxy.advice.aspectjs;
public interface UserService {
public void save(Object entity);
public void update(Object entity);
public void delete(Object entity);
public void getAllObjects();
}
UserServiceImpl.java
package www.csdn.spring.proxy.advice.aspectjs;
public class UserServiceImpl implements UserService {
@Override
public void save(Object entity) {
System.out.println("---儲存方法:save()---");
}
@Override
public void update(Object entity) {
System.out.println("---更新方法:update()---");
}
@Override
public void delete(Object entity) {
System.out.println("---刪除方法:delete()---");
//int i = 1/0;
}
@Override
public void getAllObjects() {
System.out.println("---查詢所有方法:getAllObjects()---");
}
}
下面是引用通知需要的介面和實現類:
Auditable.java
package www.csdn.spring.proxy.advice.aspectjs;
import java.util.Date;
public interface Auditable {
public void setDate(Date date);
public Date getDate();
}
AuditableImpl.java
package www.csdn.spring.proxy.advice.aspectjs;
import java.util.Date;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;
public class AuditableImpl extends DelegatingIntroductionInterceptor implements Auditable {
private Date date;
@Override
public void setDate(Date date) {
this.date = date;
}
@Override
public Date getDate() {
return date;
}
}
第一種方式:用的advice通知類:AdviceService.java
package www.csdn.spring.proxy.advice.aspectjs;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.junit.experimental.theories.Theory;
@Aspect
public class AdviceService {
//前置通知
@Before(value = "execution(* UserServiceImpl.save(..))")
public void beforeMethod(){
System.out.println("-------開啟事務-------");
}
//後置通知
@After(value = "execution(* www.csdn..UserServiceImpl.save(*))")
public void afterMethod(){
System.out.println("-------結束事務--------");
}
//環繞通知
@Around(value = "execution(* UserServiceImpl.update(*))")
public void aroundMethod(ProceedingJoinPoint pjp){
System.out.println("-=-=-=-=安全處理之前-=-=-=-");
try {
pjp.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("-=-=-=-=-=安全處理之後-=-=-=-=-");
}
//定義一個指定切入點位置的方法
@Pointcut("execution(* *..UserServiceImpl.delete(*))")
public void pointCuts(){}
//下面兩個通知引用該切入點方法
//異常通知
/*@AfterThrowing("pointCuts()")
public void throwsMethod(){
System.out.println("異常通知執行");
}*/
@AfterReturning("pointCuts()")
public void afterRuning(){
System.out.println("=========返回值========");
}
}
使用aspectj最重要的一個檔案,spring相關的配置檔案
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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,實際是aspectjs自動掃描所有bean,去找有切面的bean -->
<bean id="adviceService" class="www.csdn.spring.proxy.advice.aspectjs.AdviceService" />
<!-- 引入通知切面 -->
<bean id="auditableService" class="www.csdn.spring.proxy.advice.aspectjs.AuditableService" />
<!-- 真實主題 目標物件 -->
<bean id="userServiceImpl" class="www.csdn.spring.proxy.advice.aspectjs.UserServiceImpl" />
<!-- 使用aspectjs配置自動代理 -->
<aop:aspectj-autoproxy />
</beans>
測試類 AdviseTest.java
package www.csdn.spring.proxy.advice.aspectjs;
import java.util.Date;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AdviseTest {
@Test
public void testUser() {
ApplicationContext context = new ClassPathXmlApplicationContext(
"spring-aspectjs.xml");
// 代理主題角色,這裡用代理主題和真實主題實現的同樣介面類來接收建立的代理主題,就是建立一個目標類
UserService userService = context.getBean("userServiceImpl",
UserService.class);
userService.save(null);
/*userService.update(null);
try{
userService.delete(null);
}catch(Exception e){
}
userService.getAllObjects();*/
//引入通知測試
Auditable auditable = (Auditable) userService;
auditable.setDate(new Date());
System.out.println(auditable.getDate());
}
}
第二種方式 :使用pojo-xml編寫aspectj的通知類AdviceService.java
package www.csdn.spring.proxy.advice.aspectjs.pojoxml;
import org.aspectj.lang.ProceedingJoinPoint;
public class AdviceService {
//前置通知
public void beforeMethod(){
System.out.println("-------開啟事務-------");
}
//後置通知
public void afterMethod(){
System.out.println("-------結束事務--------");
}
//環繞通知
public void aroundMethod(ProceedingJoinPoint pjp){
System.out.println("-=-=-=-=安全處理之前-=-=-=-");
try {
pjp.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("-=-=-=-=-=安全處理之後-=-=-=-=-");
}
//異常通知
public void throwsMethod(){
System.out.println("異常通知執行");
}
//帶返回值的通知
public void afterRuning(){
System.out.println("=========返回值========");
}
}
使用pojo-xml aspectj最重要的一個檔案,spring相關的配置檔案
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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,實際是aspectjs自動掃描所有bean,去找有切面的bean -->
<bean id="adviceService"
class="www.csdn.spring.proxy.advice.aspectjs.pojoxml.AdviceService" />
<!-- 真實主題 目標物件 -->
<bean id="userServiceImpl"
class="www.csdn.spring.proxy.advice.aspectjs.pojoxml.UserServiceImpl" />
<!-- 使用pojo-xml aspectjs配置自動代理 -->
<aop:config>
<!-- 配置切面 -->
<aop:aspect ref="adviceService">
<!-- 引入通知 -->
<aop:declare-parents types-matching="*..*Service*"
implement-interface="www.csdn.spring.proxy.advice.aspectjs.pojoxml.Auditable"
default-impl="www.csdn.spring.proxy.advice.aspectjs.pojoxml.AuditableImpl" />
<!-- 切面切入的位置 切入點,可以同時寫多個不同的切入點 -->
<aop:pointcut expression="execution(* www.csdn..UserServiceImpl.save(..))"
id="myPcut" />
<aop:pointcut expression="execution(* www.csdn..UserServiceImpl.update(..))"
id="myPcuts" />
<!--織入通知 method:指明方法; pointcut-ref引入切入點 -->
<aop:before method="beforeMethod" pointcut-ref="myPcut" />
<aop:after method="afterMethod" pointcut-ref="myPcut" />
<aop:after method="afterRuning" pointcut-ref="myPcut" />
<aop:around method="aroundMethod" pointcut-ref="myPcuts" />
<aop:after-throwing method="throwsMethod" pointcut-ref="myPcuts"/>
</aop:aspect>
</aop:config>
</beans>
測試類 AdviseTest.java
package www.csdn.spring.proxy.advice.aspectjs.pojoxml;
import java.util.Date;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AdviseTest {
@Test
public void testUser() {
ApplicationContext context = new ClassPathXmlApplicationContext(
"spring-pojo*.xml");
// 代理主題角色,這裡用代理主題和真實主題實現的同樣介面類來接收建立的代理主題,就是建立一個目標類
UserService userService = context.getBean("userServiceImpl",
UserService.class);
userService.save(null);
userService.update(null);
//引入通知測試
Auditable auditable = (Auditable) userService;
auditable.setDate(new Date());
System.out.println(auditable.getDate());
}
}
相關文章
- Spring AOP介紹Spring
- AOP程式設計之AspectJ介紹及在Android中的應用程式設計Android
- 4、Spring+AOP介紹與使用Spring
- Spring AOP的AspectJ註解Spring
- 比較Spring AOP與AspectJSpring
- Spring AOP 使用介紹,從前世到今生Spring
- AOP - AspectJ
- Spring AOP 增強介紹Spring
- Spring事物入門簡介及AOP陷阱分析Spring
- Spring第9天Aop簡介,Aopxml開發,Aop註解開發SpringXML
- 在ORACLE中增進SCN及案例介紹Oracle
- Golang指標基本介紹及使用案例Golang指標
- spring心得8--AOP各種通知案例講解.docSpring
- Spring AOP AspectJ 切面表示式高階用法Spring
- Spring AOP與AspectJ的對比及應用Spring
- Spring基礎只是—AOP的概念介紹Spring
- 心得:Spring AOP和Decorator模式Spring模式
- Oracle認證介紹及入門心得Oracle
- java Spring Cloud企業快速開發架構之Spring Boot Starter的介紹及使用JavaCloud架構Spring Boot
- (7)Spring Boot Starter的介紹及使用Spring Boot
- Spring Reactor基本介紹和案例SpringReact
- spring心得9--自動代理知識點講解及案例分析Spring
- 淺嘗Spring註解開發_AOP原理及完整過程分析(原始碼)Spring原始碼
- 《AOP挖掘記》概念介紹及原理初探(一)
- 使用AI進行需求分析的案例研究AI
- spring心得6--自動裝配知識點講解及案例分析Spring
- spring-AOP(二)實現原理之AspectJ註解方式Spring
- Spring AOP 在 XML檔案中實現 AspectJ 攔截SpringXML
- Web專案開發介紹及實戰專案介紹Web
- 漸進式web應用開發---service worker 原理及介紹(一)Web
- 輕應用介紹 - 用JavaScript進行嵌入式開發JavaScript
- AspectJ 在 Spring 中的使用Spring
- Chainlink Functions 介紹 & 使用案例AIFunction
- vagrant介紹及使用
- 使用 Kotlin + Spring Boot 進行後端開發KotlinSpring Boot後端
- AOP程式設計實戰-AspectJ程式設計
- FreeSql aop功能介紹SQL
- Spring(2)-AOP簡介Spring