【Spring】Spring Framework Reference Documentation中文版32

来源:互联网 发布:阿里云域名过户流程 编辑:程序博客网 时间:2024/06/18 10:31

35. Dynamic language support

动态语言支持

 

35.1 Introduction

介绍

 

Spring 2.0 introduces comprehensive support for using classes and objects that have been defined using a dynamic language (such as JRuby) with Spring. This support allows you to write any number of classes in a supported dynamic language, and have the Spring container transparently instantiate, configure and dependency inject the resulting objects.

spring2.0引入了复杂的支持用于使用类和object定义使用动态语言(例如JRuby)。这个支持允许你写一定数量的class用支持的语言并且使用spring容器显式的实例化、配置和依赖注入到结果object

 

The dynamic languages currently supported are:

目前支持的动态语言是:

 

    JRuby 1.5+

    Groovy 1.8+

    BeanShell 2.0

 

Why only these languages?

为什么是这些语言

 

The supported languages were chosen because a) the languages have a lot of traction in the Java enterprise community, b) no requests were made for other languages at the time that this support was added, and c) the Spring developers were most familiar with them.

这些语言被选中的原因是:a,语言有一定量的作用在Java的企业社区。b,同时没有对于其他语言的需求。cspring开发者十分熟悉她们。

 

Fully working examples of where this dynamic language support can be immediately useful are described in Section 35.4,Scenarios.

动态语言支持的全部的例子描述在章节35.4,“场景”中。

 

35.2 A first example

第一个例子

 

This bulk of this chapter is concerned with describing the dynamic language support in detail. Before diving into all of the ins and outs of the dynamic language support, lets look at a quick example of a bean defined in a dynamic language. The dynamic language for this first bean is Groovy (the basis of this example was taken from the Spring test suite, so if you want to see equivalent examples in any of the other supported languages, take a look at the source code).

这个章节的描述了动态语言支持的细节。在深入他们之前,让我们看一个定义在动态语言中的bean。这个动态语言是Groovy(这个例子来自spring的测试包,因此如果你希望看到相同功能的其他语言代码请查询源码)。

 

Find below the Messenger interface that the Groovy bean is going to be implementing, and note that this interface is defined in plain Java. Dependent objects that are injected with a reference to the Messenger wont know that the underlying implementation is a Groovy script.

找到下面的Messenger接口,Groovybean已经将其实现,并且通知这个接口被定义在普通的Java中。独立的object注入了一个引用对于Messenger并且不会被底层应用指导是一个Groovy的脚本。

 

package org.springframework.scripting;

 

public interface Messenger {

 

    String getMessage();

 

}

 

Here is the definition of a class that has a dependency on the Messenger interface.

这里是类的定义有一个独立的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...

    }

 

}

 

Here is an implementation of the Messenger interface in Groovy.

这里是一个Groovy实现的Messenger接口。

 

// 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

 

}

 

Finally, here are the bean definitions that will effect the injection of the Groovy-defined Messenger implementation into an instance of the DefaultBookingService class.

最后,这里是bean的定义将影响Groovy定义的Messenger的注入实现到DefaultBookingService类中。

 

[Note]

注意

 

To use the custom dynamic language tags to define dynamic-language-backed beans, you need to have the XML Schema preamble at the top of your Spring XML configuration file. You also need to be using a Spring ApplicationContext implementation as your IoC container. Using the dynamic-language-backed beans with a plain BeanFactory implementation is supported, but you have to manage the plumbing of the Spring internals to do so.

为了使用自定义的语言标签来定义dynamic-language-backedbean,你需要有一个xmlSchema在你springxml配置文件的头部。你也需要使用一个springApplicationContext实现作为你的IOC容器。使用dynamic-language-backedbean在一个普通的BeanFactory实现中是支持的,但是你必须管理spring的内部设施来实现这个目的。

 

For more information on schema-based configuration, see Chapter 41, XML Schema-based configuration.

对于更多基于schema的配置,见章节41,基于Schema的配置。

 

<?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>

 

The bookingService bean (a DefaultBookingService) can now use its private messenger member variable as normal because the Messenger instance that was injected into it is a Messenger instance. There is nothing special going on here, just plain Java and plain Groovy.

bookingServicebean现在可以使用它的私有messenger成员变量作为普通的Messenger实例被注入到Messenger实例中。这里没有什么特别的,只是普通的Java和普通的Groovy

 

Hopefully the above XML snippet is self-explanatory, but dont worry unduly if it isnt. Keep reading for the in-depth detail on the whys and wherefores of the above configuration.

上面的xml片段是十分简单的,不用担心无法理解。可以通过配置来了解其中的细节。

 

35.3 Defining beans that are backed by dynamic languages

定义bean使用动态语言作为后备

 

This section describes exactly how you define Spring managed beans in any of the supported dynamic languages.

