Spring 5 - Spring AOP 架構
Spring 5 - Spring AOP 架構
- 概念
- Advice介面
- 關於ProxyFactory類
- 增加 Before Advice
- 增加After-Returning Advice
- 增加Around Advice
- 增加Throws Advice
概念
- Joinpoints: 是程式執行中的一個點,比如呼叫一個方法,方法呼叫它自己,類初始化和物件例項的生成等。Joinpoints是AOP的核心概念,在程式裡定義可以插入附加邏輯的點
- Advice:在特定的joinpoint執行的程式碼就是advice,由你的類的方法定義。有很多型別的advice,比如before,
它在joinpoint之前執行;比如after,它在joinpoint之後執行 - Pointcuts:是advice應該被執行時候的joinpoints的集合。通過增加pointcuts,可以更細粒度地控制advice如何
作用於你程式的元件。一個典型的joinpoint是一個方法呼叫,或者特定類的所有方法呼叫的集合。你可以在複雜的關係中
合成pointcuts,限制advice的執行 - Aspects:封裝在一個類中的advice和pointcuts的組合
- Weaving:把aspects插入程式程式碼的適當位置的過程。對於編譯時AOP,weaving通常在build時候生成;對於執行時AOP,weaving過程在執行時動態執行。AspectJ支援另一個機制-load-time weaving (LTW)-當類被載入的時候,攔截底層的JVM類載入器,把weaving提供給位元組碼
- Target:被AOP修改的物件。通常,目標物件就是advised物件
- Introduction:通過附加的方法或者屬性,修改物件的結構的過程。你可以使用introduction AOP,讓任何物件實現一個特定的介面,而不用物件的類實現該介面
Spring AOP基於代理。當你增加一個類的advised的例項的時候,你必須使用ProxyFactory增加類的代理例項,先給它提供所有的構建代理的aspects。當然,一般情況下,你不用直接使用ProxyFactory,而是宣告AOP配置機制(ProxyFactoryBean、aop名稱空間和AspectJ的註解)。為了理解原理,我們先通過程式設計增加代理。
在執行時,Spring分析bean的定義,動態生成代理bean。不直接呼叫目標bean,而是呼叫被注入的代理bean。代理bean分析執行狀況(joinpoint、pointcut或者advice)注入合適的內容。Spring支援兩種代理實現:JDK動態代理和CGLIB代理。預設地,當要被advised的目標物件實現了一個介面,就使用JDK動態代理生成目標的代理例項。否則,如果目標物件沒實現一個介面,就使用CGLIB代理。一個主要原因是,JDK動態代理只能處理介面。
Spring AOP的一個更明顯的簡化是,它只支援一個joinpoint型別:方法呼叫。而AspectJ支援更多的joinpoints。方法呼叫joinpoint是最有用的joinpoint。
Spring AOP的aspect是指實現了Advisor介面的類的例項。Spring提供了方便的Advisor實現,你可以在程式裡重新使用。Advisor有兩個子介面:PointcutAdvisor和IntroductionAdvisor。所有的Advisor實現都實現了PointcutAdvisor,它使用pointcuts控制應用於joinpoints的advice。
Spring的Advice型別
Advice Name | Interface | Description |
---|---|---|
Before | org.springframework.aop.MethodBeforeAdvice | 在joinpoint執行前,執行自定義過程。因為joinpoint總是方法呼叫,實質上允許你在方法執行前執行預處理。Before advice可以完全訪問方法呼叫的目標以及傳給方法的引數,但是無法控制方法本身的執行。如果在advice前拋了異常,攔截器鏈(以及目標方法)的執行被終止,異常被傳播回攔截器鏈 |
After-Returning | org.springframework.aop.AfterReturningAdvice | 在joinpoint的方法呼叫執行完成並且已經有返回值以後,執行After-returning advice。它可以訪問方法呼叫的目標,傳給方法的引數和返回值。如果方法拋了異常,就不呼叫advice,異常被傳給呼叫棧。 |
After(finally) | org.springframework.aop.AfterAdvice | 方法正常執行完,才呼叫After-returning advice。而after(finally)無論如何都會執行,甚至在方法拋異常的時候也會執行。 |
Around | org.aopalliance.intercept.MethodInterceptor | 使用AOP聯盟的方法攔截器標準。在方法呼叫執行前後都可以執行你的advice,你可以控制允許方法呼叫繼續執行的點。你可以選擇旁路方法,提供自己的實現。 |
Throws | org.springframework.aop.ThrowsAdvice | 在方法呼叫拋異常後執行。throws advice可以只捕獲特定異常,此時,你可以訪問丟擲異常的方法,傳遞給方法的引數和呼叫的目標。 |
Introduction | org.springframework.aop.IntroductionInterceptor | introductions是特殊型別的攔截器。使用這樣的攔截器,可以指定advice介紹的方法的實現。 |
Advice介面
關於ProxyFactory類
ProxyFactory控制代理增加過程。它有兩個重要方法,setTarget()方法指定目標物件,addAdvice()方法增加Advice。
在ProxyFactory內部,由DefaultAopProxyFactory的例項(實際使用JdkDynamicAopProxy或者CglibAopProxy)增加相應的代理。
addAdvice()方法把你傳的advice放進DefaultPointcutAdvisor的一個例項,DefaultPointcutAdvisor是PointcutAdvisor的標準實現,預設地,應用於物件的全部方法。
增加 Before Advice
Before advice是Spring支援的最有用的advice型別。它能修改傳給方法的引數,能通過拋異常的辦法阻止方法執行。下來,我們看看簡單的例子,在方法執行前,在控制檯寫一個訊息,其中包含方法的名字。程式碼是SimpleBeforeAdvice類:
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;
import java.lang.reflect.Method;
public class SimpleBeforeAdvice implements MethodBeforeAdvice {
public static void main(String... args) {
Guitarist johnMayer = new Guitarist();
ProxyFactory pf = new ProxyFactory();
pf.addAdvice(new SimpleBeforeAdvice());
pf.setTarget(johnMayer);
Guitarist proxy = (Guitarist) pf.getProxy();
proxy.sing();
}
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("Before '" + method.getName() + "', tune guitar.");
}
private static class Guitarist implements Singer {
private String lyric = "You're gonna live forever in me";
@Override
public void sing(){
System.out.println(lyric);
}
}
interface Singer {
void sing();
}
}
Guitarist類很簡單,只有一個方法-sing()-在控制檯輸出lyric。它實現了Singer介面。
可以看到,SimpleBeforeAdvice實現了MethodBeforeAdvice介面,定義了一個方法before()。我們現在使用的是addAdvice()方法提供的預設pointcut,這樣就匹配類裡的所有方法。before()方法有三個引數:被呼叫的方法,要傳給方法的引數和呼叫的目標物件。SimpleBeforeAdvice類使用before()方法的Method引數,在控制檯寫訊息,訊息包含被呼叫方法的名字。執行一下,輸出是這樣的:
Before 'sing', tune guitar.
You're gonna live forever in me
通過Before Advice,實現安全的方法訪問
我們實現before advice,在允許方法呼叫之前,檢查使用者證書。如果使用者證書無效,通過該advice拋異常,這樣阻止方法的執行。本例有點簡單化,它允許使用者使用任何密碼鑑權,也只允許一個硬編碼的使用者訪問安全的方法。
先看SecureBean類,它會被安全地執行:
class SecureBean {
void writeSecureMessage() {
System.out.println("Every time I learn something new, "
+ "it pushes some old stuff out of my brain");
}
}
因為本示例需要做使用者認證,所以需要有地方儲存他們的細節。我們使用UserInfo儲存使用者證書:
class UserInfo {
private String userName;
private String password;
UserInfo(String userName, String password) {
this.userName = userName;
this.password = password;
}
public String getPassword() {
return password;
}
public String getUserName() {
return userName;
}
}
下來是SecurityManager類,負責認證,並儲存他們的證書,供以後檢索:
class SecurityManager {
private static ThreadLocal<UserInfo>
threadLocal = new ThreadLocal<>();
void login(String userName, String password) {
threadLocal.set(new UserInfo(userName, password));
}
void logout() {
threadLocal.set(null);
}
UserInfo getLoggedOnUser() {
return threadLocal.get();
}
}
程式使用SecurityManager類認證使用者,並在之後檢索當前已認證的使用者的細節。使用login()方法做認證,它增加一個UserInfo物件,儲存到ThreadLocal。getLoggedOnUser()方法返回當前認證的使用者的資訊,如果沒有被認證的使用者,就返回null。
要檢查一個使用者是否已經被認證,如果被認證了,就可以訪問SecureBean類的方法。所以,我們增加advice,在方法呼叫前執行,檢查使用者資訊:
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class SecurityAdvice implements MethodBeforeAdvice {
private SecurityManager securityManager;
SecurityAdvice() {
this.securityManager = new SecurityManager();
}
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
UserInfo user = securityManager.getLoggedOnUser();
if (user == null) {
System.out.println("No user authenticated");
throw new SecurityException(
"You must login before attempting to invoke the method: "
+ method.getName());
} else if ("John".equals(user.getUserName())) {
System.out.println("Logged in user is John - OKAY!");
} else {
System.out.println("Logged in user is " + user.getUserName()
+ " NOT GOOD :(");
throw new SecurityException("User " + user.getUserName()
+ " is not allowed access to method " + method.getName());
}
}
}
SecurityAdvice類在它的構造器裡增加了一個SecurityManager的例項。在before()方法裡,我們簡單地檢查,使用者名稱是不是John。如果是,允許使用者訪問;否則,拋異常。
下面的程式碼,做測試:
import org.springframework.aop.framework.ProxyFactory;
public class SecurityDemo {
public static void main(String... args) {
SecurityManager mgr = new SecurityManager();
SecureBean bean = getSecureBean();
mgr.login("John", "pwd");
bean.writeSecureMessage();
mgr.logout();
try {
mgr.login("invalid user", "pwd");
bean.writeSecureMessage();
} catch (SecurityException ex) {
System.out.println("Exception Caught: " + ex.getMessage());
} finally {
mgr.logout();
}
try {
bean.writeSecureMessage();
} catch (SecurityException ex) {
System.out.println("Exception Caught: " + ex.getMessage());
}
}
private static SecureBean getSecureBean() {
SecureBean target = new SecureBean();
SecurityAdvice advice = new SecurityAdvice();
ProxyFactory factory = new ProxyFactory();
factory.setTarget(target);
factory.addAdvice(advice);
SecureBean proxy = (SecureBean) factory.getProxy();
return proxy;
}
}
我們測試了三個場景,只有John通過了驗證:
Logged in user is John - OKAY!
Every time I learn something new, it pushes some old stuff out of my brain
Logged in user is invalid user NOT GOOD :(
Exception Caught: User invalid user is not allowed access to method writeSecureMessage
No user authenticated
Exception Caught: You must login before attempting to invoke the method: writeSecureMessage
增加After-Returning Advice
After-returning advice在方法呼叫返回後執行。既然方法已經執行了,你不能修改傳給它的引數。雖然你能讀這些引數,你不能修改執行路徑,也不能阻止方法執行。而且,你也不能在after-returning advice內修改返回值,但是,你可以拋異常,異常取代了返回值,被送到呼叫棧。
下面,我們看兩個例子。第一個,在方法被呼叫後,在控制檯輸出訊息。第二個,顯示如何使用after-returning advice,給一個方法增加錯誤檢查。考慮一個類,KeyGenerator,生成用於加密的key。很多加密演算法都會碰到這樣的問題,有些key太弱了(即使不知道key,也容易匯出原始訊息)。第二個例子用來檢查弱key。
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.framework.ProxyFactory;
import java.lang.reflect.Method;
public class SimpleAfterReturningAdvice implements
AfterReturningAdvice {
public static void main(String... args) {
Guitarist target = new Guitarist();
ProxyFactory pf = new ProxyFactory();
pf.addAdvice(new SimpleAfterReturningAdvice());
pf.setTarget(target);
Guitarist proxy = (Guitarist) pf.getProxy();
proxy.sing();
}
@Override
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
System.out.println("After '" + method.getName() + "' put down guitar.");
}
private static class Guitarist implements SimpleBeforeAdvice.Singer {
private String lyric = "You're gonna live forever in me";
@Override
public void sing() {
System.out.println(lyric);
}
}
interface Singer {
void sing();
}
}
理想情況下,key生成器會檢查弱key,但是,弱key出現機率很小,所以,很多key生成器不做這樣的檢查。我們現在使用after-returning advice做檢查:
class KeyGenerator {
static final long WEAK_KEY = 0xFFFFFFF0000000L;
static final long STRONG_KEY = 0xACDF03F590AE56L;
private Random rand = new Random();
long getKey() {
int x = rand.nextInt(3);
if (x == 1) {
return WEAK_KEY;
}
return STRONG_KEY;
}
}
不能認為key生成器是安全的。上面程式碼每三次就有一次機會生產弱key。WeakKeyCheckAdvice類檢查getKey()方法返回的是否弱key:
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
import static spring.aop.KeyGenerator.WEAK_KEY;
public class WeakKeyCheckAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
if ((target instanceof KeyGenerator)
&& ("getKey".equals(method.getName()))) {
long key = ((Long) returnValue).longValue();
if (key == WEAK_KEY) {
throw new SecurityException(
"Key Generator generated a weak key. Try again");
}
}
}
}
下面我們做測試:
public class AfterAdviceDemo {
private static KeyGenerator getKeyGenerator() {
KeyGenerator target = new KeyGenerator();
ProxyFactory factory = new ProxyFactory();
factory.setTarget(target);
factory.addAdvice(new WeakKeyCheckAdvice());
return (KeyGenerator)factory.getProxy();
}
public static void main(String... args) {
KeyGenerator keyGen = getKeyGenerator();
for(int x = 0; x < 10; x++) {
try {
long key = keyGen.getKey();
System.out.println("Key: " + key);
} catch(SecurityException ex) {
System.out.println("Weak Key Generated!");
}
}
}
}
增加Around Advice
Around advice像是before和after advice的組合。但是有幾點不同:你可以修改返回值,也能阻止方法的執行。意思是,使用around advice,你可以用新程式碼代替方法。Spring很多地方都使用了around advice,比如遠方代理支援和事務管理。
首先,我們使用Agent類,看怎麼使用基本的方法攔截器在方法呼叫的兩端寫一條訊息。應該注意的是,MethodInterceptor介面的invoke()方法的引數集和MethodBeforeAdvice、AfterReturningAdvice的不一樣。
下面的例子,我們通過advise,得到方法執行時效能的相關資訊。特別是,我們想知道方法執行了多長時間。我們使用了Spring的StopWatch。先看看
WorkerBean,它是被觀察物件:
class WorkerBean {
void doSomeWork(int noOfTimes) {
for (int x = 0; x < noOfTimes; x++) {
work();
}
}
private void work() {
System.out.print("");
}
}
ProfilingInterceptor類使用StopWatch類觀察方法呼叫時長:
public class ProfilingInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
StopWatch sw = new StopWatch();
sw.start(invocation.getMethod().getName());
Object returnValue = invocation.proceed();
sw.stop();
dumpInfo(invocation, sw.getTotalTimeMillis());
return returnValue;
}
private void dumpInfo(MethodInvocation invocation, long ms) {
Method m = invocation.getMethod();
Object target = invocation.getThis();
Object[] args = invocation.getArguments();
System.out.println("Executed method: " + m.getName());
System.out.println("On object of type: " +
target.getClass().getName());
System.out.println("With arguments:");
for (int x = 0; x < args.length; x++) {
System.out.print(" > " + args[x]);
}
System.out.print("\n");
System.out.println("Took: " + ms + " ms");
}
}
下來是測試程式碼:
public class ProfilingDemo {
public static void main(String... args) {
WorkerBean bean = getWorkerBean();
bean.doSomeWork(10000000);
}
private static WorkerBean getWorkerBean() {
WorkerBean target = new WorkerBean();
ProxyFactory factory = new ProxyFactory();
factory.setTarget
相關推薦
Spring 5 - Spring AOP 架構
Spring 5 - Spring AOP 架構
概念
Advice介面
關於ProxyFactory類
增加 Before Advice
通過Before Advice,實現安全的方法訪問
增加After-Returni
Java 22:Spring 5(Spring MVC 入門)
Spring MVC的流程經歷流程:
1、請求帶著使用者請求的資訊,到達DispatcherServlet。
Spring MVC所有的請求都會通過一個前端控制器Servlet。前端控制器是常用的Web應用程式模式。DispatcherServlet的任務是將請求傳送給Sp
[Spring Boot實戰系列] - No.5 Spring boot AOP 示例
Spring boot AOP 示例
在之前的文章中,介紹過Spring 的AOP與AspectJ相關的內容。最近實驗室的一個專案又用到了springboot的AOP,在網上調研了一下發現了幾個配置極其簡單但功能很完善的示例,在這裡總結一下。AOP相關的原理及含義不再解釋,參考之前的
Spring 5 設計模式 - 使用代理和裝飾模式的Spring AOP
Spring 5 設計模式 - 使用代理和裝飾模式的Spring AOP
Spring中的代理模式
什麼是AOP
AOP要解決的問題
程式碼糾纏
程式碼分散
解決
AOP的核心術語
《Spring 5官方文件》37. Spring AOP的經典用法
原文連結
在本附錄中,我們會討論一些初級的Spring AOP介面,以及在Spring 1.2應用中所使用的AOP支援。
對於新的應用,我們推薦使用 Spring AOP 2.0來支援,在AOP章節有介紹。但在已有的專案中,或者閱讀資料或者文章時,可能會遇到Spring AOP 1.2風格的示
[AOP] 5. Spring AOP中提供的種種Aspects
本文繼續討論ConcurrencyThrottleInterceptor(基於Spring 4.3.7)。以及上一篇文章中遺留的一個關於SimpleAsyncTaskExecutor類中屬性concurrencyLimit的問題。
這些都和併發控制相關。但是這
那些年、一起追過的Spring--(5)----AOP
瞭解: (在概念上和原理上充分理解)
參考視訊:http://www.jikexueyuan.com/course/665_3.html?ss=1
1. 什麼是AOP
2. AOP的存在價值
3. AOP的原理剖析
4. AOP的關鍵概念
day39-Spring 08-Spring的AOP:基於AspectJ的註解
ima spring mage 開發 技術 asp day3 cnblogs ring 基於AspectJ的註解的開發要重點掌握.
day39-Spring 08-Spring的AOP:基於AspectJ的註解
day39-Spring 11-Spring的AOP:基於AspectJ的XML配置方式
asp 技術 mage bsp aop src xml配置方式 img aspectj
day39-Spring 11-Spring的AOP:基於AspectJ的XML配置方式
5.Spring+Struts+Hibernate配置文件整合
extends nco 方法 系統 ted -a type -i ping 一:配置文件整合SSH
1.創建Hibernate實體類的映射文件,一般在resource下建文件夾下放置
<?xml version="1.0" encoding="UTF-8"?>&
Spring Boot學習——AOP編程的簡單實現
col .com tsig 訪問 pan -s ping 編程範式 lan 首先應該明白一點,AOP是一種編程範式,是一種程序設計思想,與具體的計算機編程語言無關,所以不止是Java,像.Net等其他編程語言也有AOP的實現方式。AOP的思想理念就是將通用邏輯
Spring系列之AOP
-a cte implement 結合 動態擴展 分離 可操作性 技術 其中 一、什麽是AOPAOP(Aspect-OrientedProgramming,面向方面編程),可以說是OOP(Object-Oriented Programing,面向對象編程)的補充和完善。OO
Spring系列之AOP實現的兩種方式
部分 靜態常量 cep value conf tar import enc ble AOP常用的實現方式有兩種,一種是采用聲明的方式來實現(基於XML),一種是采用註解的方式來實現(基於AspectJ)。
首先復習下AOP中一些比較重要的概念:
Joinpoint(連接點)
spring筆記3-AOP
父類 ride 支持 ack beans 方法參數 cep 結構 express
一.概述
AOP:(Aspect Oriented Programming)即:面向切面編程。把我們程序重復的代碼抽取出來,在需要執行的時候,使用動態代理的技術,在不修改源碼的基礎上,對我們
(二)整合spring cloud雲服務架構 - particle雲架構
介紹 能夠 步驟 架構 第一篇 img .net 業務 服務架構
第一篇文章簡單給大家介紹了Spring Cloud架構,我這邊結合了當前大部分企業的通用需求,包括技術的選型比較嚴格、苛刻,不僅要用業界最流行的技術,還要和國際接軌,在未來的5~10年內不能out。作為公司
(一)整合spring cloud雲服務架構 - Spring Cloud簡介
springcloud 架構 雲服務 Spring Cloud是一系列框架的有序集合。利用Spring Boot的開發模式簡化了分布式系統基礎設施的開發,如服務發現、註冊、配置中心、消息總線、負載均衡、斷路器、數據監控等(這裏只簡單的列了一部分),都可以用Spring Boot的開發風格做到一鍵啟動和部署
(三)整合spring cloud雲服務架構 - particle雲架構代碼結構構建
itl log lan 作用 購物 基本架構 集成 eight control 上一篇介紹了spring cloud雲服務架構的基本架構圖,本篇我們根據架構圖進行代碼的構建,根據微服務化設計思想,結合spring cloud本身的服務發現、治理、配置化管理、分布式等項目優秀
Spring cloud 微服務架構 Eureka篇
ring enabled 密碼 config lns 用戶 one ima nap
1 服務發現
## 關於服務發現
在微服務架構中,服務發現(Service Discovery)是關鍵原則之一。手動配置每個客戶端或某種形式的約定是很難做的,並且很脆弱。Sprin
spring cloud微服務架構 服務提供者和服務消費者
服務 lee 名詞 mave into gin tag bigint snap 服務提供者和服務消費者
下面這張表格,簡單描述了服務提供者/消費者是什麽:
| 名詞 | 概念 |
| ----- | ---------
spring cloud 微服務架構 簡介
session 進行 tell div apach 後來 tro 最新版 maven Spring Cloud
1、 Spring Cloud 簡介
Spring Cloud是在Spring Boot的基礎上構建的,用於簡化分布式系統構建的工具集,為開發人員提供快