1. 程式人生 > >Spring (二)AOP

Spring (二)AOP

AOP中關鍵性概念 : 連線點(Joinpoint):程式執行過程中明確的點,如方法的呼叫,或者異常的丟擲.

目標(Target):被通知(被代理)的物件 注1:完成具體的業務邏輯 通知(Advice):在某個特定的連線點上執行的動作,同時Advice也是程式程式碼的具體實現,例如一個實現日誌記錄的程式碼(通知有些書上也稱為處理) 注2:完成切面程式設計 代理(Proxy):將通知應用到目標物件後建立的物件(代理=目標+通知), 例子:外科醫生+護士 注3:只有代理物件才有AOP功能,而AOP的程式碼是寫在通知的方法裡面的 切入點(Pointcut):多個連線點的集合,定義了通知應該應用到那些連線點。

(也將Pointcut理解成一個條件 ,此條件決定了容器在什麼情況下將通知和目標組合成代理返回給外部程式)

介面卡(Advisor):介面卡=通知(Advice)+切入點(Pointcut)

如何實現AOP? 目標物件只負責業務邏輯程式碼 通知物件負責AOP程式碼,這二個物件都沒有AOP的功能,只有代理物件才有

AOP:

即面向切面程式設計

AOP帶來的好處:

讓我們可以 “專心做事”

案例: spring-context.xml配置檔案: 在這裡插入圖片描述 在這裡插入圖片描述

<!-- 目標物件 -->
	<bean class="com.zking.aop.biz.impl.BookBizImpl" id="bookBiz"></bean>
	
	<!-- 前置通知 -->
	<bean class="com.zking.aop.advice.MyMethodBeforeAdvice" id="myMethodBeforeAdvice"></bean>
	
	<!-- 後置通知 -->
	<bean class="com.zking.aop.advice.MyAfterReturningAdvice" id="myAfterReturningAdvice" ></bean>
	
	<!-- 環繞通知 -->
	<bean class="com.zking.aop.advice.MyMethodInterceptor" id="myMethodInterceptor"></bean>
	
	<!-- 異常通知 -->
	<bean class="com.zking.aop.advice.MyThrowsAdvice" id="myThrowsAdvice" ></bean>
	
	<!-- 過濾通知(介面卡) -->
	<bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="myAfterReturningAdvice2" >
		<property name="advice" ref="myAfterReturningAdvice" ></property>
		<!-- .*buy:[.*]任意字元0~n個,已buy結尾的方法 -->
		<property name="pattern" value=".*buy" ></property>
	</bean>
	
	<!-- 生成代理(目標物件+通知) -->
	<bean class="org.springframework.aop.framework.ProxyFactoryBean" id="proxyFactoryBean" >
		<!-- 目標 -->
		<property name="target" ref="bookBiz"></property>
		<!-- 代理工廠生產的代理需要實現的介面列表 -->
		<property name="proxyInterfaces"  >
			<list>
				<value>com.zking.aop.biz.IBookBiz</value>
			</list>
		</property>
		<!-- 通知 -->
		<property name="interceptorNames">
			<list>
				<value>myMethodBeforeAdvice</value>
				<!-- <value>myAfterReturningAdvice</value> -->
				<!-- <value>myAfterReturningAdvice2</value> -->
				<!-- <value>myMethodInterceptor</value> -->
				<!-- <value>myThrowsAdvice</value> -->
			</list>
		</property>

IBookBiz :

package com.zking.aop.biz;

public interface IBookBiz {
	// 購書
	public boolean buy(String userName, String bookName, Double price);

	// 發表書評
	public void comment(String userName, String comments);
}

BookBizImpl :

package com.zking.aop.biz.impl;

import com.zking.aop.biz.IBookBiz;
import com.zking.aop.ex.PriceException;

public class BookBizImpl implements IBookBiz {

	public BookBizImpl() {
		super();
	}

	public boolean buy(String userName, String bookName, Double price) {
		// 通過控制檯的輸出方式模擬購書
		if (null == price || price <= 0) {
			throw new PriceException("book price exception");
		}
		System.out.println(userName + " buy " + bookName + ", spend " + price);
		return true;
	}

	public void comment(String userName, String comments) {
		// 通過控制檯的輸出方式模擬發表書評
		System.out.println(userName + " say:" + comments);
	}

}

測試類: 在這裡插入圖片描述

1、前置通知