这个章节描述了你如何配置spring管理的bean对于支持的动态语言。

 

Please note that this chapter does not attempt to explain the syntax and idioms of the supported dynamic languages. For example, if you want to use Groovy to write certain of the classes in your application, then the assumption is that you already know Groovy. If you need further details about the dynamic languages themselves, please consult Section 35.6,Further Resourcesat the end of this chapter.

请注意这个章节没有试图解释动态语言的语法和习惯。例如,如果你希望使用Groovy来书写class在你的应用中,则你应该已经学会了Groovy。如果你需要了解动态语言,请参考章节35.6,“更多资源”在本章的末尾。

 

35.3.1 Common concepts

通用的内容

 

The steps involved in using dynamic-language-backed beans are as follows:

使用dynamic-language-backedbean的步骤如下:

 

    Write the test for the dynamic language source code (naturally)

书写测试用于动态语言代码

    Then write the dynamic language source code itself :)

书写动态语言源代码

    Define your dynamic-language-backed beans using the appropriate <lang:language/> element in the XML configuration (you can of course define such beans programmatically using the Spring API - although you will have to consult the source code for directions on how to do this as this type of advanced configuration is not covered in this chapter). Note this is an iterative step. You will need at least one bean definition per dynamic language source file (although the same dynamic language source file can of course be referenced by multiple bean definitions).

定义你的dynamic-language-backedbean使用适当的<lang:language/>元素在xml配置中(你可以定义这样的bean使用springAPI————尽管你必须参考源代码来了解如何去做这个类型的配置在本节中并未包含)。注意这是一个迭代的过程。你需要至少一个bean的定义对于每个动态语言的源码文件(尽管相同的语言文件中包含多个bean的定义)。

 

The first two steps (testing and writing your dynamic language source files) are beyond the scope of this chapter. Refer to the language specification and / or reference manual for your chosen dynamic language and crack on with developing your dynamic language source files. You will first want to read the rest of this chapter though, as Springs dynamic language support does make some (small) assumptions about the contents of your dynamic language source files.

最初的两步(测试和书写你的动态语言源码文件)不在本章的介绍范围内。参考语言的定义对于你选择的动态语言并且致力于开发你的动态语言源代码文件。你将首先读取这个章节作为spring动态语言支持作为假设有关你动态语言文件中的内容。

 

The <lang:language/> element

 

The final step involves defining dynamic-language-backed bean definitions, one for each bean that you want to configure (this is no different from normal JavaBean configuration). However, instead of specifying the fully qualified classname of the class that is to be instantiated and configured by the container, you use the <lang:language/> element to define the dynamic language-backed bean.

最后一个步骤定义dynamic-language-backedbean的定义,用于每个bean你希望配置(和普通的bean的配置没有区别)。然而,代替定义全限定名对于类可以被实例化和配置通过容器,你需要使用<lang:language/>元素来定义你的动态语言后备的bean

 

Each of the supported languages has a corresponding <lang:language/> element:

每个支持的语言都有一个相应的<lang:language/>元素。

 

    <lang:jruby/> (JRuby)

    <lang:groovy/> (Groovy)

    <lang:bsh/> (BeanShell)

 

The exact attributes and child elements that are available for configuration depends on exactly which language the bean has been defined in (the language-specific sections below provide the full lowdown on this).

额外的属性和子元素可以用于配置依赖语言定义在(指定语言片段展示如下)。

 

Refreshable beans

 

One of the (if not the) most compelling value adds of the dynamic language support in Spring is the'refreshable bean' feature.

对于在spring中加入动态语言支持的最重要的目的是实现刷新的特性。

 

A refreshable bean is a dynamic-language-backed bean that with a small amount of configuration, a dynamic-language-backed bean can monitor changes in its underlying source file resource, and then reload itself when the dynamic language source file is changed (for example when a developer edits and saves changes to the file on the filesystem).

一个可以被刷新的bean是一个动态语言的后备bean使用一定的配置,一个动态语言后备的bean可以监控修改对于底层的源文件并且重新加载如果动态语言的源文件被修改了(例如当一个开发者编辑和保存并且改变了文件系统中的文件内容)。

 

This allows a developer to deploy any number of dynamic language source files as part of an application, configure the Spring container to create beans backed by dynamic language source files (using the mechanisms described in this chapter), and then later, as requirements change or some other external factor comes into play, simply edit a dynamic language source file and have any change they make reflected in the bean that is backed by the changed dynamic language source file. There is no need to shut down a running application (or redeploy in the case of a web application). The dynamic-language-backed bean so amended will pick up the new state and logic from the changed dynamic language source file.

