05 Spring Aop例項(AOP 如此簡單)@Aspect、@Around 註解方式配置
轉載請註明來源 賴賴的部落格
導語
沒有什麼是不可以改變的,換個角度看世界,截然不同!
IoC相關的基本內容告一段落,本次介紹Spring的第二個特性,AOP,面向切面程式設計,術語聽起來比較不容易理解,沒關係,一切盡在例項中,讓我們看一個簡單的例項,就能明白。
例項
專案工程目錄結構和程式碼獲取地址
獲取地址(版本Log將會註明每一個版本對應的課程)
目錄結構
執行工程
執行具有Main函式的 App.java
得到如下輸出
method start time:1480223298250
userHello
method end time:1480223299250
專案詳解
從App.java入手
App.java
package me.laiyijie.demo; import org.springframework.context.support.ClassPathXmlApplicationContext; import me.laiyijie.demo.service.HelloInterface; public class App { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("root-context.xml"); HelloInterface userService = context.getBean(HelloInterface.class); userService.sayHello(); context.close(); } }
呼叫的是HelloInterface
的sayHello
方法
HelloInterface.java
package me.laiyijie.demo.service;
public interface HelloInterface{
void sayHello();
}
其實現類為UserServiceImpl.java
UserServiceImpl.java
package me.laiyijie.demo.service; import org.springframework.stereotype.Service; @Service public class UserServiceImpl implements HelloInterface { public void sayHello() { try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("userHello"); } }
誒?情況跟我們看到的程式碼有出入?
sayHello 應該只輸出 userHello,前後兩行輸出從何出現?
在Main函式中找不到一點兒線索!
這就是AOP的一個強大特性:
無侵入性,不改變原有的程式碼,卻能增加功能!
那麼究竟是如何增加功能的呢?
讓我們看看TimeMonitor.java
TimeMonitor.java
package me.laiyijie.demo.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Service;
@Service
@Aspect
public class TimeMonitor {
@Around("execution(* me.laiyijie.demo.service.UserServiceImpl.sayHello(..))")
public void monitorAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("method start time:" + System.currentTimeMillis());
Object re = pjp.proceed();
System.out.println("method end time:" + System.currentTimeMillis());
}
}
終於看到了 method start time:1480223298250
和 method end time:1480223299250
這兩行輸出是從哪兒出現的了!
讓我們來仔細解讀一下這個類
- 類有兩個註釋,分別是@Service和@Aspect,第一個註解是使得TimeMonitor受Spring託管並例項化。@Aspect就是使得這個類具有AOP功能(你可以這樣理解)兩個註解缺一不可
類裡面只有一個方法,名字叫做monitorAroud,其實就是為了檢測函式執行時間的!
那麼關鍵點來了,兩個輸出語句是怎麼插入到sayHello方法的前後的呢!
看這個註解:
@Around(“execution(* me.laiyijie.demo.service.UserServiceImpl.sayHello(..))”)
- @Around表示包圍一個函式,也就是可以在函式執行前做一些事情,也可以在函式執行後做一些事情
execution(* me.laiyijie.demo.service.UserServiceImpl.sayHello(..))
這個比較好理解,就是使用表示式的方式指定了要對哪個函式進行包圍!(除了execution以外還有很多,可以搜尋AspectJ語法來學習)
也就是說,這個註解完整的說明了,應該在函式的什麼位置插入變化,也就是所謂的切點
之後是函式的定義:
public Object monitorAround(ProceedingJoinPoint pjp)
這裡引入了ProceedingJoinPoint
,在使用了@Around之後可以帶入這個引數,代表的其實就是sayHello這個函式,不過做了一些封裝
而 Object re = pjp.proceed();
就是相當於執行了 sayHello
方法!
剩下的程式碼就不用過多解釋了,就是在執行這個函式的前後分別進行了系統時間的獲取。
我們把這個函式體,也就是定義了要做那些事情的程式碼,稱作增強
而包含切點和增強結合起來就稱作切面
面向切面由此而來!
Spring AOP 開啟需要的配置
需要配置兩項
- pom.xml增加依賴(因為要用到AOP還需要不同的JAR包)
- root-context.xml中增加切面相關配置
root-context.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:context="http://www.springframework.org/schema/context"
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/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<context:component-scan base-package="me.laiyijie.demo"></context:component-scan>
</beans>
root-context.xml 增加了兩行
xmlns:aop="http://www.springframework.org/schema/aop"
代表加入名稱空間<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
使用1中引入的aop名稱空間開起自動代理(自動代理具體含義後續慢慢解釋,簡單的理解就是AOP的實現是依靠自動代理實現的)
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>me.laiyijie</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
</dependencies>
</project>
增加了一個依賴
- AspectJ 一個強大的AOP框架,也就是@Aspect和@Around以及ProceedingJoinPoint這些註解和方法的提供者
小結
- 增強:定義了應該怎麼把額外的動作加入到指定函式中
- 切點:定義了你應該把增強插入到哪個函式的什麼位置
- 切面:切點和增強組合起來的稱呼
盡情享受AOP吧!給你一個不同尋常的體驗