1. 程式人生 > >Spring_第四章【AspectJ的AOP】

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