这语言开发者部署一定数量的动态语言源文件作为应用的一部分,配置spring的容器来创建bean通过动态语言文件(使用本章描述的策略),并且作为要求改变或一些额外的因此需要处理,简单的编辑动态语言源文件并且任何改变都会反应在bean中通过后备动态语言文件修改。这不需要关闭一个正在运行的应用(或重新部署web应用)。动态语言后备的bean因此将启用新的状态和逻辑来自于已经改变的动态源文件。

 

[Note]

注意

 

Please note that this feature is off by default.

请注意这个特性默认是关闭的。

 

Lets take a look at an example to see just how easy it is to start using refreshable beans. To turn on the refreshable beans feature, you simply have to specify exactly one additional attribute on the <lang:language/> element of your bean definition. So if we stick with the example from earlier in this chapter, heres what we would change in the Spring XML configuration to effect refreshable beans:

让我们看一个例子来展示如何简单的使用通过使用可更新的bean。为了打开这个bean的特性,你需要指定一个额外的属性在你的bean的定义的<lang:language/>元素上。因此如果我们修改之前的一个例子,这里我们改变xml的配置使他成为可更新的bean

 

<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>

 

That really is all you have to do. The 'refresh-check-delay' attribute defined on the 'messenger' bean definition is the number of milliseconds after which the bean will be refreshed with any changes made to the underlying dynamic language source file. You can turn off the refresh behavior by assigning a negative value to the 'refresh-check-delay' attribute. Remember that, by default, the refresh behavior is disabled. If you dont want the refresh behavior, then simply dont define the attribute.

这是你需要做的。refresh-check-delay属性定义在messengerbean的定义中是一个毫秒单位的数值指定这个bean将被更新通过底层的动态语言文件。你可以关闭更新的行为或标记一个负值给这个属性。记住,默认的更新是被关闭的。如果你不希望更新行为,可以不定义这个属性。

 

If we then run the following application we can exercise the refreshable feature; please do excuse the 'jumping-through-hoops-to-pause-the-execution' shenanigans in this next slice of code. The System.in.read() call is only there so that the execution of the program pauses while I (the author) go off and edit the underlying dynamic language source file so that the refresh will trigger on the dynamic-language-backed bean when the program resumes execution.

如果我们运行下面的应用我们可以测试刷新的特性:请执行'jumping-through-hoops-to-pause-the-execution'的恶作剧在下一个代码的片段中。System.in.read()调用将因此执行程序暂停当我关闭和编辑底层的动态语言源文件因此刷新将被触发对于动态语言的后备bean当程序恢复执行时。

 

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());

    }

}

 

Lets assume then, for the purposes of this example, that all calls to the getMessage() method of Messenger implementations have to be changed such that the message is surrounded by quotes. Below are the changes that I (the author) make to the Messenger.groovy source file when the execution of the program is paused.

我们假设这个例子的目的,所有对于getMessage方法的调用有关Messenger实现已经被改变因此message被引号包裹。下面是改变使得Messenger.groovy源代码文件在程序暂停时被执行。

 

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

    }

}

 

When the program executes, the output before the input pause will be I Can Do The Frug. After the change to the source file is made and saved, and the program resumes execution, the result of calling the getMessage() method on the dynamic-language-backed Messenger implementation will be 'I Can Do The Frug' (notice the inclusion of the additional quotes).

当程序执行,输入之前的输出将是I Can Do The Frug。改变源文件之后,程序恢复执行,调用getMessage方法对于dynamic-language-backedMessenger的实现将会是'I Can Do The Frug',添加了引号。

 

It is important to understand that changes to a script will not trigger a refresh if the changes occur within the window of the 'refresh-check-delay' value. It is equally important to understand that changes to the script are not actually 'picked up' until a method is called on the dynamic-language-backed bean. It is only when a method is called on a dynamic-language-backed bean that it checks to see if its underlying script source has changed. Any exceptions relating to refreshing the script (such as encountering a compilation error, or finding that the script file has been deleted) will result in a fatal exception being propagated to the calling code.

这是重要的理解改变脚本将不会触发刷新如果改变发生在'refresh-check-delay'的值中。这是重要的理解脚本没有实际被调用直到一个方法对于动态语言后备bean的调用。当方法被调用对于dynamic-language-backedbean,他检查如果底层文件被改变。任何异常依赖于刷新脚本(例如作为一个编译错误或发现脚本文件被删除)将导致一个致命的错误对于代码的调用。

 

The refreshable bean behavior described above does not apply to dynamic language source files defined using the <lang:inline-script/> element notation (see the section calledInline dynamic language source files). Additionally, it only applies to beans where changes to the underlying source file can actually be detected; for example, by code that checks the last modified date of a dynamic language source file that exists on the filesystem.

可更新行为描述在上面没有应用于动态语言源文件定义使用了<lang:inline-script/>元素(将章节“内嵌的动态语言源文件”)。此外,应用于bean当改变了底层的源文件可以实际被探测到,例如,通过代码检查动态语言文件的修改日期对于文件系统。

 

