Spring入門—SpringAop

一、springAop術語

springAop:面向切面編程。可插拔式的。即各個方法模塊獨立。需要就添加配置,不需要時就刪除配置。

  1. 切面(Aspect):橫切關注點被模塊化的特殊對象,即要插入的功能。
  2. 通知(Advice):店面必須要完成的工作,所謂通知是指攔截到joinpoint之後要做的事情。
    • 通知分爲:前置通知、後置通知、異常通知、最終通知、和環繞通知。
  3. 目標(target):被通知的對象。
  4. 代理(Proxy):向目標對象應用通知之後創建的對象。
  5. 連接點(JoinPoint):程序執行的某個特定位置。eg:類的某個方法運行前、調用後、方法拋出異常後等。
    • 連接點有兩個信息要確定,一個是方法(程序執行點),即執行什麼樣的方法時需要連接。
    • 另一個就是方位(程序相對點),即在什麼時候連接,是方法執行前、執行後還是拋出異常後等。
  6. 切點(PointCut):每個類都擁有多個連接點,那麼切點就是用來定位到特殊連接點的。
    • 類比:連接點相當於數據庫中的記錄,而切點相當於查詢條件。
  7. 織入(Weaving):是指把切面應用到目標對象來創建新的代理對象的過程,切面怎麼指定的連接點織入到目標對象。
  8. 引入(Introduction):在不修改代碼的前提下,Introduction可以在運行期爲類動態的添加一些方法或Filed。

二、springAop快速入門—案例(這裏使用註解方案)

1. 導入相關依賴包

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-beans</artifactId>
	<version>5.2.3.RELEASE</version>
</dependency>

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>5.2.3.RELEASE</version>
</dependency>

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-aspects</artifactId>
	<version>5.2.3.RELEASE</version>
</dependency>

<dependency>
	<groupId>log4j</groupId>
	<artifactId>log4j</artifactId>
	<version>1.2.17</version>
</dependency>

2. 編寫計算器接口(Calculator.java)

public interface Calculator {
	public int plus(int x, int y, int z);
	public double plus(double x, double y);
	public int plus(int x, int y);
	public int substract(int x, int y);
	public int division(int x,int y);
	public int multiplication(int x,int y);
}

3. 編寫計算器類繼承上面的接口(HxCalculator.java)

@Component		//這裏一定要加上註解,説明這是一個組件
public class HxCalculator implements Calculator{
	@Override
	public int plus(int x, int y, int z) {
		return x + y + z;
	}
	@Override
	public double plus(double x, double y) {
		return x + y;
	}
	@Override
	public int plus(int x, int y) {
		int result = x + y;
		return result;
	}
	@Override
	public int substract(int x, int y) {
		int result = x - y;
		return result;
	}
	@Override
	public int division(int x, int y) {
		int result = x / y;
		return result;
	}
	@Override
	public int multiplication(int x, int y) {
		int result = x * y;
		return result;
	}
}

4. 編寫日誌工具類(LogUtil.java)

public class LogUtil {
	public static Logger log = Logger.getLogger(LogUtil.class);
}

5. 編寫日誌切面類(LoggingAspect.java)

/**
 * 日誌切面
 * @author Huathy
 * @date 2020年3月5日 
 */
@Order(1)		//如果同時有多個切面,可以通過@Order註解來解決切面的先後順序,值越小優先級越高
@Component		//這個切面我們需要放到ioc容器中,所以需要加上註解@Componet
@Aspect			//將這個類聲明爲切面
public class LoggingAspect {
	/**
	 * 前置通知
	 * @param jp
	 */
	@Before("execution(public int com.hx.springaop.impl.HxCalculator.plus(int,int))")
	public void beforeMethod(JoinPoint jp){
		String methodName = jp.getSignature().getName();
		LogUtil.log.info( "前置通知-方法" + methodName + "開始執行,參數為" + Arrays.toString(jp.getArgs()) );
	}
	/**
	 * 後置通知
	 * @param jp
	 */
	@After("execution(public * com.hx.springaop.impl.HxCalculator.plus(..))")
	public void afterMethod(JoinPoint jp){
		String methodName = jp.getSignature().getName();
		LogUtil.log.info( "後置通知-方法" + methodName + "運行結束..." );
	}
	
	@Pointcut("execution(public * com.hx.springaop.impl.HxCalculator.*(..))")
	public void logging(){}
	
