Spring 5.0.3.RELEASE中的 Kotlin 語言支持
https://docs.spring.io/spring/docs/current/spring-framework-reference/languages.html
1. Kotlin
Kotlin是靜態(tài)類型語言定位的JVM(以及其他平臺)压汪,它允許寫簡潔而優(yōu)雅的代碼,同時(shí)提供很好 的互操作性與Java編寫的現(xiàn)有的庫古瓤。
Spring框架提供了 Kotlin 一等支持止剖,允許Kotlin 程序員無縫使用 Spring框架落君。
1.1穿香。要求
彈簧框架支持科特林1.1+并且需要 kotlin-stdlib
(或它的一個(gè)kotlin-stdlib-jre7
/ kotlin-stdlib-jre8
變體)和kotlin-reflect
對存在于類路徑。他們在默認(rèn)情況下绎速,如果一個(gè)自舉在科特林項(xiàng)目提供 start.spring.io皮获。
1.2。擴(kuò)展
科特林擴(kuò)展提供到具有附加功能擴(kuò)展現(xiàn)有的類的能力纹冤。Spring框架科特林的API利用這些擴(kuò)展到新的科特林具體的便利添加到現(xiàn)有的Spring的API洒宝。
Spring框架KDOC API列表和文檔的所有科特林?jǐn)U展和提供的DSL。
科特林?jǐn)U展需要 import 使用萌京。例如雁歌,在GenericApplicationContext.registerBean
如果科特林?jǐn)U展將只能import org.springframework.context.support.registerBean
。
例如枫夺,科特林具體化類型參數(shù) 提供JVM一種變通方法泛型類型擦除将宪,和Spring框架提供了一些擴(kuò)展至利用此功能優(yōu)勢。這樣可以更好的科特林API RestTemplate
,新WebClient
的春天WebFlux和各種其他的API较坛。
像 Reactor 和 Spring Data 數(shù)據(jù)的其他庫還提供Kotlin 擴(kuò)展 API印蔗。
要檢索列表Foo
中的Java對象,人們通常會寫:
Flux<User> users = client.get().retrieve().bodyToFlux(User.class)
雖然與科特林和Spring框架的擴(kuò)展丑勤,一個(gè)是能寫:
val users = client.get().retrieve().bodyToFlux<User>()
// or (both are equivalent)
val users : Flux<User> = client.get().retrieve().bodyToFlux()
正如在Java中华嘹,users
在科特林是強(qiáng)類型罕模,但Kotlin 的聰明的類型推斷允許更短的語法南窗。
1.3⊙龀空安全
一個(gè)科特林的主要特點(diǎn)是空的安全 -這干凈地涉及null
在編譯的時(shí)候岔霸,而不是撞到著名的值 NullPointerException
在運(yùn)行時(shí)薛躬。
這使得應(yīng)用更加安全,通過空性的聲明呆细,并表示“有值或沒有值” 的語義無需支付包裝成本Optional
型宝。參考: http://www.baeldung.com/kotlin-null-safety
雖然Java不允許一個(gè)來表達(dá)它的類型系統(tǒng)空安全,Spring框架現(xiàn)在提供整個(gè)Spring框架API的空安全 通過的聲明工裝友好注釋org.springframework.lang
包絮爷。默認(rèn)情況下趴酣,在科特林使用的Java API類型被認(rèn)為是 平臺類型 為其中空檢查是放松。 對于JSR 305個(gè)注解科特林支持 +春空性的注釋為整個(gè)Spring框架API來開發(fā)科特林空安全坑夯,與涉及的優(yōu)勢null
在編譯時(shí)的相關(guān)問題岖寞。
像 Reactor 反應(yīng)堆或 Spring Data 庫提供空安全的API利用此功能。
JSR 305檢查可以通過添加被配置-Xjsr305
具有以下選項(xiàng)的編譯標(biāo)志:
-Xjsr305={strict|warn|ignore}
柜蜈。
對于科特林版本1.1.50+仗谆,默認(rèn)行為是一樣的來-Xjsr305=warn
。該strict
值是必需的跨释。
泛型類型參數(shù)胸私,可變參數(shù)和數(shù)組元素為空性尚不支持厌处,而應(yīng)在未來版本中鳖谈,看到這個(gè)dicussion 達(dá)最新信息。
1.4阔涉。類和接口
彈簧框架支持各種科特林構(gòu)造等經(jīng)由主構(gòu)造實(shí)例科特林類缆娃,不可變的類數(shù)據(jù)綁定和具有默認(rèn)值的功能的可選參數(shù)。
科特林參數(shù)名通過專用的認(rèn)可KotlinReflectionParameterNameDiscoverer
瑰排,其允許贯要,而不需要在Java 8找到接口方法的參數(shù)名稱-parameters
編譯時(shí)啟用編譯器標(biāo)志。
序列化/反序列化JSON數(shù)據(jù)的 jackson-module-kotlin在類路徑發(fā)現(xiàn)椭住,如果沒有 jackson-module-kotlin 被檢測到崇渗,有警告消息。
1.5。注解
Spring框架與 科特林空安全 宅广。
例如:確定是否一個(gè)HTTP參數(shù)是必須的葫掉,而無需顯式定義required
屬性。這意味著@RequestParam name: String?
如不是必需的跟狱,反之將被視為@RequestParam name: String
為被需要俭厚。此功能還支持在 Spring Messaging
消息@Header
注解。
以類似的方式驶臊,Spring的bean注射@Autowired
或@Inject
使用該信息來確定是否需要與否的bean挪挤。
@Autowired lateinit var foo: Foo
暗示Bean Foo
必須在應(yīng)用程序上下文中進(jìn)行注冊,而
@Autowired lateinit var foo: Foo?
如果這樣的Bean不存在不會引發(fā)錯(cuò)誤关翎。
如果您使用的是帶班Bean驗(yàn)證 主構(gòu)造屬性扛门,確保使用 注釋使用現(xiàn)場的目標(biāo) 在描述這個(gè)堆棧溢出響應(yīng)。
1.6纵寝。bean定義DSL
彈簧框架5介紹了使用的lambda作為替代XML或JavaConfig(功能性的方式來登記豆一種新的方式@Configuration
和@Bean
)尖飞。簡單地說,它能夠與作為一個(gè)拉姆達(dá)注冊豆FactoryBean
店雅。這個(gè)機(jī)制是非常有效的政基,因?yàn)樗恍枰魏蔚姆瓷浠駽GLIB代理。
在Java中闹啦,一個(gè)例如可以寫:
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean(Foo.class);
context.registerBean(Bar.class, () -> new Bar(context.getBean(Foo.class))
);
雖然在科特林與具體化類型參數(shù)和GenericApplicationContext
科特林?jǐn)U展一個(gè)可以代替簡單的寫:
val context = GenericApplicationContext().apply {
registerBean<Foo>()
registerBean { Bar(it.getBean<Foo>()) }
}
為了讓更聲明的方式和更清晰的語法沮明,Spring框架提供了科特林bean定義DSL 它聲明的ApplicationContextInitializer
通過一個(gè)干凈的聲明API,它使一個(gè)處理配置文件和Environment
自定義豆是如何注冊窍奋。
fun beans() = beans {
bean<UserHandler>()
bean<Routes>()
bean<WebHandler>("webHandler") {
RouterFunctions.toWebHandler(
ref<Routes>().router(),
HandlerStrategies.builder().viewResolver(ref()).build()
)
}
bean("messageSource") {
ReloadableResourceBundleMessageSource().apply {
setBasename("messages")
setDefaultEncoding("UTF-8")
}
}
bean {
val prefix = "classpath:/templates/"
val suffix = ".mustache"
val loader = MustacheResourceTemplateLoader(prefix, suffix)
MustacheViewResolver(Mustache.compiler().withLoader(loader)).apply {
setPrefix(prefix)
setSuffix(suffix)
}
}
profile("foo") {
bean<Foo>()
}
}
在這個(gè)例子中荐健,bean<Routes>()
使用由自動裝配構(gòu)造和ref<Routes>()
為捷徑applicationContext.getBean(Routes::class.java)
。
這beans()
則函數(shù)可用于注冊應(yīng)用程序上下文豆琳袄。
val context = GenericApplicationContext().apply {
beans().initialize(this)
refresh()
}
這DSL是程序化江场,從而它允許豆的定制注冊邏輯經(jīng)由if
表達(dá)式,一個(gè)for
環(huán)或任何其他科特林構(gòu)建體窖逗。
見Beans.kt 為一個(gè)具體的例子址否。
春季啟動基于Java的配置,并 沒有提供的功能bean定義中還支持碎紊,但一個(gè)實(shí)驗(yàn)可以通過Spring Boot的使用功能bean定義ApplicationContextInitializer
的支持佑附,看到這個(gè)堆棧溢出的答案 的詳細(xì)信息和先進(jìn)的最新信息。
1.7仗考。Kotlin Web
1.7.1音同。WebFlux功能DSL
Spring框架現(xiàn)在使用了 科特林路由DSL ,使人們得以充分利用WebFlux功能API編寫干凈地道科特林代碼:
router {
accept(TEXT_HTML).nest {
GET("/") { ok().render("index") }
GET("/sse") { ok().render("sse") }
GET("/users", userHandler::findAllView)
}
"/api".nest {
accept(APPLICATION_JSON).nest {
GET("/users", userHandler::findAll)
}
accept(TEXT_EVENT_STREAM).nest {
GET("/users", userHandler::stream)
}
}
resources("/**", ClassPathResource("static/"))
}
這DSL是程序化秃嗜,從而它允許豆的定制注冊邏輯經(jīng)由if
表達(dá)式权均,一個(gè)for
環(huán)或任何其他科特林構(gòu)建體顿膨。當(dāng)路由需要根據(jù)動態(tài)數(shù)據(jù)進(jìn)行登記(例如,從數(shù)據(jù)庫中)叽赊,其可以是有用的虽惭。
見MIXIT項(xiàng)目路線 的一個(gè)具體的例子。
1.7.2蛇尚⊙看剑科特林腳本模板
對于4.3版本,Spring框架提供了一個(gè) ScriptTemplateView 渲染使用的腳本引擎取劫,支持模板 JSR-223匆笤。Spring框架5走得更遠(yuǎn)通過擴(kuò)展這個(gè)功能WebFlux并支持 國際化和嵌套模板。
科特林提供類似的支持谱邪,并允許根據(jù)科特林模板渲染炮捧,看到 這次提交的詳細(xì)資料。
這使得一些有趣的使用情況-比如使用書寫類型安全模板 kotlinx.html DSL惦银,或者干脆利用科特林多String
用插咆课。
這可以允許一個(gè)寫在支持的IDE完全自動完成和重構(gòu)支持科特林模板:
import io.spring.demo.*
"""
${include("header")}
<h1>${i18n("title")}</h1>
<ul>
${users.joinToLine{ "<li>${i18n("user")} ${it.firstname} ${it.lastname}</li>" }}
</ul>
${include("footer")}
"""
見科特林腳本,模板化示例項(xiàng)目的更多細(xì)節(jié)扯俱。
1.8书蚪。在科特林的Spring項(xiàng)目
本節(jié)提供了一些具體的提示和建議值得科特林開發(fā)Spring項(xiàng)目時(shí),了解的重點(diǎn)迅栅。
1.8.1殊校。最終默認(rèn)
默認(rèn)情況下,在科特林所有的類都是final
读存。在open
一類調(diào)節(jié)劑是Java的相反final
:它允許別人從這個(gè)類繼承为流。這也適用于成員函數(shù),因?yàn)樗鼈冃枰粯?biāo)記為open
被覆蓋让簿。
雖然科特林的JVM友好的設(shè)計(jì)通常與春季摩擦敬察,這個(gè)特定的科特林功能可以防止應(yīng)用程序無法啟動,如果這一點(diǎn)不考慮拍攝尔当。這是因?yàn)榇憾雇ǔS蒀GLIB代理-比如@Configuration
類-這需要在運(yùn)行時(shí)因技術(shù)原因被繼承莲祸。解決方法是添加一個(gè)open
對CGLIB代理的Spring bean如每個(gè)類和成員函數(shù)關(guān)鍵字@Configuration
類,很快就會變得疼痛居凶,是對保持代碼簡潔和可預(yù)測的科特林原則虫给。
幸運(yùn)的是藤抡,現(xiàn)在科特林提供了一個(gè) kotlin-spring
插件侠碧,一個(gè)預(yù)配置版本kotlin-allopen
的插件,自動打開了注解的類型或元注解與以下注釋的一個(gè)類及其成員函數(shù):
@Component
@Async
@Transactional
@Cacheable
元注釋支持意味著標(biāo)注了類型@Configuration
缠黍,@Controller
弄兜, @RestController
,@Service
或者@Repository
因?yàn)檫@些注解元標(biāo)注有自動打開@Component
。
start.spring.io使得它在默認(rèn)情況下替饿,所以在實(shí)踐中你就可以寫你的科特林豆沒有任何額外的open
關(guān)鍵詞语泽,像Java中。
1.8.2视卢。使用持久不變的類實(shí)例
在科特林踱卵,這是非常方便和最佳實(shí)踐是主構(gòu)造內(nèi)聲明只讀屬性,如下面的例子:
class Person(val name: String, val age: Int)
您可以選擇添加的data
關(guān)鍵字 据过,使編譯器自動獲得來自主構(gòu)造聲明的所有屬性的成員如下:
等于()/ hashCode()方法對
toString()將形式的 “用戶(名稱=約翰惋砂,年齡= 42)”
對應(yīng)于該屬性在其聲明的順序componentN()函數(shù)
副本()函數(shù)
這可以很容易地改變,即使個(gè)別屬性Person
的屬性是只讀的:
data class Person(val name: String, val age: Int)
val jack = Person(name = "Jack", age = 1)
val olderJack = jack.copy(age = 2)
常見的持久化技術(shù)绳锅,如JPA需要一個(gè)默認(rèn)的構(gòu)造西饵,防止這種設(shè)計(jì)。幸運(yùn)的是鳞芙,現(xiàn)在這個(gè)解決辦法 “默認(rèn)構(gòu)造函數(shù)地獄” 眷柔,因?yàn)榭铺亓痔峁┝?a target="_blank" rel="nofollow">科特林,JPA 插件原朝,它生成與JPA注解類合成的無參數(shù)的構(gòu)造函數(shù)驯嘱。
如果您需要利用這種機(jī)制對其他持久化技術(shù),你可以配置科特林-noarg 插件喳坠。
|
作為凱釋放列車宙拉,春季數(shù)據(jù)支持科特林不可改變類實(shí)例和不需要kotlin-noarg
如果模塊利用彈簧數(shù)據(jù)對象映射(如使用的MongoDB,Redis的丙笋,卡桑德拉等)插件谢澈。
1.8.3。注入依賴
我們的建議是嘗試并有利于構(gòu)造注射val
只讀(和非空的可能時(shí)) 的屬性御板。
@Component
class YourBean(
private val mongoTemplate: MongoTemplate,
private val solrClient: SolrClient
)
由于Spring框架4.3的锥忿,有一個(gè)構(gòu)造函數(shù)的類都有自己的參數(shù)自動自動連接,這就是為什么沒有必要明確地@Autowired constructor
在上面顯示的例子怠肋。
如果一個(gè)人真正需要使用字段注入敬鬓,使用lateinit var
結(jié)構(gòu),即笙各,
@Component
class YourBean {
@Autowired
lateinit var mongoTemplate: MongoTemplate
@Autowired
lateinit var solrClient: SolrClient
}
1.8.4钉答。注入配置屬性
在Java中,一個(gè)可以使用注釋等注入配置屬性@Value("${property}")
杈抢,但是在科特林$
是用于保留字符串內(nèi)插数尿。
因此,如果希望使用@Value
在科特林注釋惶楼,該$
角色將需要通過寫逃脫@Value("\${property}")
右蹦。
作為替代方案诊杆,能夠以自定義屬性通過聲明以下配置豆占位前綴:
@Bean
fun propertyConfigurer() = PropertySourcesPlaceholderConfigurer().apply {
setPlaceholderPrefix("%{")
}
現(xiàn)有的代碼(如Spring引導(dǎo)致動器或@LocalServerPort
一個(gè)使用)${…?}
的語法,可以用配置Bean進(jìn)行定制何陆,例如晨汹,如下所示:
@Bean
fun kotlinPropertyConfigurer() = PropertySourcesPlaceholderConfigurer().apply {
setPlaceholderPrefix("%{")
setIgnoreUnresolvablePlaceholders(true)
}
@Bean
fun defaultPropertyConfigurer() = PropertySourcesPlaceholderConfigurer()
如果使用Spring Boot,那么 可以使用@ConfigurationProperties
替代@Value
注釋贷盲,但是目前這只能用于可空var
屬性(這遠(yuǎn)非理想)淘这,因?yàn)椴恢С钟蓸?gòu)造函數(shù)初始化的不可變類。查看有關(guān)@ConfigurationProperties
綁定不可變POJO 和@ConfigurationProperties
綁定接口 的更多詳細(xì)信息巩剖。
1.8.5慨灭。注釋陣列屬性
Kotlin注釋大部分與Java類似,但是在Spring中廣泛使用的數(shù)組屬性 - 行為不同球及。正如Kotlin文檔中所述氧骤, 與其他屬性不同,value
屬性名稱可以省略吃引,當(dāng)它是數(shù)組屬性時(shí)筹陵,它將被指定為vararg
參數(shù)。
要明白這意味著什么镊尺,讓我們@RequestMapping
朦佩,這是最廣泛使用Spring注解作為例子之一。此Java注釋聲明如下:
public @interface RequestMapping {
@AliasFor("path")
String[] value() default {};
@AliasFor("value")
String[] path() default {};
RequestMethod[] method() default {};
// ...
}
典型的使用情況@RequestMapping
是將處理程序方法映射到一個(gè)特定的路徑和方法庐氮。在Java中语稠,有可能指定注釋陣列屬性一個(gè)單一的值,它將被自動轉(zhuǎn)換成一個(gè)數(shù)組弄砍。
這就是為什么一個(gè)可以寫入 @RequestMapping(value = "/foo", method = RequestMethod.GET)
或 @RequestMapping(path = "/foo", method = RequestMethod.GET)
仙畦。
然而,在科特林音婶,一個(gè)將不得不寫@RequestMapping("/foo", method = arrayOf(RequestMethod.GET))
慨畸。使用變體path
是不推薦,因?yàn)樗枰粚懭?@RequestMapping(path = arrayOf("/foo"), method = arrayOf(RequestMethod.GET))
衣式。
一種用于此特定解決方法method
屬性(最常見的一種)是使用快捷方式注釋諸如@GetMapping
或@PostMapping
等
提醒:如果@RequestMapping
method
沒有指定屬性寸士,所有的HTTP方法將被匹配,不僅GET
方法碴卧。
改善科特林注釋陣列屬性的語法和一致性中討論 此科特林語言的設(shè)計(jì)問題弱卡。
1.8.6。測試
每類的生命周期
科特林允許指定反引號之間有意義的測試函數(shù)名住册,并作為JUnit的5個(gè)科特林測試類可以使用@TestInstance(TestInstance.Lifecycle.PER_CLASS)
注釋以使測試類的單個(gè)實(shí)例婶博,其允許使用@BeforeAll
與@AfterAll
在非靜態(tài)方法的注解,這是一個(gè)良好的配合對于科特林界弧。
現(xiàn)在可以更改默認(rèn)行為凡蜻,PER_CLASS
多虧了 junit-platform.properties
一個(gè)文件junit.jupiter.testinstance.lifecycle.default = per_class
屬性搭综。
class IntegrationTests {
val application = Application(8181)
val client = WebClient.create("http://localhost:8181")
@BeforeAll
fun beforeAll() {
application.start()
}
@Test
fun `Find all users on HTML page`() {
client.get().uri("/users")
.accept(TEXT_HTML)
.retrieve()
.bodyToMono<String>()
.test()
.expectNextMatches { it.contains("Foo") }
.verifyComplete()
}
@AfterAll
fun afterAll() {
application.stop()
}
}
規(guī)范類測試
它可以使用JUnit 5和科特林創(chuàng)建規(guī)范樣測試垢箕。
class SpecificationLikeTests {
@Nested
@DisplayName("a calculator")
inner class Calculator {
val calculator = SampleCalculator()
@Test
fun `should return the result of adding the first number to the second number`() {
val sum = calculator.sum(2, 4)
assertEquals(6, sum)
}
@Test
fun `should return the result of subtracting the second number from the first number`() {
val subtract = calculator.subtract(4, 2)
assertEquals(2, subtract)
}
}
}
WebTestClient
在科特林類型推斷問題
WebTestClient
不可用但在科特林由于 類型推理問題預(yù)計(jì)將被固定為1.3科特林的划栓。你可以看 SPR-16057以獲取最新的最新信息。同時(shí)条获,所提出的替代方案是直接用WebClient
其反應(yīng)堆和Spring科特林?jǐn)U展到嵌入式WebFlux服務(wù)器上進(jìn)行集成測試忠荞。
1.9。入門
1.9.1帅掘。start.spring.io
開始在科特林一個(gè)新的Spring框架5項(xiàng)目最簡單的方法是創(chuàng)建一個(gè)新的春天啟動二期工程start.spring.io委煤。
也可以作為描述的創(chuàng)建一個(gè)獨(dú)立的WebFlux項(xiàng)目 這個(gè)博客帖子。
1.9.2修档。選擇Web味道
Spring框架現(xiàn)在帶有2個(gè)不同的網(wǎng)絡(luò)棧:Spring MVC的和 春天WebFlux碧绞。
如果想要?jiǎng)?chuàng)建將處理時(shí)延的應(yīng)用,長期連接吱窝,流方案或干脆如果想使用網(wǎng)絡(luò)功能科特林DSL建議春季W(wǎng)ebFlux讥邻。
對于其他用途的情況下,特別是如果你使用的是封鎖的技術(shù)院峡,如JPA兴使,Spring MVC和它的基于注解的編程模型是一個(gè)完全有效的,并完全支持選擇照激。
1.10发魄。資源
1.10.1。博客文章
1.10.2。例子
彈簧引導(dǎo)科特林-演示:普通的Spring引導(dǎo)+彈簧數(shù)據(jù)JPA項(xiàng)目
MIXIT:春季啟動2 + WebFlux +無彈簧數(shù)據(jù)的MongoDB
彈簧科特林官能:獨(dú)立WebFlux +官能bean定義DSL
彈簧科特林-fullstack:WebFlux科特林與Kotlin2js fullstack例如用于前端的代替的JavaScript或打字稿
彈簧的PetClinic-科特林:春節(jié)PetClinic示例應(yīng)用中的科特林版本
1.10.3口柳。教程
1.10.4赏淌。問題
下面是有關(guān)的未決春+科特林支持問題的列表。
Spring框架
春季啟動
科特林
2.阿帕奇的Groovy
Groovy是一種功能強(qiáng)大,可選類型和動態(tài)語言荣茫,與靜態(tài)打字和靜態(tài)編譯能力想帅。它提供了一個(gè)簡潔的語法,并與任何現(xiàn)有的Java應(yīng)用程序順利集成啡莉。
Spring框架提供了一個(gè)專用ApplicationContext
港准,支持基于Groovy的bean定義DSL旨剥。有關(guān)詳細(xì)信息,請參閱 Groovy的bean定義DSL浅缸。
對Groovy轨帜,包括用Groovy,刷新腳本豆豆衩椒,更加進(jìn)一步的支持是在明年的部分提供動態(tài)語言的支持蚌父。
3.動態(tài)語言支持
3.1。介紹
彈簧2.0引入了使用類和已使用與彈簧的動態(tài)語言(例如JRuby)定義的對象的全面支持毛萌。這種支持允許你寫任意數(shù)量的類別中支持動態(tài)語言苟弛,并有Spring容器透明的實(shí)例化,配置阁将,依賴注入其最終對象膏秫。
目前支持的動態(tài)語言是:
JRuby的1.5+
Groovy的1.8+
BeanShell的2.0
為什么只有這些語言?
支持的語言被選中做盅,因?yàn)?em>一)語言有很多Java企業(yè)社區(qū)牽引缤削,B)不要求被其他語言的那個(gè)加入這一支持時(shí)作出的,而C) Spring開發(fā)者最熟悉它們言蛇。
充分的地方這個(gè)動態(tài)語言的支持可立即有用的工作實(shí)例描述場景僻他。
3.2。第一個(gè)例子
本章的大部分內(nèi)容的關(guān)注點(diǎn)都在詳細(xì)地描述動態(tài)語言的支持腊尚。潛入所有的插件和動態(tài)語言支持的細(xì)節(jié)之前吨拗,讓我們來看看在動態(tài)語言定義的bean的一個(gè)簡單的例子。第一個(gè)bean的動態(tài)語言Groovy的是(這個(gè)例子的基礎(chǔ)上婿斥,從Spring的測試套件采取的劝篷,所以如果你想看到的任何其他支持的語言相同的例子,看看源代碼)民宿。
找到下面Messenger
的Groovy的豆將要實(shí)現(xiàn)接口娇妓,并注意該接口是使用純Java定義。這與該參考注入依賴的對象Messenger
將不知道底層的實(shí)現(xiàn)是Groovy腳本活鹰。
package org.springframework.scripting;
public interface Messenger {
String getMessage();
}
下面是有一個(gè)依賴一類的定義Messenger
接口哈恰。
package org.springframework.scripting;
public class DefaultBookingService implements BookingService {
private Messenger messenger;
public void setMessenger(Messenger messenger) {
this.messenger = messenger;
}
public void processBooking() {
// use the injected Messenger object...
}
}
下面是一個(gè)實(shí)現(xiàn)Messenger
在Groovy接口。
// from the file 'Messenger.groovy'
package org.springframework.scripting.groovy;
// import the Messenger interface (written in Java) that is to be implemented
import org.springframework.scripting.Messenger
// define the implementation in Groovy
class GroovyMessenger implements Messenger {
String message
}
最后志群,這里的bean定義是將Groovy定義的注射Messenger
執(zhí)行到的實(shí)例 DefaultBookingService
類着绷。
| |
要使用自定義動態(tài)語言標(biāo)簽來定義動態(tài)語言支持豆,你需要在Spring XML配置文件的頂部相應(yīng)的XML Schema锌云。你還需要使用彈簧ApplicationContext
實(shí)現(xiàn)作為IoC容器荠医。使用動態(tài)語言的支持豆,一個(gè)普通BeanFactory
的實(shí)施是支持的,但你必須管理Spring內(nèi)部的管道這樣做彬向。
有關(guān)基于模式的配置的詳細(xì)信息兼贡,請參閱基于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:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd">
<!-- this is the bean definition for the Groovy-backed Messenger implementation -->
<lang:groovy id="messenger" script-source="classpath:Messenger.groovy">
<lang:property name="message" value="I Can Do The Frug" />
</lang:groovy>
<!-- an otherwise normal bean that will be injected by the Groovy-backed Messenger -->
<bean id="bookingService" class="x.y.DefaultBookingService">
<property name="messenger" ref="messenger" />
</bean>
</beans>
該bookingService
豆(一DefaultBookingService
)現(xiàn)在可以使用其私有 messenger
成員變量作為正常的娃胆,因?yàn)?code>Messenger這是注射到它的實(shí)例就是一個(gè)Messenger
實(shí)例遍希。沒有什么特別的地方,只是簡單的Java和Groovy的缕棵。
希望上面的XML片段是不言自明孵班,但不要過分擔(dān)心涉兽,如果事實(shí)并非如此招驴。保持閱讀在原因和上述結(jié)構(gòu)的wherefores深入的細(xì)節(jié)。
3.3枷畏。定義由動態(tài)語言支持的bean
本節(jié)描述了如何在任何支持的動態(tài)語言定義Spring管理豆别厘。
請注意,本章不試圖解釋的語法和支持的動態(tài)語言的成語拥诡。例如触趴,如果你想使用Groovy來編寫某些應(yīng)用程序中的類,那么假設(shè)是你已經(jīng)知道的Groovy渴肉。如果您需要了解和動態(tài)語言本身有關(guān)的更多細(xì)節(jié)冗懦,請參考更多的資源在這一章的結(jié)尾。
3.3.1仇祭。常見的概念
是涉及使用動態(tài)語言實(shí)現(xiàn)的bean的步驟如下:
寫測試針對動態(tài)語言的源代碼(自然)
然后編寫動態(tài)語言源碼:)
定義使用適當(dāng)?shù)膭討B(tài)語言實(shí)現(xiàn)的bean
<lang:language/>
的XML配置元素(你當(dāng)然可以定義這樣的豆使用Spring API -盡管你要咨詢的源代碼就如何做到這一點(diǎn)披蕉,因?yàn)檫@類型的方向先進(jìn)的配置不本章中)。請注意乌奇,這是一個(gè)反復(fù)的一步没讲。你需要每一個(gè)動態(tài)語言的源文件至少一個(gè)bean定義(同一個(gè)動態(tài)語言的源文件當(dāng)然可以在多個(gè)bean定義中引用)。
前兩步(測試并編寫動態(tài)語言源文件)超出了本章的范圍礁苗。請參考語言規(guī)范和/或參考手冊您選擇的動態(tài)語言爬凑,并與顯影動態(tài)語言的源文件上裂紋。你會首先要閱讀本章的其余部分试伙,如Spring的動態(tài)語言支持確實(shí)讓你的動態(tài)語言的源文件的內(nèi)容有一些(朽倚拧)的假設(shè)。
所述的<lang:language />元素
最后一步是定義動態(tài)語言支持的bean定義疏叨,一個(gè)用于您要配置(這是不正常的JavaBean配置不同)的每個(gè)bean潘靖。然而,而不是指定要被實(shí)例化和容器配置的類的完全限定類名的考廉,你可以使用 <lang:language/>
元素來定義動態(tài)語言實(shí)現(xiàn)的bean秘豹。
每個(gè)支持的語言都有一個(gè)相應(yīng)的<lang:language/>
元素:
<lang:groovy/>
(Groovy的)<lang:bsh/>
(BeanShell的)<lang:std/>
(JSR-223)
可用于配置的確切屬性和子元素正是依賴于豆已經(jīng)(以下特定語言有關(guān)的章節(jié)會揭示全部內(nèi)幕)中定義的語言。
刷新豆
其中一個(gè)(如果沒有的)Spring對動態(tài)語言支持的最引人注目的價(jià)值在于增加了對“刷新豆”功能昌粤。
可刷新的豆是一個(gè)動態(tài)語言支持的豆與配置少量既绕,動態(tài)語言支持的bean可以監(jiān)控底層源文件資源更改啄刹,然后當(dāng)動態(tài)語言源文件被改變重新加載本身(例如開發(fā)者編輯并保存更改文件在文件系統(tǒng))。
這使得開發(fā)人員以后部署任意數(shù)量的動態(tài)語言的源文件作為應(yīng)用程序的一部分凄贩,配置Spring容器來創(chuàng)建動態(tài)語言源文件支持(使用本章描述的機(jī)制)豆誓军,然后根據(jù)需求的變化或一些外部因素開始發(fā)揮作用,只需編輯動態(tài)語言源文件疲扎,并將它們會反射由已改變的動態(tài)語言源文件為bean的變化昵时。有沒有必要關(guān)閉正在運(yùn)行的應(yīng)用程序(或Web應(yīng)用程序的情況下重新部署)。動態(tài)語言支持的bean能夠自我修正椒丧,新的狀態(tài)和邏輯從改變的動態(tài)語言源文件壹甥。
| |
請注意,此功能是關(guān)閉默認(rèn)壶熏。
|
讓我們來看一個(gè)例子句柠,看看它是多么容易開始使用刷新豆。要打開的刷新豆功能棒假,你只需要明確指定 一個(gè)上附加屬性<lang:language/>
的bean定義的元素溯职。因此,如果我們堅(jiān)持的例子從本章前面帽哑,這里就是我們將在Spring XML配置變化來實(shí)現(xiàn)刷新豆:
<beans>
<!-- this bean is now 'refreshable' due to the presence of the 'refresh-check-delay' attribute -->
<lang:groovy id="messenger"
refresh-check-delay="5000" <!-- switches refreshing on with 5 seconds between checks -->
script-source="classpath:Messenger.groovy">
<lang:property name="message" value="I Can Do The Frug" />
</lang:groovy>
<bean id="bookingService" class="x.y.DefaultBookingService">
<property name="messenger" ref="messenger" />
</bean>
</beans>
這就是所有你需要做的谜酒。在'refresh-check-delay'
所定義的屬性 'messenger'
bean定義是在此之后,豆將與底層動態(tài)語言的源文件所作的任何更改被刷新的毫秒數(shù)妻枕。您可以通過分配負(fù)值的關(guān)閉刷新行為 'refresh-check-delay'
屬性僻族。請記住,在默認(rèn)情況下佳头,該刷新行為被禁止鹰贵。如果你不希望刷新行為,那么根本就沒有定義屬性康嘉。
如果我們再運(yùn)行下面的應(yīng)用程序碉输,我們可以鍛煉刷新的功能; 請?jiān)?em>“跳躍通箍到暫停中,執(zhí)行”惡作劇在這個(gè)代碼下一個(gè)切片亭珍。該System.in.read()
電話只能有這樣程序的執(zhí)行暫停敷钾,而我(作者)组底,這個(gè)時(shí)候去修改底層的動態(tài)語言源文件轴咱,以便刷新將在動態(tài)語言實(shí)現(xiàn)的bean觸發(fā)時(shí)远搪,程序繼續(xù)執(zhí)行惧眠。
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.scripting.Messenger;
public final class Boot {
public static void main(final String[] args) throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
Messenger messenger = (Messenger) ctx.getBean("messenger");
System.out.println(messenger.getMessage());
// pause execution while I go off and make changes to the source file...
System.in.read();
System.out.println(messenger.getMessage());
}
}
假設(shè)那么,在這個(gè)例子的目的始衅,是對所有呼叫 getMessage()
的方法Messenger
的實(shí)現(xiàn)必須改變摇庙,以使得該消息被引號括起來勋锤。下面是改變我(作者)做出的 Messenger.groovy
源文件時(shí),程序的執(zhí)行被暫停羊壹。
package org.springframework.scripting
class GroovyMessenger implements Messenger {
private String message = "Bingo"
public String getMessage() {
// change the implementation to surround the message in quotes
return "'" + this.message + "'"
}
public void setMessage(String message) {
this.message = message
}
}
當(dāng)程序執(zhí)行時(shí)蓖宦,在輸入暫停之前的輸出將是我可以做Frug。源文件做出更改并保存后油猫,程序繼續(xù)執(zhí)行稠茂,調(diào)用的結(jié)果getMessage()
對動態(tài)語言支持的方法Messenger
實(shí)施將是“我可以做Frug” (注意附加報(bào)價(jià)列入) 。
要明白情妖,修改腳本將是很重要的不是如果的窗口內(nèi)發(fā)生的變化觸發(fā)刷新'refresh-check-delay'
值睬关。要明白,修改劇本是同樣重要的是沒有真正“拿起”毡证,直到一個(gè)方法被調(diào)用的動態(tài)語言實(shí)現(xiàn)的bean电爹。只有當(dāng)一個(gè)方法被調(diào)用的動態(tài)語言實(shí)現(xiàn)的bean,它檢查是否它的底層腳本源發(fā)生了變化情竹。有關(guān)刷新腳本(如遇到編譯錯(cuò)誤藐不,或找到腳本文件已被刪除)的任何異常都會導(dǎo)致致命的異常傳播到調(diào)用代碼匀哄。
上述的可刷新的豆的行為并沒有適用于使用所定義的動態(tài)語言的源文件<lang:inline-script/>
元素符號(參照 內(nèi)置動態(tài)語言的源文件)秦效。此外,它僅適用于其中改變底層源文件實(shí)際上可以檢測豆; 例如涎嚼,通過檢查該文件系統(tǒng)上的存在的動態(tài)語言的源文件的最后修改日期代碼阱州。
內(nèi)置動態(tài)語言源文件
動態(tài)語言的支持也能滿足那些直接嵌入在Spring bean定義動態(tài)語言源文件。更具體地說法梯, <lang:inline-script/>
元素苔货,可以立即定義Spring配置文件中的動態(tài)語言源代碼。下面的例子或許可以將嵌入腳本功能一清二楚:
<lang:groovy id="messenger">
<lang:inline-script>
package org.springframework.scripting.groovy;
import org.springframework.scripting.Messenger
class GroovyMessenger implements Messenger {
String message
}
</lang:inline-script>
<lang:property name="message" value="I Can Do The Frug" />
</lang:groovy>
如果我們把一側(cè)周圍是否是很好的做法立哑,定義一個(gè)Spring配置文件中的動態(tài)語言源的問題夜惭,該<lang:inline-script/>
元素可以在某些情況下非常有用。例如铛绰,我們可能想快速Spring的增加Validator
實(shí)現(xiàn)的Spring MVC的Controller
诈茧。這不過是使用內(nèi)聯(lián)源片刻的工夫。(請參閱腳本驗(yàn)證器為這樣的例子捂掰。)
了解構(gòu)造器注入動態(tài)語言實(shí)現(xiàn)的bean的情況下
有一個(gè)非常要注意的是關(guān)于Spring的動態(tài)語言支持重要的事情敢会。也就是說,它不是(目前)可以提供構(gòu)造器參數(shù)这嚣,以動態(tài)語言實(shí)現(xiàn)的bean(因此構(gòu)造注射不適用于動態(tài)語言支持的bean)鸥昏。為了將構(gòu)造器和屬性100%清楚的這種特殊處理的利益,代碼和配置以下混合物將無法正常工作姐帚。
// from the file 'Messenger.groovy'
package org.springframework.scripting.groovy;
import org.springframework.scripting.Messenger
class GroovyMessenger implements Messenger {
GroovyMessenger() {}
// this constructor is not available for Constructor Injection
GroovyMessenger(String message) {
this.message = message;
}
String message
String anotherMessage
}
<lang:groovy id="badMessenger"
script-source="classpath:Messenger.groovy">
<!-- this next constructor argument will not be injected into the GroovyMessenger -->
<!-- in fact, this isn't even allowed according to the schema -->
<constructor-arg value="This will not work" />
<!-- only property values are injected into the dynamic-language-backed object -->
<lang:property name="anotherMessage" value="Passed straight through to the dynamic-language-backed object" />
</lang>
在實(shí)踐中吏垮,這種限制是不是第一次出現(xiàn),因?yàn)閟etter注入是通過反正絕大多數(shù)的開發(fā)商青睞注射風(fēng)格顯著(讓我們離開討論是否這是一件好事,以另一天)膳汪。
3.3.2像樊。的Groovy bean
Groovy依賴庫
在Spring支持的Groovy腳本需要以下庫在你的應(yīng)用程序的classpath。
groovy-1.8.jar
asm-3.2.jar
antlr-2.7.7.jar
來自Groovy官方網(wǎng)頁...
“ Groovy是一種敏捷的動態(tài)語言旅敷,Java 2平臺有很多的功能生棍,人們喜歡這么多的像Python,Ruby和Smalltalk語言媳谁,使其可使用Java的語法Java開發(fā)人員涂滴。 ”
如果您已經(jīng)閱讀從頂部本章直,你應(yīng)該已經(jīng) 看到一個(gè)例子一個(gè)Groovy的動態(tài)語言實(shí)現(xiàn)的bean的晴音。讓我們來看看另一個(gè)例子(還是選自Spring的測試套件的例子)柔纵。
package org.springframework.scripting;
public interface Calculator {
int add(int x, int y);
}
下面是一個(gè)實(shí)現(xiàn)Calculator
在Groovy接口。
// from the file 'calculator.groovy'
package org.springframework.scripting.groovy
class GroovyCalculator implements Calculator {
int add(int x, int y) {
x + y
}
}
<-- from the file 'beans.xml' -->
<beans>
<lang:groovy id="calculator" script-source="classpath:calculator.groovy"/>
</beans>
最后锤躁,這里是一個(gè)小的應(yīng)用程序來測試上面的配置搁料。
package org.springframework.scripting;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void Main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
Calculator calc = (Calculator) ctx.getBean("calculator");
System.out.println(calc.add(2, 8));
}
}
從運(yùn)行上述程序的輸出結(jié)果得到的將是(不出所料)10。(令人興奮的例子系羞,是吧郭计?記住我們的目的是為了說明這個(gè)概念,請參考動態(tài)語言的示例項(xiàng)目更復(fù)雜的例子椒振,或甚 方案本章后面)昭伸。
你是很重要的不明確Groovy源文件中不止一個(gè)類。雖然這是完全合法的Groovy中澎迎,它是(可以說)一個(gè)不好的做法:在一個(gè)一致的方法的利益庐杨,你應(yīng)該(在筆者的意見)尊重每個(gè)源文件中的一個(gè)(public)類標(biāo)準(zhǔn)Java約定。
通過回調(diào)定制Groovy對象
該GroovyObjectCustomizer
接口是一個(gè)回調(diào)夹供,它允許你將附屬的創(chuàng)建邏輯添加到創(chuàng)建一個(gè)Groovy的bean的過程灵份。例如,這個(gè)接口的實(shí)現(xiàn)可以調(diào)用任何所需的初始化方法(一個(gè)或多個(gè))哮洽,或設(shè)置某些默認(rèn)屬性值填渠,或指定自定義MetaClass
。
public interface GroovyObjectCustomizer {
void customize(GroovyObject goo);
}
Spring框架將實(shí)例你的Groovy-backed bean的實(shí)例袁铐,然后將通過創(chuàng)建GroovyObject
到指定GroovyObjectCustomizer
如果已經(jīng)定義揭蜒。你可以做任何你所提供的喜歡GroovyObject
參考:預(yù)計(jì)自定義的設(shè)置MetaClass
是什么,大多數(shù)人都希望這個(gè)回調(diào)做剔桨,你可以看到這樣做屉更,下面的例子。
public final class SimpleMethodTracingCustomizer implements GroovyObjectCustomizer {
public void customize(GroovyObject goo) {
DelegatingMetaClass metaClass = new DelegatingMetaClass(goo.getMetaClass()) {
public Object invokeMethod(Object object, String methodName, Object[] arguments) {
System.out.println("Invoking '" + methodName + "'.");
return super.invokeMethod(object, methodName, arguments);
}
};
metaClass.initialize();
goo.setMetaClass(metaClass);
}
}
元編程的完整討論Groovy已經(jīng)超出了本參考手冊的范圍洒缀。查閱Groovy參考手冊的相關(guān)部分瑰谜,或者做一個(gè)網(wǎng)上搜索:有大量的關(guān)于這方面的文章欺冀。其實(shí)利用的GroovyObjectCustomizer
是容易的,如果你使用的是Spring命名空間支持萨脑。
<!-- define the GroovyObjectCustomizer just like any other bean -->
<bean id="tracingCustomizer" class="example.SimpleMethodTracingCustomizer"/>
<!-- ... and plug it into the desired Groovy bean via the 'customizer-ref' attribute -->
<lang:groovy id="calculator"
script-source="classpath:org/springframework/scripting/groovy/Calculator.groovy"
customizer-ref="tracingCustomizer"/>
如果你不使用Spring命名空間的支持隐轩,你仍然可以使用的 GroovyObjectCustomizer
功能。
<bean id="calculator" class="org.springframework.scripting.groovy.GroovyScriptFactory">
<constructor-arg value="classpath:org/springframework/scripting/groovy/Calculator.groovy"/>
<!-- define the GroovyObjectCustomizer (as an inner bean) -->
<constructor-arg>
<bean id="tracingCustomizer" class="example.SimpleMethodTracingCustomizer"/>
</constructor-arg>
</bean>
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
| |
由于Spring框架4.3.3渤早,你也可以指定一個(gè)Groovy CompilationCustomizer
(如ImportCustomizer
)职车,或者甚至是完全的Groovy CompilerConfiguration
在同一個(gè)地方作為春天的對象GroovyObjectCustomizer
。
|
3.3.3鹊杖。BeanShell的豆
BeanShell的依賴庫
在Spring支持的BeanShell腳本需要以下庫在你的應(yīng)用程序的classpath悴灵。
bsh-2.0b4.jar
來自BeanShell官方網(wǎng)頁...
“ BeanShell的是一個(gè)小的,自由的骂蓖,可嵌入的Java源代碼解釋器具有動態(tài)語言功能积瞒,用Java編寫的。BeanShell動態(tài)執(zhí)行標(biāo)準(zhǔn)的Java語法和與常見的腳本的便利登下,如松散類型延伸它茫孔,命令和方法封閉像那些在Perl和JavaScript 。 “
和Groovy相比被芳,基于BeanShell的bean定義需要一些(戌直础)的額外配置。Spring對BeanShell動態(tài)語言支持的實(shí)現(xiàn)是有趣的地方是這樣的:春創(chuàng)建了JDK動態(tài)代理實(shí)現(xiàn)在指定的接口'script-interfaces'
中的屬性值<lang:bsh>
元素(這就是為什么你必須至少提供一個(gè)接口中的屬性筐钟,以及使用基于BeanShell的豆時(shí)(相應(yīng)地)程序接口)的值揩瞪。這意味著,基于BeanShell對象的每一個(gè)方法調(diào)用正在經(jīng)歷的JDK動態(tài)代理調(diào)用機(jī)制篓冲。
讓我們來看看使用它實(shí)現(xiàn)了一個(gè)基于BeanShell的bean的可工作的完整例子Messenger
這是本章(下面重復(fù)為了您的方便)在早期定義的接口。
package org.springframework.scripting;
public interface Messenger {
String getMessage();
}
這里是的BeanShell的“執(zhí)行”(該術(shù)語的隨意) Messenger
接口宠哄。
String message;
String getMessage() {
return message;
}
void setMessage(String aMessage) {
message = aMessage;
}
而這里的Spring XML定義了上述“類”的一個(gè)“實(shí)例”(這里對術(shù)語的使用非常的隨意)壹将。
<lang:bsh id="messageService" script-source="classpath:BshMessenger.bsh"
script-interfaces="org.springframework.scripting.Messenger">
<lang:property name="message" value="Hello World!" />
</lang:bsh>
見方案對于某些情況下,您可能希望使用基于BeanShell的bean毛嫉。
3.4诽俯。方案
這里定義Spring管理豆腳本語言可能出現(xiàn)的情況將是有益的,當(dāng)然承粤,多種多樣的暴区。本節(jié)介紹Spring對動態(tài)語言支持兩種可能的使用情況。
3.4.1辛臊。腳本Spring MVC控制器
那可以使用動態(tài)語言支持的bean得益于有一組類是Spring MVC的控制器仙粱。在純Spring MVC應(yīng)用中,導(dǎo)航流程通過web應(yīng)用是通過在Spring MVC的控制器內(nèi)包封的碼來確定在很大程度上彻舰。作為一個(gè)Web應(yīng)用程序的導(dǎo)航流程和其他表示層邏輯需要進(jìn)行更新伐割,以應(yīng)對支持問題或變化的業(yè)務(wù)需求候味,它很可能會更容易通過編輯一個(gè)或多個(gè)動態(tài)語言源文件,看到那些進(jìn)行任何此類要求的變化變化被立即反映在正在運(yùn)行的應(yīng)用程序的狀態(tài)隔心。
請記住白群,在由項(xiàng)目支持的輕量級架構(gòu)模型如Spring,你通常目標(biāo)是有一個(gè)非常薄的表示層硬霍,所有的應(yīng)用程序的肉香業(yè)務(wù)邏輯被包含在域和服務(wù)層的類帜慢。開發(fā)Spring MVC控制器動態(tài)語言實(shí)現(xiàn)的bean允許你通過簡單的編輯保存文本文件就可以修改表示層邏輯; 這樣的動態(tài)語言的源文件的任何更改將(取決于配置)在由動態(tài)語言的源文件備份豆自動反映。
| |
為了實(shí)現(xiàn)的任何變化動態(tài)語言支持的bean這一自動“皮卡”唯卖,你將不得不啟用'refreshable bean的功能崖堤。見 刷新的豆子一個(gè)完整的處理這個(gè)功能的。
|
請看下面的一個(gè)例子org.springframework.web.servlet.mvc.Controller
是使用Groovy動態(tài)語言實(shí)現(xiàn)耐床。
// from the file '/WEB-INF/groovy/FortuneController.groovy'
package org.springframework.showcase.fortune.web
import org.springframework.showcase.fortune.service.FortuneService
import org.springframework.showcase.fortune.domain.Fortune
import org.springframework.web.servlet.ModelAndView
import org.springframework.web.servlet.mvc.Controller
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
class FortuneController implements Controller {
@Property FortuneService fortuneService
ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse httpServletResponse) {
return new ModelAndView("tell", "fortune", this.fortuneService.tellFortune())
}
}
<lang:groovy id="fortune"
refresh-check-delay="3000"
script-source="/WEB-INF/groovy/FortuneController.groovy">
<lang:property name="fortuneService" ref="fortuneService"/>
</lang:groovy>
3.4.2密幔。腳本校驗(yàn)
可通過動態(tài)語言支持的bean提供的靈活性,有利于應(yīng)用開發(fā)與Spring的另一個(gè)領(lǐng)域是驗(yàn)證撩轰。它可能 是更容易使用松散類型的動態(tài)語言(也可能有內(nèi)置正則表達(dá)式的支持)胯甩,而不是常規(guī)的Java來表達(dá)復(fù)雜的驗(yàn)證邏輯。
再次堪嫂,制定驗(yàn)證動態(tài)語言實(shí)現(xiàn)的bean可以讓你通過簡單的編輯和保存一個(gè)簡單的文本文件來改變驗(yàn)證邏輯; 任何這樣的改變將(取決于配置)自動反映在運(yùn)行中的應(yīng)用程序的執(zhí)行并且不需要應(yīng)用程序的重新啟動偎箫。
| |
請注意,為了實(shí)現(xiàn)的任何變化動態(tài)語言支持的bean自動“皮卡”皆串,你將不得不啟用“刷新豆”功能淹办。見刷新的豆子一個(gè)完整和詳細(xì)的治療此功能。
|
下面為一個(gè)春天的一個(gè)例子org.springframework.validation.Validator
是使用Groovy動態(tài)語言實(shí)現(xiàn)恶复。(請參閱使用Spring的Validator接口驗(yàn)證的的討論 Validator
接口)怜森。
import org.springframework.validation.Validator
import org.springframework.validation.Errors
import org.springframework.beans.TestBean
class TestBeanValidator implements Validator {
boolean supports(Class clazz) {
return TestBean.class.isAssignableFrom(clazz)
}
void validate(Object bean, Errors errors) {
if(bean.name?.trim()?.size() > 0) {
return
}
errors.reject("whitespace", "Cannot be composed wholly of whitespace.")
}
}
3.5。位和鮑勃
最后一節(jié)包含了一些位和相關(guān)的動態(tài)語言支持羈絆谤牡。
3.5.1副硅。AOP - 通知腳本化bean
它可以使用Spring AOP框架建議腳本豆。Spring AOP框架實(shí)際上是不知道正在被通知一個(gè)bean可能是一個(gè)腳本豆翅萤,所以所有的AOP的使用情況和功能恐疲,你可能會使用或旨在利用將與腳本豆類工作。只有一個(gè)套么,你需要知道通知腳本化bean時(shí)的(信嗉骸)的東西......你不能使用基于類的代理,則必須使用基于接口的代理胚泌。
你當(dāng)然不局限于通知腳本豆...你也可以寫在一個(gè)支持動態(tài)語言本身方面和使用這些bean來提醒其他的Spring bean省咨。這確實(shí)是一個(gè)先進(jìn)的使用動態(tài)語言的支持,雖然诸迟。
3.5.2茸炒。作用域
在情況下愕乎,它是不是很明顯,腳本化bean當(dāng)然可以壁公,就像任何其他的bean作用域感论。在scope
對各種屬性<lang:language/>
的元素可以讓你控制底層腳本bean的范圍,只是因?yàn)樗c常規(guī)的豆一樣紊册。(默認(rèn)范圍單比肄,只是因?yàn)樗桥c“常規(guī)”豆)。
發(fā)現(xiàn)下面使用的示例scope
屬性來定義作用域作為一個(gè)Groovy豆原型囊陡。
<?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:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd">
<lang:groovy id="messenger" script-source="classpath:Messenger.groovy" scope="prototype">
<lang:property name="message" value="I Can Do The RoboCop" />
</lang:groovy>
<bean id="bookingService" class="x.y.DefaultBookingService">
<property name="messenger" ref="messenger" />
</bean>
</beans>
見Bean的作用域中的IoC容器 在Spring框架的作用域支持的更詳細(xì)的討論芳绩。
3.5.3。Lang XML模式
在lang
與暴露已寫入動態(tài)語言如JRuby的或Groovy為Spring容器豆對象Spring XML配置協(xié)議的標(biāo)簽撞反。
這些標(biāo)簽(和動態(tài)語言的支持)的全面覆蓋在章標(biāo)題為動態(tài)語言支持妥色。請不要咨詢,了解該支持全細(xì)節(jié)和該章節(jié)lang
標(biāo)簽本身遏片。
為了完整起見嘹害,為了使用lang
模式中的標(biāo)簽,您需要在Spring XML配置文件的頂部有以下前導(dǎo)碼; 以下片段中的文本引用了正確的模式吮便,以便可以使用lang
名稱空間中的標(biāo)記笔呀。
<?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:lang="http://www.springframework.org/schema/lang" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd"> <!-- bean definitions here -->
</beans>
3.6。更多資源
查找以下鏈接髓需,了解有關(guān)本章介紹的各種動態(tài)語言的更多資源许师。
在JRuby的主頁
在Groovy的主頁
該BeanShell的主頁