Inline dynamic language source files

内嵌动态语言源文件

 

The dynamic language support can also cater for dynamic language source files that are embedded directly in Spring bean definitions. More specifically, the <lang:inline-script/> element allows you to define dynamic language source immediately inside a Spring configuration file. An example will perhaps make the inline script feature crystal clear:

动态语言支持可以配合动态语言源文件直接内嵌到springbean的定义中。更加确切的,<lang:inline-script/>元素允许你定义动态源代码实现在spring的配置文件中。一个例子将展示内嵌的脚本特性。

 

<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>

 

If we put to one side the issues surrounding whether it is good practice to define dynamic language source inside a Spring configuration file, the <lang:inline-script/> element can be useful in some scenarios. For instance, we might want to quickly add a Spring Validator implementation to a Spring MVC Controller. This is but a moments work using inline source. (See Section 35.4.2,Scripted Validatorsfor such an example.)

如果我们将问题放在一边对于定义源文件是一个好的选择在spring的配置文件中,<lang:inline-script/>元素可以在一些场景下使用。例如,实例,我们希望田间一个springmvc的控制器的spring validator实现。这是使用内嵌的好处。(将章节35.4.2,“脚本验证”用于一个例子。)

 

Find below an example of defining the source for a JRuby-based bean directly in a Spring XML configuration file using the inline: notation. (Notice the use of the < characters to denote a '<' character. In such a case surrounding the inline source in a <![CDATA[]]> region might be better.)

