帶有命名切入點的AOP上下文繫結

工程 | Ben Hale | 2007年3月29日 | ...

Spring AOP中有大量新功能,包括AspectJ切入點語言、<aop:*/>名稱空間和@AspectJ語法支援。但到目前為止,最強大的方面之一(請原諒雙關語)是AOP上下文繫結。

例如,假設您想要建議一個將String作為引數的方法。


public interface HelloService {
	String getHelloMessage(String toAddHello);
}

要建議此方法,您需要編寫一個切入點,它尋找String返回型別,HelloService介面的所有實現以及getHelloMessage(String)方法。


@Before("execution(public java.lang.String aop.HelloService+.getHelloMessage(String))")

但是,如果您想應用一個需要在內部使用 String 引數的建議呢?


public void filter(String input) {
	if (obscenities.contains(input)) {
		throw new IllegalArgumentException("Obscenities such as '" + input + "' will not be tolerated!");
	}
}

嗯,這就是 AOP 上下文繫結的作用所在。事實上,Spring 支援相當多的 AspectJ 切點語言。這裡我們關心的是 args() 運算子。這個運算子允許我們選擇一個引數並將其繫結到我們的建議。所以,當切點和建議結合起來時,你會看到這樣的效果。


@Before("execution(public java.lang.String aop.HelloService+.getHelloMessage(String)) && args(input)")
public void filter(String input) {
	if (obscenities.contains(input)) {
		throw new IllegalArgumentException("Obscenities such as '" + input + "' will not be tolerated!");
	}
}

現在這很酷。您可以從被建議的方法中強型別且命名地將引數繫結到建議。在更復雜的示例中,還可以將多個上下文片段(例如其他引數、正在呼叫的物件等)也繫結到建議。有一點我想強調一下,因為它總是讓我感到困惑:args() 運算子中的引數名稱對應於建議方法中的引數名稱。

此特定配置的問題在於,大多數時候您不會建立帶有嵌入式切點的建議宣告。通常,您會將切點外部化到一個命名切點。為此,您需要引入另一個間接層。也就是說,命名切點後跟建議定義。


@Pointcut("execution(public java.lang.String aop.HelloService+.getHelloMessage(String)) && args(helloInput)")
public void helloService(String helloInput) {}


@Before("helloService(input)")
public void filter(String input) {
	if (obscenities.contains(input)) {
		throw new IllegalArgumentException("Obscenities such as '" + input + "' will not be tolerated!");
	}
}

在此示例中要記下的重要事項是,命名切點需要將其上下文型別作為引數,以便可以將該引數傳播到建議。您可以看到 helloService(String) 接受一個 String,以便 Before 建議可以引用 helloService(input)

最後一步是建立一個將系統粘合在一起的配置檔案。


<?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:aop="http://www.springframework.org/schema/aop"
	xmlns:util="http://www.springframework.org/schema/util"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
		http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
		http://www.springframework.org/schema/util
		http://www.springframework.org/schema/util/spring-util-2.0.xsd">

	<bean id="helloService" class="aop.HelloServiceImpl" />

	<bean id="obscenityFilter" class="aop.ObscenityFilter">
		<constructor-arg>
			<util:set>
				<value>Microsoft</value>
			</util:set>
		</constructor-arg>
	</bean>

	<aop:aspectj-autoproxy>
		<aop:include name="obscenityFilter" />
	</aop:aspectj-autoproxy>

</beans>


現在,有些人可能會問,為什麼要使用 AOP 上下文繫結。確實,您只需向建議新增一個 JoinPoint 引數,Spring AOP 就會自動繫結它。該物件將包含您透過上下文繫結可以獲得的所有引數、返回值等。但是,在處理該上下文資訊時,您真正得到的是 ObjectsObject[] 項。您仍然需要進行型別轉換並處理潛在的異常。透過上下文繫結,您只獲得您正在尋找的內容(無需在 JoinPoint 資料結構中進行探究),並且該資料是強型別的。程式碼更少 == 維護更少 == 成本更低!(但這正是 AOP 的宗旨,不是嗎?)

對於有興趣的人,我將在此示例中的原始碼 放在這裡。

獲取 Spring 新聞通訊

透過 Spring 新聞通訊保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助您加速進步。

瞭解更多

獲得支援

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案,只需一份簡單的訂閱。

瞭解更多

即將舉行的活動

檢視 Spring 社群所有即將舉行的活動。

檢視所有