二、Spring AOP 切面的定義
阿新 • • 發佈:2018-11-15
學習內容
Spring AOP 切面的定義
Spring AOP定義切面有多種方式,例如
1、使用@AspectJ註解
2、使用<aop:aspect>標籤
3、使用<aop:advisor>標籤
4、使用Advisor類
一、使用@AspectJ註解
a、在配置檔案中加<aop:aspectj-autoproxy>
b、編寫切面類
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import java.util.Arrays; @Component @Aspect public class LogAspect { private final String POINT_CUT = "execution(public * com.congrong.service.*.*(..))"; @Pointcut(POINT_CUT) public void pointCut(){} /** * 切點方法之前執行 * @param joinPoint */ @Before(value = "pointCut()") public void before(JoinPoint joinPoint){ System.out.println("@Before通知執行"); } /** * 切點方法之後執行 * @param joinPoint */ @After(value = POINT_CUT) public void doAfterAdvice(JoinPoint joinPoint){ System.out.println("After通知執行"); } /** * 切點方法返回後執行 * 如果第一個引數為JoinPoint,則第二個引數為返回值的資訊 * 如果第一個引數不為JoinPoint,則第一個引數為returning中對應的引數 * returning:限定了只有目標方法返回值與通知方法引數型別匹配時才能執行後置返回通知,否則不執行, * 引數為Object型別將匹配任何目標返回值 * @param joinPoint * @param result */ @AfterReturning(value = POINT_CUT,returning = "result") public void doAfterReturningAdvice(JoinPoint joinPoint,Object result){ System.out.println("AfterReturning通知執行"); } /** * 切點方法拋異常執行 * 定義一個名字,該名字用於匹配通知實現方法的一個引數名,當目標方法丟擲異常返回後,將把目標方法丟擲的異常傳給通知方法; * throwing:限定了只有目標方法丟擲的異常與通知方法相應引數異常型別時才能執行後置異常通知,否則不執行, * 對於throwing對應的通知方法引數為Throwable型別將匹配任何異常。 * @param joinPoint * @param exception */ @AfterThrowing(value = POINT_CUT,throwing = "exception") public void doAfterThrowingAdvice(JoinPoint joinPoint,Throwable exception){ System.out.println("AfterThrowing通知執行"); if(exception instanceof NullPointerException){ System.out.println("NullPointerException!"); } } /** * 環繞通知: * Spring AOP的環繞通知會影響到AfterThrowing通知的執行,不要同時使用 * 環繞通知非常強大,可以決定目標方法是否執行,什麼時候執行,執行時是否需要替換方法引數,執行完畢是否需要替換返回值。 * 環繞通知第一個引數必須是org.aspectj.lang.ProceedingJoinPoint型別 * @param proceedingJoinPoint * @return */ @Around(value = POINT_CUT) public Object doAroundAdvice(ProceedingJoinPoint proceedingJoinPoint){ System.out.println("@Around環繞通知開始執行"); Object obj = null; try { obj = proceedingJoinPoint.proceed(); } catch (Throwable throwable) { throwable.printStackTrace(); } System.out.println("@Around環繞通知結束執行"); return obj; } }
二、使用<aop:aspect>標籤
<!-- 定義目標物件 --> <bean name="userDao" class="com.congrong.dao.UserDaoImpl" /> <!-- 定義切面 --> <bean name="logAspect" class="com.congrong.LogAspect" /> <!-- 配置AOP --> <aop:config> <!-- 定義切點函式 --> <aop:pointcut id="pointcut" expression="execution(* com.congrong.dao.*.*(..))" /> <!-- 配置切面--> <aop:aspect ref="logAspect"> <!-- 前置通知method 指定通知方法名,必須與logAspect中的相同pointcut 指定切點函式--> <aop:before method="before" pointcut-ref="pointcut" /> <!-- 返回通知 returning="returnVal" 定義返回值 必須與類中宣告的名稱一樣--> <aop:after-returning method="afterReturn"pointcut-ref="pointcut" returning="returnVal" /> <!-- 環繞通知 --> <aop:around method="around" pointcut-ref="pointcut" /> <!--異常通知 throwing="throwable" 指定異常通知錯誤資訊變數,必須與類中宣告的名稱一樣--> <aop:after-throwing method="afterThrowing"pointcut-ref="pointcut" throwing="throwable"/> <!--後置/最終通知 --> <aop:after method="after" pointcut-ref="pointcut"/> </aop:aspect> </aop:config>
三、使用<aop:advisor>標籤
與< aop:aspect>定義切面時不同的是,< aop:aspect>的通知只需要定義一般的bean就行,而
< aop:advisor>中引用的通知,必須實現Advice介面。
定義通知
//定義通知 public class LogAdvice implements MethodBeforeAdvice,AfterReturningAdvice{ @Override public void before(Method arg0, Object[] arg1, Object arg2)throws Throwable { System.out.println("開始列印日誌!"); } @Override public void afterReturning(Object arg0, Method arg1, Object[] arg2,Object arg3) throws Throwable { System.out.println("結束列印日誌!"); } }
配置
<bean id="logAdvice" class="com.congrong.LogAdvice"></bean>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.congrong.*.*(..))"/>
<aop:advisor advice-ref="logAdvice" pointcut-ref="pointcut"/>
</aop:config>
四、使用Advisor類
//定義一個介面
public interface UserDao {
void addUser();
}
//目標物件實現介面並重寫方法
public class UserDaoImpl implements UserDao {
@Override
public void addUser() {
System.out.println("新增使用者");
}
}
//實現增強類的介面
public class LogBefore implements MethodBeforeAdvice {
//arg0 目標類的方法
arg1 目標類的入引數
arg2 目標類
@Override
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
System.out.println("新增日誌");
}
}
ProxtyFactory以程式設計形式
public class Test {
public static void main(String[] args) throws Exception{
LogBefore log = new LogBefore();
UserDao userDao = new UserDaoImpl();
ProxyFactory proxyf = new ProxyFactory();
//設定目標物件
proxyf.setTarget(userDao);
//設定增強類物件
proxyf.addAdvice(log);
//獲得代理物件
UserDao up = proxyf.getProxy();
up.addUser();
}
}
ProxyFactoryBean通過xml配置代理。
<bean id="logBefore" class="com.cong.LogBefore"/>
<bean id="target" class="com.cong.UserDaoImpl"/>
<bean id="userDao" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyInterfaces="com.cong.UserDao"
p:interceptorNames="logBefore"
p:target-ref="target"/>