下面的例子定义了一个基于JRubybeanspringxml配置中使用内嵌。(注意<字符的使用来表示<字符。在这样的情况下围绕内部源码的是<![CDATA[]]>可以更好。

 

<lang:jruby id="messenger" script-interfaces="org.springframework.scripting.Messenger">

    <lang:inline-script>

 

require 'java'

 

include_class 'org.springframework.scripting.Messenger'

 

class RubyMessenger < Messenger

 

    def setMessage(message)

        @@message = message

    end

 

    def getMessage

        @@message

    end

 

end

 

        </lang:inline-script>

    <lang:property name="message" value="Hello World!" />

</lang:jruby>

 

Understanding Constructor Injection in the context of dynamic-language-backed beans

理解动态语言后备bean的构造器注入

 

There is one very important thing to be aware of with regard to Springs dynamic language support. Namely, it is not (currently) possible to supply constructor arguments to dynamic-language-backed beans (and hence constructor-injection is not available for dynamic-language-backed beans). In the interests of making this special handling of constructors and properties 100% clear, the following mixture of code and configuration will not work.

这是很重要的有关作为spring的动态语言支持。也就是,可以应用构造器参数对于动态语言后备bean(并且constructor-injection并不是动态语言的后备bean)。在处理控制器和属性是很干净的,下面是最少的配置工作。

 

// 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>

 

In practice this limitation is not as significant as it first appears since setter injection is the injection style favored by the overwhelming majority of developers anyway (lets leave the discussion as to whether that is a good thing to another day).

例子是没有任何含义的作为他首次出现设置注入是注入风格通过开发者的方式(让我们放弃讨论思考如何做到更好)。

 

35.3.2 JRuby beans

 

The JRuby library dependencies

JRuby库的依赖

 

The JRuby scripting support in Spring requires the following libraries to be on the classpath of your application.

JRuby脚本支持在spring中需要下面的库被加入到classpath中。

 

    jruby.jar

 

From the JRuby homepage?

来自JRuby的官方主页……

 

"JRuby is an 100% pure-Java implementation of the Ruby programming language."

JRuby是一个100%的出Java实现对于Ruby编程语言。

 

In keeping with the Spring philosophy of offering choice, Springs dynamic language support also supports beans defined in the JRuby language. The JRuby language is based on the quite intuitive Ruby language, and has support for inline regular expressions, blocks (closures), and a whole host of other features that do make solutions for some domain problems a whole lot easier to develop.

为了保证spring的哲理对于选择,spring的动态语言支持也支持bean定义通过JRuby语言。JRuby语言是基于Ruby语言,并且支持内嵌的正则表达式,块和其他特性对于一些主要问题的解决方案便于开发。

 

The implementation of the JRuby dynamic language support in Spring is interesting in that what happens is this: Spring creates a JDK dynamic proxy implementing all of the interfaces that are specified in the 'script-interfaces' attribute value of the <lang:ruby> element (this is why you must supply at least one interface in the value of the attribute, and (accordingly) program to interfaces when using JRuby-backed beans).

JRuby动态语言支持的实现是有意义的对于发生了什么:spring创建了一个JDK的动态代理实现了所有的接口被定义在script-interfaces属性值对于<lang:ruby>元素(这也是为什么你必须应用至少一个接口对于属性值并且程序对于接口当使用JRuby的后备bean时)。

 

Let us look at a fully working example of using a JRuby-based bean. Here is the JRuby implementation of the Messenger interface that was defined earlier in this chapter (for your convenience it is repeated below).

让我们看一个完整的例子有关使用基于JRubybean。这是一个JRuby实现Messenger接口定义在之前的章节中(为了方便重复一下)。

 

package org.springframework.scripting;

 

public interface Messenger {

 

    String getMessage();

 

}

 

require 'java'

 

class RubyMessenger

    include org.springframework.scripting.Messenger

 

    def setMessage(message)

        @@message = message

    end

 

    def getMessage

        @@message

    end

end

 

# this last line is not essential (but see below)

RubyMessenger.new

 

And here is the Spring XML that defines an instance of the RubyMessenger JRuby bean.

这里是springxml定义了RubyMessengerJRubybean的实例。

 

<lang:jruby id="messageService"

        script-interfaces="org.springframework.scripting.Messenger"

        script-source="classpath:RubyMessenger.rb">

 

    <lang:property name="message" value="Hello World!" />

 

</lang:jruby>

 

Take note of the last line of that JRuby source ( 'RubyMessenger.new'). When using JRuby in the context of Springs dynamic language support, you are encouraged to instantiate and return a new instance of the JRuby class that you want to use as a dynamic-language-backed bean as the result of the execution of your JRuby source. You can achieve this by simply instantiating a new instance of your JRuby class on the last line of the source file like so:

注意JRuby源文件的最后一行( 'RubyMessenger.new')。当使用JRubyspring动态语言支持的内容时,你需要初始化并且返回一个新的实例对于JRuby的类使得你希望使用它作为一个动态语言后备的bean作为执行你的JRuby源码的结果。你可以打包他们通过简单的实例化你的JRuby类对于源文件的最后一行如下:

 

require 'java'

 

include_class 'org.springframework.scripting.Messenger'

 

# class definition same as above...

 

# instantiate and return a new instance of the RubyMessenger class

RubyMessenger.new

 

If you forget to do this, it is not the end of the world; this will however result in Spring having to trawl (reflectively) through the type representation of your JRuby class looking for a class to instantiate. In the grand scheme of things this will be so fast that youll never notice it, but it is something that can be avoided by simply having a line such as the one above as the last line of your JRuby script. If you dont supply such a line, or if Spring cannot find a JRuby class in your script to instantiate then an opaque ScriptCompilationException will be thrown immediately after the source is executed by the JRuby interpreter. The key text that identifies this as the root cause of an exception can be found immediately below (so if your Spring container throws the following exception when creating your dynamic-language-backed bean and the following text is there in the corresponding stacktrace, this will hopefully allow you to identify and then easily rectify the issue):

如果你忘记这么做,也不是很大的问题。这会导致spring被拖慢由于JRuby的类来查找一个实例。一般情况下他会很快以至于你都无法发现他,但是有时他可以不避免通过JRuby脚本的最后一行。如果你没有提供这样的一行或如果spring不能找到一个JRuby类来实例化则ScriptCompilationException将被立刻抛出在源代码被JRuby拦截器执行之后。关键文本展示了异常的触发点可以直接被发现如下(因此如果你的spring容器抛出下面的异常当创建你动态语言后备的bean和下面的文本在相应的栈信息中,将帮助你定位和尽快处理问题):

 

org.springframework.scripting.ScriptCompilationException: Compilation of JRuby script returned ''

 

To rectify this, simply instantiate a new instance of whichever class you want to expose as a JRuby-dynamic-language-backed bean (as shown above). Please also note that you can actually define as many classes and objects as you want in your JRuby script; what is important is that the source file as a whole must return an object (for Spring to configure).

为了改正,简单的实例化一个新的实例对于你希望暴露作为一个JRuby动态语言后备的baen(展示如上)。请注意你可以直接定义许多的类和object作为你希望出现在你的Ruby的脚本中;重要的是源文件必须返回一个object(用于spring的配置)。

 

See Section 35.4, Scenariosfor some scenarios where you might want to use JRuby-based beans.

将章节35.4,“场景”用于一些你可能会使用基于JRubybean

 

35.3.3 Groovy beans

 

The Groovy library dependencies

Groovy库依赖

 

The Groovy scripting support in Spring requires the following libraries to be on the classpath of your application.

Groovy脚本支持在spring需要将下面的库放入你应用的classpath中。

 

    groovy-1.8.jar

    asm-3.2.jar

    antlr-2.7.7.jar

 

From the Groovy homepage…​

来自Groovy的主页

 

"Groovy is an agile dynamic language for the Java 2 Platform that has many of the features that people like so much in languages like Python, Ruby and Smalltalk, making them available to Java developers using a Java-like syntax. "

Groovy是一个敏捷的动态语言用于Java2平台有许多的特性类似于PythonRubySmalltalk,使得可以用于Java开发者使用类似于Java的语法“

 

If you have read this chapter straight from the top, you will already have seen an example of a Groovy-dynamic-language-backed bean. Lets look at another example (again using an example from the Spring test suite).

如果你有从头开始阅读这一章,你可能已经看到了一个有关Groovy动态语言的后备bean。让我们看一下一个其他的例子(使用来自spring测试包中的例子)。

 

package org.springframework.scripting;

 

public interface Calculator {

 

    int add(int x, int y);

 

}

 

Here is an implementation of the Calculator interface in Groovy.

这里是一个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>

 

Lastly, here is a small application to exercise the above configuration.

最后,这里是一个小的应用用于练习上面的配置。

 

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));

    }

}

 

