Spring框架附帶AOP支持。 實際上,如Spring參考文檔中所述 ,
“ Spring的關鍵組件之一是AOP框架。 盡管Spring IoC容器不依賴于AOP,這意味著您不需要使用AOP,但AOP是對Spring IoC的補充,以提供功能強大的中間件解決方案。 AOP在Spring框架中用于…
- …提供聲明性企業服務,尤其是代替EJB聲明性服務。 此類服務中最重要的是聲明式事務管理。 ?
- …允許用戶實現自定義方面,并通過AOP補充其對OOP的使用。 ”
盡管如此,與完整的AOP實現(例如AspectJ)相比, Spring AOP框架還是有某些限制。 人們在使用Spring AOP框架時遇到的最常見問題源于以下事實: Spring AOP是“基于代理的”。 換句話說,當將bean用作依賴項并且應通過特定方面建議其方法時,IoC容器將注入“方面感知” bean代理,而不是bean本身。 為了對用戶透明地對代理bean實例執行方法調用,以便在將調用委派給實際的“代理” bean之前和/或之后執行方面邏輯。
此外, Spring AOP框架使用JDK動態代理或CGLIB創建給定目標對象的代理。 第一個只能為接口創建代理,而第二個可以代理具體類,但有一定的限制。 特別是,如Spring參考文檔中所述 ,
“ 如果要代理的目標對象實現至少一個接口,則將使用JDK動態代理。 目標類型實現的所有接口都將被代理。 如果目標對象未實現任何接口,則將創建CGLIB代理。 ”
總而言之,在使用Spring AOP框架時,您應該牢記兩個重要事項:
- 如果您的“代理” bean實現了至少一個接口,則只能將代理bean強制轉換為該接口。 如果嘗試將其強制轉換為“代理” bean類,則應期望在運行時引發ClassCastException。 盡管如此, Spring AOP框架提供了強制CGLIB代理的選項,但有上述限制(請參閱Spring參考文檔的相關章節)
- 方面不適用于術中呼叫。 這意味著代理無法攔截來自相同“代理” bean的另一個方法的方法的調用
我們建議克服以上問題的方法是使用AspectJ編織。 換句話說,將方面邏輯直接注入到目標類中,并消除了代理所有方法的必要性。 有三種方法可以注入AspectJ方面所隱含的指令:
- 編譯時間編織–通過AspectJ編譯器編譯目標源或方面類
- 編譯后編織–向已編譯的類注入方面指令
- 加載時間編織–在類加載期間向字節碼注入方面指令
可以使用上述任何方法。 在本教程中,我們將介紹如何在Spring和Maven中使用AspectJ編譯時編織。 我們將實現最小的“問候” Spring服務和相關的“問候” AspectJ方面。 Spring服務方法調用將被AspectJ方面攔截。 AspectJ方面將使用其自己的“問候”消息來豐富Spring服務的“問候”消息。 AspectJ方面的“問候”消息將從Spring容器中注入,只是為了展示如何將Spring依賴項注入到AspectJ方面。
已經為其bean服務實現了方面的Spring用戶可以透明地切換到AspectJ ,這意味著由于Spring AOP框架使用AspectJ切入點表達語言的子集而無需編寫任何特殊代碼,并且@AspectJ Spring方面完全符合AspectJ的編織要求。 。
我們首選的開發環境是Eclipse ,因此,必須先安裝具有Maven支持的Eclipse 。 用于Eclipse的Maven插件的安裝不在本教程的討論范圍內,因此將不予討論。 但是,您將需要以下組件:
- 從這里蝕
- 從這里開始 ,Eclipse的Maven插件
在本教程中,我們將使用Eclipse Galileo,“ m2eclipse” Maven Integration for Eclipse插件版本0.10.0,Spring版本3.0.1,aspectjrt版本1.6.7和Aspectj-maven-plugin版本1.3。
讓我們開始,
- 創建一個新的Maven項目,轉到File? 項目? Maven? Maven項目
- 在向導的“選擇項目名稱和位置”頁面中,確保未選中“創建簡單項目(跳過原型選擇)”選項,單擊“下一步”以繼續使用默認值
- 在向導的“選擇原型”頁面中,在“目錄”下拉列表中選擇“ Nexus Indexer”,并在刷新原型選擇區域后,從“ org.codehaus.mojo”中選擇“ webapp-jee5”原型。原型”。 您可以使用“過濾器”文本框來縮小搜索結果范圍。 點擊“下一步”繼續
- 在向導的“輸入工件ID”頁面中,您可以定義項目的名稱和主程序包。 我們將“ Group Id”變量設置為“ com.javacodegeeks”,將“ Artifact Id”變量設置為“ aspectjspring”。 前面提到的選擇組成了主項目包“ com.javacodegeeks.aspectjspring”和項目名“ aspectjspring”。 點擊“完成”退出向導并創建您的項目
讓我們回顧一下有關Maven Web項目結構的一些事情
- / src / main / java文件夾包含應用程序動態內容的源文件
- / src / test / java文件夾包含用于單元測試的所有源文件
- / src / main / webapp文件夾包含用于創建有效的Web應用程序的基本文件,例如“ web.xml”
- / target文件夾包含已編譯和打包的可交付成果
- “ pom.xml”是項目對象模型(POM)文件。 包含所有項目相關配置的單個文件。
為了在運行時正確使用Spring ,我們必須向Web應用程序提供所有必需的庫。 打開“ pom.xml”的圖形編輯器并執行以下更改:
- 在POM編輯器的“概述”頁面上的“屬性”部分中找到并執行以下更改:
- 創建一個名稱為org.springframework.version且值為3.0.1.RELEASE的新屬性
- 根據您的Java運行時環境的版本,創建一個名稱為maven.compiler.source的新屬性,并賦值為value,我們將使用1.6
- 根據您的Java運行時環境的版本創建一個名稱為maven.compiler.target的新屬性,并將其值設置為value,我們將使用1.6
- 導航到POM編輯器的“ Dependencies”頁面,并創建以下依賴關系(您應在該頁面的“ Dependency Details”部分的“ GroupId”,“ Artifact Id”和“ Version”字段中進行填充):
- 組ID: org.springframework工件ID: spring-web版本: $ {org.springframework.version}
- 組ID:org.aspectj工件ID:aspectjrt版本:1.6.7
- 導航到POM編輯器的“插件”頁面,并創建以下插件(您應在該頁面的“插件詳細信息”部分的“ GroupId”,“工件ID”和“版本”字段中進行填充):
- 組ID: org.codehaus.mojo工件ID: aspectj-maven-plugin版本: 1.3
- 在POM編輯器的“插件”頁面上,選擇新創建的插件(從“插件”部分中),并將其綁定到編譯執行目標。 為此,請找到“執行”部分并創建一個新的執行。 在“執行詳細信息”部分,創建一個新目標并將其命名為“ compile ”
- 新創建的插件需要進行最后的配置更改。 為了使AspectJ編譯器正確地編織方面類,我們必須定義所使用的Java運行時環境版本。 我們需要編輯“ pom.xml”文件來執行更改。 選擇POM編輯器的“ pom.xml”頁面,找到新創建的插件,并如下進行更改:
<plugin><groupId>org.codehaus.mojo</groupId><artifactId>aspectj-maven-plugin</artifactId><version>1.3</version><configuration><source>${maven.compiler.source}</source><target>${maven.compiler.target}</target></configuration><executions><execution><goals><goal>compile</goal></goals></execution></executions> </plugin>
- 最后,如下所示更改“ maven-compiler-plugin”:
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>2.0.2</version><configuration><source>${maven.compiler.source}</source><target>${maven.compiler.target}</target></configuration> </plugin>
如您所見, Maven以聲明方式管理庫依賴關系。 創建本地存儲庫(默認情況下,位于{user_home} /。m2文件夾下),所有必需的庫都從公共存儲庫下載并放置在該庫中。 此外,庫內的依賴關系會自動解決和處理。
下一步是為Web應用程序提供掛鉤,以便在啟動時加載Spring上下文。
在/ src / main / webapp / WEB-INF下找到“ web.xml”文件,并添加以下內容:
為了在啟動時加載Spring上下文,
<listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
現在讓我們創建將驅動Spring容器的applicationContext.xml文件。 在/ src / main / webapp / WEB-INF目錄下創建文件。 下面是一個示例“ applicationContext.xml”
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"xmlns:task="http://www.springframework.org/schema/task"xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsdhttp://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"><context:component-scan base-package="com.javacodegeeks.aspectjspring" /><bean class="com.javacodegeeks.aspectjspring.aspects.GreetingAspect" factory-method="aspectOf"><property name="message" value="Hello from Greeting Aspect"/></bean></beans>
這里要注意的事情:
- 將context:component-scan元素的base-package屬性更改為項目的基本包,以便掃描Spring組件
- 僅當我們要向它們注入依賴項時,才必須在“ applicationContext.xml”中定義我們的方面
- AspectJ表示術語“方面關聯”。 它定義了如何管理方面狀態。 支持以下狀態關聯:
- 每個JVM –構造和使用一個共享的方面實例(默認)
- 每個對象–每個建議對象的方面都有其自己的狀態
- 每個控制流–方面在每個特定控制流中都有自己的狀態
所有AspectJ方面類都具有“ hasAspect()”和“ aspectOf()”靜態方法。 這些方法由AspectJ編譯器/加載時間編織器隱式生成。 因此,對于默認的方面狀態,可以使用“ aspectOf()”方法來檢索一個方面的實例
現在讓我們創建“問候” Spring服務和相關的“問候” AspectJ方面。 在主程序包下創建一個名為“服務”的子程序包,并將“ GreetingService”類放在此處。 下面是一個示例“問候”服務:
package com.javacodegeeks.aspectjspring.services;import org.springframework.stereotype.Service;@Service("greetingService") public class GreetingService {public String sayHello() {return "Hello from Greeting Service";}}
在主包下創建一個名為“ aspects”的子包,并將“ GreetingAspect”類放在此處。 下面是一個示例“問候”方面:
package com.javacodegeeks.aspectjspring.aspects;import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect;@Aspect public class GreetingAspect {private String message;public void setMessage(String message) {this.message = message;}@Around("execution(* com.javacodegeeks.aspectjspring.services.GreetingService.*(..))")public Object advice(ProceedingJoinPoint pjp) throws Throwable {String serviceGreeting = (String) pjp.proceed();return message + " and " + serviceGreeting;}}
最后,在/ src / main / webapp文件夾下找到項目的主網頁“ index.jsp”,并進行如下更改:
<%@ page language="java" import="org.springframework.web.context.WebApplicationContext, org.springframework.web.context.support.WebApplicationContextUtils, com.javacodegeeks.aspectjspring.services.GreetingService"%> <%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd"><% WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); GreetingService greetingService = (GreetingService) webApplicationContext.getBean("greetingService"); %> <html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>JSP Page</title></head><body><h1>Test service invoked and greets you by saying : <%=greetingService.sayHello()%></h1></body> </html>
這里要注意的事情:
- 頁面加載后,我們檢索Spring Web應用程序上下文,并查找“問候”服務。 我們要做的就是調用“ sayHello()”方法,從我們的方面和服務中查看合并的問候消息
要構建應用程序,請右鍵單擊您的項目? 運行為? Maven包
要部署Web應用程序,只需將“ .war”文件從“ target”目錄復制到Apache – Tomcat “ webapps”文件夾
午餐應用程序將您的瀏覽器指向以下地址
http:// localhost:8080 / {application_name} /
如果一切順利,您應該會看到顯示以下內容的主網頁:
“測試服務被調用并打招呼:“ Greeting Aspect向您問好,Greeting Service向您問好”
您可以從這里下載項目
希望你喜歡
賈斯汀
相關文章 :
- GWT 2 Spring 3 JPA 2 Hibernate 3.5教程
- GWT Spring和Hibernate進入數據網格世界
- Spring3 RESTful Web服務
- GWT 2 Spring 3 JPA 2 Hibernate 3.5教程– Eclipse和Maven 2展示
- 帶有Spring和Maven教程的JAX–WS
翻譯自: https://www.javacodegeeks.com/2010/07/aspect-oriented-programming-with-spring.html