簡介
Aspect Oriented Programming(AOP)稱爲面向切面編程,在程序開發中主要用來解決一些系統層面上的問題,如日誌,事務,權限等等
相關概念
- 滿足OCP開閉原則:對程序擴展打開,對程序修改關閉
- Aspect(切面):通常是一個類,在切面中定義通知和切入點
- JointPoint(連接點):需要攔截的點(方法類型)
- PointCut(切入點):指定連接點的規則,規定連接點連接位置以及對連接點進行篩選
- Advice(通知):決定增強業務的內容,有before(前置),after(後置),afterReturning(最終),afterThrowing(異常),around(環繞)
搭建
- 依賴包 spring-aop
- AspectJ組件
a.aopalliance (aop聯盟規則)
b.spring-aspects(spring的aspectj集成包)
c.aspectj.weaver(AspectJ織入包)
連接點
自動記錄對應方法的信息
方法名:jointPoint.getSignature().getName()
目標對象:jointPoint.getTarget().getClass().getName()
代理對象:jointPoint.getThis().getClass().getName()
方法的返回值(後置通知,環繞通知,最終通知) 要在配置文件中配置返回值綁定到後置通知的參數上
使用
applicationContext.xml
<!--業務層-->
<bean id="userService" class="com.service.UserServiceImpl"></bean>
<bean id="proService" class="com.service.ProServiceImpl"></bean>
<!--切面-->
<bean id="myAspect" class="com.aop.MyAspect"></bean>
<!--配置切入點和切面-->
<aop:config>
<aop:pointcut id="xxx1" expression="bean(proService)"/>
<!--1.規定切面 -->
<aop:aspect ref="myAspect">
<!--2.切入點 切入的規則-->
<aop:pointcut id="xxx" expression="bean(*Service)"/>
<!--3.配置通知的時間點-->
<!--
1.前置通知before 在進入連接點之前執行
2.後置通知AfterReturning 連接點執行之後通知再執行
3.環繞通知Around 連接點執行的整個過程
4.異常通知AfterThrowing 在連接點拋出異常之後
5.最終通知After 無論方法是否異常都一定會執行
-->
<aop:before method="beforeLogin" pointcut-ref="xxx" ></aop:before>
<aop:after-returning method="afterRetuturningLogin" pointcut-ref="xxx" returning="returnVal"></aop:after-returning>
<aop:around method="around" pointcut-ref="xxx"></aop:around>
<aop:after-throwing method="afterThrowing" pointcut-ref="xxx" throwing="ex"></aop:after-throwing>
<aop:after method="after" pointcut="bean(*Service)" ></aop:after>
</aop:aspect>
</aop:config>
MyAspect.java(切面類)
public class MyAspect {
//前置通知
public void beforeLogin(JoinPoint jointPoint){
//方法名
System.out.println("=============開始進入前置通知===============");
System.out.println("攔截的方法名是===" + jointPoint.getSignature().getName());
System.out.println("目標對象是==="+jointPoint.getTarget().getClass().getName());
System.out.println("代理對象是====" + jointPoint.getThis().getClass().getName());
System.out.println("當前方法的參數" + Arrays.toString(jointPoint.getArgs()));
System.out.println("進入了方法前的時間是" + CommmonUtil.getTime());
System.out.println("=============前置通知結束===============");
}
//後置通知
public void afterRetuturningLogin(JoinPoint jointPoint,Object returnVal){
System.out.println("=============開始進入後置通知===============");
System.out.println("攔截的方法名是===" + jointPoint.getSignature().getName());
System.out.println("目標對象是==="+jointPoint.getTarget().getClass().getName());
System.out.println("代理對象是====" + jointPoint.getThis().getClass().getName());
System.out.println("當前方法的返回值是" + returnVal);
System.out.println("出方法的時間是" + CommmonUtil.getTime());
System.out.println("=============後置通知結束===============");
}
//環繞通知(本質就是代理原來的方法)
public Object around(ProceedingJoinPoint jointPoint) throws Throwable {
System.out.println("=============開始進入環繞通知===============");
System.out.println("攔截的方法名是===" + jointPoint.getSignature().getName());
System.out.println("目標對象是==="+jointPoint.getTarget().getClass().getName());
System.out.println("代理對象是====" + jointPoint.getThis().getClass().getName());
System.out.println("當前方法的參數" + Arrays.toString(jointPoint.getArgs()));
System.out.println("進入了方法前的時間是" + CommmonUtil.getTime());
Object returnVal = jointPoint.proceed();
System.out.println("當前方法的返回值是" + returnVal);
System.out.println("出方法的時間是" + CommmonUtil.getTime());
System.out.println("=============環繞通知結束===============");
return returnVal;
}
//異常通知
public void afterThrowing(JoinPoint jointPoint,Throwable ex){
System.out.println("=============開始進入異常通知===============");
System.out.println("攔截的方法名是===" + jointPoint.getSignature().getName());
System.out.println("目標對象是==="+jointPoint.getTarget().getClass().getName());
System.out.println("代理對象是====" + jointPoint.getThis().getClass().getName());
System.out.println("異常信息爲=====" + ex.getMessage());
System.out.println("異常時間是" + CommmonUtil.getTime());
System.out.println("=============異常通知結束===============");
}
//最終通知
public void after(JoinPoint jointPoint){
System.out.println("=============開始進入最終通知===============");
System.out.println("攔截的方法名是===" + jointPoint.getSignature().getName());
System.out.println("目標對象是==="+jointPoint.getTarget().getClass().getName());
System.out.println("代理對象是====" + jointPoint.getThis().getClass().getName());
System.out.println("最終的時間是" + CommmonUtil.getTime());
System.out.println("=============最終結束===============");
}
}
調用*Service實例中的方法則會完成AOP代理運行。