The resulting output from running the above program will be (unsurprisingly) 10. (Exciting example, huh? Remember that the intent is to illustrate the concept. Please consult the dynamic language showcase project for a more complex example, or indeed Section 35.4, Scenarioslater in this chapter).

结果输出来自于上面运行的程序将会是10.(激动的例子?记住事件说明了内容。请考虑动态语言的复杂项目或深入章节35.4,“场景”在后面的部分)。

 

It is important that you do not define more than one class per Groovy source file. While this is perfectly legal in Groovy, it is (arguably) a bad practice: in the interests of a consistent approach, you should (in the opinion of this author) respect the standard Java conventions of one (public) class per source file.

这是重要的你没有定义多个类在一个Groovy的源文件中。这在Groovy中是合法的,但是这是一种不推荐的方式:以始终如一的方法,你应当(以这个作者的观点)代表标准的Java规范对于每个源文件中只有一个类。

 

Customizing Groovy objects via a callback

考虑Groovyobject通过一个回调

 

The GroovyObjectCustomizer interface is a callback that allows you to hook additional creation logic into the process of creating a Groovy-backed bean. For example, implementations of this interface could invoke any required initialization method(s), or set some default property values, or specify a custom MetaClass.

GroovyObjectCustomizer接口是一个回调允许你出来额外的创建逻辑到创建一个Groovy后备bean的程序。例如,这个接口的实现可以调用任何需要的初始化方法或设置一些默认的属性值或指定一个自定义的MetaClass

 

public interface GroovyObjectCustomizer {

 

    void customize(GroovyObject goo);

}

 

The Spring Framework will instantiate an instance of your Groovy-backed bean, and will then pass the created GroovyObject to the specified GroovyObjectCustomizer if one has been defined. You can do whatever you like with the supplied GroovyObject reference: it is expected that the setting of a custom MetaClass is what most folks will want to do with this callback, and you can see an example of doing that below.

spring框架将举例说明一个Groovy后备bean的实例,并且传递创建的GroovyObject给指定的GroovyObjectCustomizer如果已经被定义。你可以做任何你想做的使用支持的GroovyObject的引用:他可以设置一个自定义的MetaClass使用这个回调并且你可以在下面看到更多的例子。

 

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);

    }

 

}

 

A full discussion of meta-programming in Groovy is beyond the scope of the Spring reference manual. Consult the relevant section of the Groovy reference manual, or do a search online: there are plenty of articles concerning this topic. Actually making use of a GroovyObjectCustomizer is easy if you are using the Spring namespace support.

对于在Groovy中的元标称是在spring参考手册的范围中的。参考相关的章节对于Groovy的引用或在网上进行查找:他们是有关主题的一些文章。实际上使用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"/>

 

If you are not using the Spring namespace support, you can still use the GroovyObjectCustomizer functionality.

如果你使用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"/>

 

[Note]

注意

 

As of Spring Framework 4.3.3, you may also specify a Groovy CompilationCustomizer (such as an ImportCustomizer) or even a full Groovy CompilerConfiguration object in the same place as Springs GroovyObjectCustomizer.

由于spring4.3.3,你也可以指定一个GroovyCompilationCustomizer(例如一个ImportCustomizer)或一个GroovyCompilerConfigurationobjectspringGroovyObjectCustomizer中。

 

35.3.4 BeanShell beans

 

The BeanShell library dependencies

BeanShell库依赖

 

The BeanShell scripting support in Spring requires the following libraries to be on the classpath of your application.

BeanShell脚本支持在spring中需要下面的库放置在你应用的classpath中。

 

    bsh-2.0b4.jar

 

From the BeanShell homepage…​

来自BeanShell的注意

 

"BeanShell is a small, free, embeddable Java source interpreter with dynamic language features, written in Java. BeanShell dynamically executes standard Java syntax and extends it with common scripting conveniences such as loose types, commands, and method closures like those in Perl and JavaScript."