實現org.springframework.aop.MethodBeforeAdvice介面 例如:買書、評論前加系統日誌 在這裡插入圖片描述

package com.zking.aop.advice;

import java.lang.reflect.Method;
import java.util.Arrays;

import org.springframework.aop.MethodBeforeAdvice;

/**
 * 前置通知:
 * 呼叫專案中的某一介面實現類的方法時,將類名、方法名,攜帶的引數,作為日誌儲存到資料庫。
 * @author Administrator
 *
 */
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {

	public void before(Method method, Object[] args, Object target) throws Throwable {
		// TODO Auto-generated method stub
		String targetName = target.getClass().getName();
		String methodName = method.getName();
		String params = Arrays.toString(args);
		String msg = "[系統日誌]:正在呼叫--》"+targetName+"."+methodName+",攜帶的引數:"+params;
		System.out.println(msg);
		
	}

}

效果:在連線點之前執行的通知()

在這裡插入圖片描述

2、後置通知

實現org.springframework.aop.AfterReturningAdvice介面 買書返利(存在bug) 在這裡插入圖片描述

package com.zking.aop.advice;

import java.lang.reflect.Method;
import java.util.Arrays;

import org.springframework.aop.AfterReturningAdvice;

/**
 * 後置通知
 * @author Administrator
 *
 */
public class MyAfterReturningAdvice implements AfterReturningAdvice {

	public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
		// TODO Auto-generated method stub
		String targetName = target.getClass().getName();
		String methodName = method.getName();
		String params = Arrays.toString(args);
		String msg = "[後置通知]:返利   0$   --》"+targetName+"."+methodName+",攜帶的引數:"+params+",目標物件所呼叫的方法的返回值"+returnValue;
		System.out.println(msg);
	}

}

效果:在連線點之前執行的通知()

在這裡插入圖片描述

3、環繞通知

org.aopalliance.intercept.MethodInterceptor 類似過濾器,會包括切入點,目標類前後都會執行程式碼。

在這裡插入圖片描述

package com.zking.aop.advice;

import java.lang.reflect.Method;
import java.util.Arrays;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

/**
 * 環繞通知
 * @author Administrator
 *
 */
public class MyMethodInterceptor implements MethodInterceptor {

	public Object invoke(MethodInvocation invocation) throws Throwable {
		
		Object target = invocation.getThis();
		Method method = invocation.getMethod();
		Object[] args = invocation.getArguments();
		
		String targetName = target.getClass().getName();
		String methodName = method.getName();
		String params = Arrays.toString(args);
		String msg = "[環繞通知]:---  --》"+targetName+"."+methodName+",攜帶的引數:"+params;
		System.out.println(msg);
		
		Object returnValue = invocation.proceed();
		
		String msg2 = "[環繞通知]:---  --》"+targetName+"."+methodName+",攜帶的引數:"+params+",目標物件所呼叫的方法的返回值"+returnValue;
		System.out.println(msg2);
		
		return returnValue;
	}

}

效果:包圍一個連線點的通知,最大特點是可以修改返回值,由於它在方法前後都加入了自己的邏輯程式碼,因此功能異常強大。 它通過MethodInvocation.proceed()來呼叫目標方法(甚至可以不呼叫,這樣目標方法就不會執行)

在這裡插入圖片描述

4、異常通知

org.springframework.aop.ThrowsAdvice 出現異常執行系統提示,然後進行處理。價格異常為例

異常類:

package com.zking.aop.ex;

public class PriceException extends RuntimeException {

	public PriceException() {
		super();
	}

	public PriceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
		super(message, cause, enableSuppression, writableStackTrace);
	}

	public PriceException(String message, Throwable cause) {
		super(message, cause);
	}

	public PriceException(String message) {
		super(message);
	}

	public PriceException(Throwable cause) {
		super(cause);
	}
	
}

在這裡插入圖片描述

package com.zking.aop.advice;

import org.springframework.aop.ThrowsAdvice;

import com.zking.aop.ex.PriceException;

public class MyThrowsAdvice implements ThrowsAdvice {

	public void afterThrowing( PriceException ex ) {
		System.out.println("輸入的價格有誤,購買失敗,請重新輸入!!!!");		
	}
	
}

效果:這個通知會在方法丟擲異常退出時執行

在這裡插入圖片描述

5、過濾通知(介面卡)

org.springframework.aop.support.RegexpMethodPointcutAdvisor 處理買書返利的bug 在這裡插入圖片描述

效果: 在這裡插入圖片描述