Spring_第四章【AspectJ的AOP】
1:什麼是AspectJ的aop
AspectJ是一個(AOP)面向切面的框架,它擴充套件了Java語言。AspectJ定義了AOP語法,所以它有一個專門的編譯器用來生成遵守Java位元組編碼規範的Class檔案。spring2.0之後新增了對AspectJ的支援
AspectJ支援Java註解和xml配置
@Before 前置通知,相當於BeforeAdvie(用於許可權驗證)
@AfterReturning 後置通知,相當於AfterReturningAdvie (操作日誌記錄)
@Around環繞通知,相當於MethodInterceptor(事務開啟關閉)
@AfterThrowing異常通知,相當於ThrowAdvie(用於許可權驗證)
@After 最終通知,跟finally類似(用於許可權驗證)
execution(<訪問修飾符> <返回值型別> <方法名>(<引數>)<異常>)
execution(public **(..))
2:怎麼使用AspectJ的aop
2.1基於AspectJ註解的方式實現AOP
目標類程式碼
package com.thit.aspectj1; public class userdao { public String add(){ System.out.println("新增方法!"); return "OMG!"; } public void select(){ int i=0/0; System.out.println("查詢方法!"); } public void update(){ System.out.println("修改方法!"); } public String delete(){ System.out.println("刪除方法!"); return "CNM"; } }
切面類程式碼:
package com.thit.aspectj1; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.After; /** * * @author 79027 切面類 */ @Aspect public class aspectj { // 前置通知 @Before("execution (* com.thit.aspectj1.userdao.ad*(..))") public void before(JoinPoint j) { System.out.println("前置通知" + j); // 前置通知execution(void com.thit.aspectj1.userdao.add()) } // 後置通知,returning定義方法返回值 @AfterReturning(value = "execution (* com.thit.aspectj1.userdao.add(..))", returning = "obj") public void After(Object obj) { System.out.println("後置通知"); System.out.println("後置通知接受方法引數:" + obj); } // 環繞通知,returning定義方法返回值 @Around(value = "execution (* com.thit.aspectj1.userdao.delete(..))") public Object Around(ProceedingJoinPoint joinPoint) { System.out.println("---環繞通知之前---"); Object o = null; try { // 如果沒有joinPoint.proceed,則目標方法不會執行 o = joinPoint.proceed(); System.out.println("目標方法返回值:" + o); } catch (Throwable e) { // TODO Auto-generated catch block e.printStackTrace(); } // 執行目標方法 System.out.println("---環繞通知之後---"); return o; } // 異常通知 @AfterThrowing(value = "execution (* com.thit.aspectj1.userdao.select(..))", throwing = "excption") public void AfterThrowing(Throwable excption) { System.out.println("---異常通知---:" + excption); } // 最終通知 @After(value = "execution (* com.thit.aspectj1.userdao.select(..))") public void After() { System.out.println("---最終無論是否有異常---"); } }
切面程式碼類優化
package com.thit.aspectj1;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.After;
/**
*
* @author 79027 切面類
*/
@Aspect
public class aspectj {
// 前置通知
@Before("p1()")
public void before(JoinPoint j) {
System.out.println("前置通知" + j);
// 前置通知execution(void com.thit.aspectj1.userdao.add())
}
// 後置通知,returning定義方法返回值
@AfterReturning(value = "p2()", returning = "obj")
public void After(Object obj) {
System.out.println("後置通知");
System.out.println("後置通知接受方法引數:" + obj);
}
// 環繞通知,returning定義方法返回值
@Around(value = "p3()")
public Object Around(ProceedingJoinPoint joinPoint) {
System.out.println("---環繞通知之前---");
Object o = null;
try {
// 如果沒有joinPoint.proceed,則目標方法不會執行
o = joinPoint.proceed();
System.out.println("目標方法返回值:" + o);
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
} // 執行目標方法
System.out.println("---環繞通知之後---");
return o;
}
// 異常通知
@AfterThrowing(value = "p4()", throwing = "excption")
public void AfterThrowing(Throwable excption) {
System.out.println("---異常通知---:" + excption);
}
// 最終通知
@After(value = "p5()")
public void After() {
System.out.println("---最終無論是否有異常---");
}
//用於隔離大量額切點配置,隨著程式碼增加只需要更改這兩部分即可,便於維護
@Pointcut("execution (* com.thit.aspectj1.userdao.ad*(..))")
private void p1() {};
@Pointcut(value = "execution (* com.thit.aspectj1.userdao.add(..))")
private void p2() {};
@Pointcut(value = "execution (* com.thit.aspectj1.userdao.delete(..))")
private void p3() {};
@Pointcut(value = "execution (* com.thit.aspectj1.userdao.delete(..))")
private void p4() {};
@Pointcut(value = "execution (* com.thit.aspectj1.userdao.select(..))")
private void p5() {};
}
xml配置檔案
<!--開啟aspectJ的自動代理 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!--目標類 -->
<bean id="userdao" class="com.thit.aspectj1.userdao"></bean>
<!--切面類-->
<bean class="com.thit.aspectj1.aspectj"></bean>
測試方法:
public void test1() {
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
userdao u=(userdao) context.getBean("userdao");
u.add();
System.out.println("----------------------------------------------");
u.delete();
System.out.println("----------------------------------------------");
u.update();
System.out.println("----------------------------------------------");
u.select();
}
輸出結果:
----------------------------------------------
前置通知execution(String com.thit.aspectj1.userdao.add())
新增方法!
後置通知
後置通知接受方法引數:OMG!
----------------------------------------------
---環繞通知之前---
刪除方法!
目標方法返回值:CNM
---環繞通知之後---
----------------------------------------------
修改方法!
----------------------------------------------
---最終無論是否有異常---
---異常通知---:java.lang.ArithmeticException: / by zero
2.2基於配置實現AspectJ的AOP
目標類程式碼
package com.thit.aspectj2xml;
public class userdao {
public String add(){
System.out.println("新增方法!");
return "OMG!";
}
public void select(){
int i=0/0;
System.out.println("查詢方法!");
}
public void update(){
System.out.println("修改方法!");
}
public String delete(){
System.out.println("刪除方法!");
return "CNM";
}
}
切面類程式碼:
package com.thit.aspectj2xml;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.After;
/**
*
* @author 79027 切面類
*/
@Aspect
public class aspectj {
// 前置通知
public void before(JoinPoint j) {
System.out.println("前置通知" + j);
// 前置通知execution(void com.thit.aspectj1.userdao.add())
}
// 後置通知,returning定義方法返回值
public void Afterreturning(Object return1) {
System.out.println("後置通知");
System.out.println("後置通知接受方法引數:" + return1);
}
// 環繞通知,returning定義方法返回值
public Object Around(ProceedingJoinPoint joinPoint) {
System.out.println("---環繞通知之前---");
Object o = null;
try {
// 如果沒有joinPoint.proceed,則目標方法不會執行
o = joinPoint.proceed();
System.out.println("目標方法返回值:" + o);
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
} // 執行目標方法
System.out.println("---環繞通知之後---");
return o;
}
// 異常通知
public void AfterThrowing1(Throwable excption) {
System.out.println("---異常通知---:" + excption);
}
// 最終通知
public void After() {
System.out.println("---最終無論是否有異常都會執行---");
}
}
xml配置檔案
<!--目標類 -->
<bean id="userdao" class="com.thit.aspectj2xml.userdao"></bean>
<!--切面類 -->
<bean id="aspectj" class="com.thit.aspectj2xml.aspectj"></bean>
<!-- AOP配置 -->
<aop:config>
<!--配置切入點 execution (* com.thit.aspectj1.userdao.ad*(..)) -->
<aop:pointcut expression="execution (* com.thit.aspectj2xml.userdao.add(..))" id="pointcut1" />
<aop:pointcut expression="execution (* com.thit.aspectj2xml.userdao.ad*(..))" id="pointcut2" />
<aop:pointcut expression="execution (* com.thit.aspectj2xml.userdao.delete(..))" id="pointcut3" />
<aop:pointcut expression="execution (* com.thit.aspectj2xml.userdao.sel*(..))" id="pointcut4" />
<aop:pointcut expression="execution (* com.thit.aspectj2xml.userdao.sel*(..))" id="pointcut5" />
<!--配置切面 -->
<aop:aspect ref="aspectj">
<aop:before method="before" pointcut-ref="pointcut1"/>
<aop:after-returning method="Afterreturning" pointcut-ref="pointcut2" returning="return1"/>
<aop:around method="Around" pointcut-ref="pointcut3" />
<aop:after-throwing method="AfterThrowing1" pointcut-ref="pointcut4" throwing = "excption"/>
<aop:after method="After" pointcut-ref="pointcut4"/>
</aop:aspect>
</aop:config>
執行結果:
----------------------------------------------
前置通知execution(String com.thit.aspectj2xml.userdao.add())
新增方法!
後置通知
後置通知接受方法引數:OMG!
----------------------------------------------
---環繞通知之前---
刪除方法!
目標方法返回值:CNM
---環繞通知之後---
----------------------------------------------
修改方法!
----------------------------------------------
---最終無論是否有異常都會執行---
---異常通知---:java.lang.ArithmeticException: / by zero