BeanShell是一个小型的免费的内置的Java源拦截器使用动态的语言特性以Java编写。BeanShell动态的执行标准的Java语言和扩展他使用通用的脚本例如一些松散的类型、命令和封闭方法类似于PerlJavaScript。”

 

In contrast to Groovy, BeanShell-backed bean definitions require some (small) additional configuration. The implementation of the BeanShell dynamic language support in Spring is interesting in that what happens is this: Spring creates a JDK dynamic proxy implementing all of the interfaces that are specified in the 'script-interfaces' attribute value of the <lang:bsh> element (this is why you must supply at least one interface in the value of the attribute, and (accordingly) program to interfaces when using BeanShell-backed beans). This means that every method call on a BeanShell-backed object is going through the JDK dynamic proxy invocation mechanism.

相对于GroovyBeanShell后备bean定义要求一些额外的配置。BeanShell动态语言的实现支持在spring中是关心发生了什么:spirng创建了一个JDK的动态代理实现了所有的接口定义在script-interfaces属性值中通过<lang:bsh>元素(这就是为什么你必须支持至少一个接口对于属性的值并且相应编程对于接口当使用BeanShell后备的bean时)。这意味着每个方法调用对于BeanShell的后备object可以通过JDK的动态代理调用策略。

 

Lets look at a fully working example of using a BeanShell-based bean that implements the Messenger interface that was defined earlier in this chapter (repeated below for your convenience).

让我们使用一个基于BeanShellbean实现Messenger接口定义在这个章节中(为了方便再次重复)

 

package org.springframework.scripting;

 

public interface Messenger {

 

    String getMessage();

 

}

 

Here is the BeanShell 'implementation' (the term is used loosely here) of the Messenger interface.

这是BeanShell的实现(其语法是很松散的)对于Messenger接口。

 

String message;

 

String getMessage() {

    return message;

}

 

void setMessage(String aMessage) {

    message = aMessage;

}

 

And here is the Spring XML that defines an 'instance' of the above 'class' (again, the term is used very loosely here).

并且这里是springxml定义了上面的类的实例(再一次,其语法是比较松散的)。

 

<lang:bsh id="messageService" script-source="classpath:BshMessenger.bsh"

    script-interfaces="org.springframework.scripting.Messenger">

 

    <lang:property name="message" value="Hello World!" />

</lang:bsh>

 

See Section 35.4, Scenariosfor some scenarios where you might want to use BeanShell-based beans.

见章节35.4,“场景”用于你可能使用到基于BeanShellbean

 

35.4 Scenarios

场景

 

The possible scenarios where defining Spring managed beans in a scripting language would be beneficial are, of course, many and varied. This section describes two possible use cases for the dynamic language support in Spring.

可用的场景定义spring管理的bean在脚本语言中是有意义的,当然越多越有价值。这个章节描述了两个使用动态语言的例子在spring中。

 

35.4.1 Scripted Spring MVC Controllers

脚本话springmvc控制器

 

One group of classes that may benefit from using dynamic-language-backed beans is that of Spring MVC controllers. In pure Spring MVC applications, the navigational flow through a web application is to a large extent determined by code encapsulated within your Spring MVC controllers. As the navigational flow and other presentation layer logic of a web application needs to be updated to respond to support issues or changing business requirements, it may well be easier to effect any such required changes by editing one or more dynamic language source files and seeing those changes being immediately reflected in the state of a running application.

一个组的类可以来自动态语言后备beanSpringMVC的控制器。在纯springmvc应用中,一个web应用的导航栏在很大程度上通过代码包裹在你的springvmc的控制器中。由于导航流和其他表现层逻辑对于一个web应用需要被更新如果问题发生或改变业务逻辑,他可以简单的影响任何改变通过编辑或更多的动态语言源文件和直接设置这些改变反应在一个运行的应用的状态。

 

Remember that in the lightweight architectural model espoused by projects such as Spring, you are typically aiming to have a really thin presentation layer, with all the meaty business logic of an application being contained in the domain and service layer classes. Developing Spring MVC controllers as dynamic-language-backed beans allows you to change presentation layer logic by simply editing and saving text files; any changes to such dynamic language source files will (depending on the configuration) automatically be reflected in the beans that are backed by dynamic language source files.

记住在轻量级的架构模型中例如spring,你通常的目的是简化表现层,使用应用的逻辑暴行在domain和服务层类中。开发springmvc控制器作为动态语言后备bean允许你改变表现层的逻辑通过简单的编辑和保存文本文件。任何改变对于这样的动态语言文件将(依赖配置)自动被反应到bean中对于动态源文件的后备中。

 

[Note]

注意

 