	/**
	 * 返回通知
	 * @param jp
	 * @param result
	 */
	@AfterReturning(value="logging()", returning="result")
	public void afterReturnMethod(JoinPoint jp,Object result){
		String methodName = jp.getSignature().getName();
		LogUtil.log.info( "返回通知-方法" + methodName + "運行結束,返回結果為:" + result );
	}
	/**
	 * 異常通知
	 * @param jp
	 * @param e
	 */
	@AfterThrowing(value="logging()", throwing="e")
	public void afterThrowMethod(JoinPoint jp, Exception e){
		String methodName = jp.getSignature().getName();
		LogUtil.log.info( "異常通知-方法" + methodName + "出現異常信息:" + e );
	}
	/**
	 * 環繞通知
	 * @param pjp
	 * @return
	 */
	@Around("logging()")
	public Object around(ProceedingJoinPoint pjp){
		Object obj = null;
		String methodName = pjp.getSignature().getName();
		LogUtil.log.info( "環繞通知-方法" + methodName + "開始執行,參數:" + Arrays.toString(pjp.getArgs()) );
		try {
			obj = pjp.proceed();	//運行方法
			LogUtil.log.info( "環繞通知-方法" + methodName + "運行結束,結果:" + obj );
		} catch (Throwable e) {
			LogUtil.log.info( "環繞通知-方法" + methodName + "運行出現異常信息:" + e );
			e.printStackTrace();
		}
		return obj;
	}
}

6. 在資源包下編寫全局配置spring-beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:util="http://www.springframework.org/schema/util"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/util
		http://www.springframework.org/schema/util/spring-util.xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd">
	<!-- 配置掃描路徑 -->
	<context:component-scan base-package="com.hx.springaop" />
	
	<!-- 讓註解起作用 -->
	<aop:aspectj-autoproxy />
</beans>

7. 把log4j.properties放到資源包下

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss}  %m%n

log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=hx.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss}  %l  %m%n

log4j.rootLogger=debug, stdout, file

8. 編寫測試類

public class AppTest {
	@Test
	public void test1(){
		ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
		Calculator clt = (Calculator) context.getBean("hxCalculator");
		
		System.out.println( clt.plus(10, 20) );
		System.out.println( clt.plus(10, 20, 30) );
		System.out.println( clt.plus(10.1, 10.2) );
		System.out.println( clt.substract(10, 20) );
		System.out.println( clt.division(10, 0) );
	}
}

9. 項目目錄結構

在這裏插入圖片描述

三、上述案例(xml配置方案)

1.把上面所有類上的通知組件等註解刪除

2.修改spring-beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:util="http://www.springframework.org/schema/util"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/util
		http://www.springframework.org/schema/util/spring-util.xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd">
	
	<!-- 計算器類 -->
	<bean id="calculator" class="com.hx.springaop.impl.HxCalculator"></bean>
	<!-- 切面類 -->
	<bean id="logAspect" class="com.hx.springaop.util.LoggingAspect"></bean>

	<!-- 配置aop -->
	<aop:config>
		<!-- 配置切點表達式 -->
		<aop:pointcut id="pointcut1" expression="execution(public int com.hx.springaop.impl.HxCalculator.plus(int,int))"></aop:pointcut>
		<aop:pointcut id="pointcut2" expression="execution(public * com.hx.springaop.impl.HxCalculator.*(..))"></aop:pointcut>
		
		<!-- 配置切面通知。ref:應用的切面id。 -->
		<aop:aspect ref="logAspect" order="1">
			<!-- 配置通知類型對應調用的方法以及切點 -->
			<aop:before method="beforeMethod" pointcut-ref="pointcut1"></aop:before>
			<aop:after method="afterMethod" pointcut-ref="pointcut2"></aop:after>
			<aop:after-returning method="afterReturnMethod" pointcut-ref="pointcut2" returning="result"></aop:after-returning>
			<aop:after-throwing method="afterThrowMethod" pointcut-ref="pointcut2" throwing="e"></aop:after-throwing>
			<aop:around method="around" pointcut-ref="pointcut2"></aop:around>
		</aop:aspect>
	</aop:config>
</beans>

3. 修改測試類

@Test
public void test1(){
	ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
	Calculator clt = (Calculator) context.getBean("calculator");
		
	System.out.println( clt.plus(10, 20) );
	System.out.println( clt.plus(10, 20, 30) );
	System.out.println( clt.plus(10.1, 10.2) );
	System.out.println( clt.substract(10, 20) );
	System.out.println( clt.division(10, 0) );
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章