| 方式 | 時機 | 工具/機制 |
|---|---|---|
| 編譯期織入 | javac 階段 | AspectJ 編譯器 |
| 類加載期織入 (LTW) | 類載入 JVM 時 | 特殊類加載器 + -javaagent |
| 運行期織入 | 運行時動態代理 | CGLib / JDK Proxy |
AspectJ 採用前兩種,屬語言級 AOP,功能完備。Spring 2.0 引入 AspectJ 切點表達式解析,但本文聚焦**深度整合**:AspectJ 負責織入,Spring IoC 管理切面實例與依賴注入。
-javaagent-javaagent:D:\path\to\aspectjweaver.jarcatalina.bat 頭部添加set JAVA_OPTS=-javaagent:D:\path\to\aspectjweaver.jar
META-INF/aop.xml 織入配置<aspectj>
<aspects>
<aspect name="com.baobaotao.aspectj.TestAspectJ"/>
</aspects>
<weaver>
<include within="com.baobaotao..*"/>
</weaver>
</aspectj>
include 限定織入範圍,避免全量掃描影響啟動性能。
public class Waitress {
private String name;
public void serveTo(String client) {
System.out.println(name + " serves to " + client + "...");
}
// getter/setter
}
public aspect TestAspectj {
private pointcut traceServeTo() : execution(* serveTo(..));
before(): traceServeTo() {
System.out.println(message); // 禮貌用語
}
private String message;
public void setMessage(String message) { this.message = message; }
}
<bean id="aspectj" class="com.baobaotao.TestAspectj" factory-method="aspectOf">
<property name="message" value="How are you!"/>
</bean>
<bean id="waitress" class="com.baobaotao.Waitress">
<property name="name" value="Katty"/>
</bean>
關鍵:factory-method="aspectOf" 讓 Spring 從 AspectJ 獲取單例切面實例,而非自行創建。
<aspectj>
<aspects>
<aspect name="com.baobaotao.TestAspectj"/>
</aspects>
<weaver options="-showWeaveInfo -XmessageHandlerClass:org.springframework.aop.aspectj.AspectJWeaverMessageHandler">
<include within="com.baobaotao..*"/>
</weaver>
</aspectj>
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
Waitress waitress = (Waitress) ctx.getBean("waitress");
waitress.serveTo("Johnson");
輸出:How are you! Katty serves to Johnson... —— 切面織入生效,禮貌用語從 Spring 注入。
利用 org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect(位於 spring-aspects.jar)織入標注 @Configurable 的類,實現 new DomainObject() 也能享受 IoC 依賴注入。
@Configurable
public class Thread implements Serializable {
private String title;
private Topic topic; // 自動注入
// getter/setter/toString
}
@Configurable
public class Topic implements Serializable {
private String title;
private String content;
// getter/setter/toString
}
<aspectj>
<weaver options="...">
<include within="com.baobaotao.configure..*"/>
</weaver>
</aspectj>
<aop:spring-configured/> <!-- 等價於聲明 AnnotationBeanConfigurerAspect -->
<bean class="com.baobaotao.configure.Topic" scope="prototype">
<property name="title" value="測試帖子"/>
<property name="content" value="測試內容"/>
</bean>
<bean class="com.baobaotao.configure.Thread" scope="prototype">
<property name="title" value="測試的主題"/>
<property name="topic" ref="com.baobaotao.configure.Topic"/>
</bean>
Thread thread = new Thread(); // 普通 new
System.out.println(thread); // 輸出 Spring 配置的值
日志顯示 AspectJ 對 Thread、Topic 構造器織入 afterReturning 增強,從容器獲取 Bean 注入字段。
AnnotationBeanConfigurerAspect 為每 ClassLoader 單例,實現 BeanFactoryAware@Configurable("customName") 覆蓋)aop 命名空間提供 <aop:spring-configured/> 簡化配置Spring 2.0 提供 @AspectJ、Schema、AspectJ 原生三種 AOP 風格。**原則:從項目實際需求出發,選最簡單、最合適的方式。** 需要完整 AOP 能力(構造器切面、字段切面、靜態初始化切面)時,AspectJ + Spring IoC 是最強組合。