In order to effect this automatic 'pickup' of any changes to dynamic-language-backed beans, you will have had to enable the 'refreshable beans' functionality. See the section calledRefreshable beansfor a full treatment of this feature.

为了影响自动获取对于任何动态语言后备bean的改变,你将需要启动'refreshable beans'的功能。见章节'refreshable beans'来了解这个特性的内容。

 

Find below an example of an org.springframework.web.servlet.mvc.Controller implemented using the Groovy dynamic language.

下面的例子使用了Groovy动态语言是一个org.springframework.web.servlet.mvc.Controller的实现。

 

// 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>

 

35.4.2 Scripted Validators

脚本话验证器

 

Another area of application development with Spring that may benefit from the flexibility afforded by dynamic-language-backed beans is that of validation. It may be easier to express complex validation logic using a loosely typed dynamic language (that may also have support for inline regular expressions) as opposed to regular Java.

另一个应用开发的领域使用spring对于动态语言后备bean就是验证器。他可以简单的表述为复杂的验证逻辑使用松散类型的动态语言(也可以支持内置的正则表达式)作为支持用于普通的Java中。

 

Again, developing validators as dynamic-language-backed beans allows you to change validation logic by simply editing and saving a simple text file; any such changes will (depending on the configuration) automatically be reflected in the execution of a running application and would not require the restart of an application.

另外,开发验证器作为动态语言后备bean允许你改变验证逻辑通过简单的便捷和保存一个简单的文本文件;任何这样的改变(依赖于配置)自动被影响到运行的应用中并且不需要重新启动应用。

 

[Note]

注意

 

Please note that in order to effect the automatic 'pickup' of any changes to dynamic-language-backed beans, you will have had to enable the 'refreshable beans' feature. See the section calledRefreshable beansfor a full and detailed treatment of this feature.

请注意为了自动获取动态语言后备bean的改变,你将需要开启'refreshable beans'特性。见章节'refreshable beans'来了解这个特性的细节。

 

Find below an example of a Spring org.springframework.validation.Validator implemented using the Groovy dynamic language. (See Section 9.2,Validation using Springs Validator interfacefor a discussion of the Validator interface.)

下面的例子使用了Groovy动态语言实现了springorg.springframework.validation.Validator接口。(见章节9.2,“使用springValidator接口的验证器”对于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.")

    }

 

}

 

35.5 Bits and bobs

零碎的东西

 

This last section contains some bits and bobs related to the dynamic language support.

最后一节包含了一些零碎的东西对于动态语言支持。

 

35.5.1 AOP - advising scripted beans

AOP————作用于脚本bean

 

It is possible to use the Spring AOP framework to advise scripted beans. The Spring AOP framework actually is unaware that a bean that is being advised might be a scripted bean, so all of the AOP use cases and functionality that you may be using or aim to use will work with scripted beans. There is just one (small) thing that you need to be aware of when advising scripted beans…​you cannot use class-based proxies, you must use interface-based proxies.

可以使用springAOP框架对于脚本的baenspringAOP框架实际上不知道一个bean是不是脚本bean,因此所有的AOP使用案例和功能你可以使用在脚本bean上。这是一个你不需要意识到对于脚本bean的使用,你不能使用基于类的代理,你必须使用基于接口的代理。

 

You are of course not just limited to advising scripted beans…​you can also write aspects themselves in a supported dynamic language and use such beans to advise other Spring beans. This really would be an advanced use of the dynamic language support though.

当然并不限制你使用脚本bean,你也可以使用他们在支持的动态语言中并且来修饰springbean。这是动态语言支持的好处。

 

35.5.2 Scoping

范围

 

In case it is not immediately obvious, scripted beans can of course be scoped just like any other bean. The scope attribute on the various <lang:language/> elements allows you to control the scope of the underlying scripted bean, just as it does with a regular bean. (The default scope is singleton, just as it is with 'regular' beans.)

由于不是很明显,脚本bean可以被范围话就像其他的beanscope属性对于不同的<lang:language/>元素允许你控制底层脚本bean的属性,就像使用普通的bean。(默认的范围是单例,就像普通的bean。)

 

Find below an example of using the scope attribute to define a Groovy bean scoped as a prototype.

下面的例子使用了Groovybean作为一个prototype范围使用了scope属性。

 

<?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>

 

See Section 7.5, Bean scopesin Chapter 7, The IoC container for a fuller discussion of the scoping support in the Spring Framework.

将章节7.5,“Bean的范围”在章节7中,IOC容器用于了解范围的支持在spring框架中。

 

35.6 Further Resources

更多的资源

 

Find below links to further resources about the various dynamic languages described in this chapter.

下面的超链接是更多的资源对于不同的动态语言描述在本掌中。

 

    The JRuby homepage

    The Groovy homepage

    The BeanShell homepage

 

 

阅读全文
0 0
原创粉丝点击