【Spring】Spring Framework Reference Documentation中文版6

7.12 Java-based container configuration

基于java容器的配置

 

7.12.1 Basic concepts: @Bean and @Configuration

基本含义:@Bean@Configuration

 

The central artifacts in Springs new Java-configuration support are @Configuration-annotated classes and @Bean-annotated methods.

spring的新java配置提供支持的是@Configuration注解类和@Bean注解类。

 

The @Bean annotation is used to indicate that a method instantiates, configures and initializes a new object to be managed by the Spring IoC container. For those familiar with Springs <beans/> XML configuration the @Bean annotation plays the same role as the <bean/> element. You can use @Bean annotated methods with any Spring @Component, however, they are most often used with @Configuration beans.

@Bean注解用于指定配置和初始化由springioc容器管理的实例。@Bean注解和beans元素中的bean元素有相同的作用。你可以在@Component中使用@Bean注解方法,然而,最常用的是@Configuration修饰bean

 

Annotating a class with @Configuration indicates that its primary purpose is as a source of bean definitions. Furthermore, @Configuration classes allow inter-bean dependencies to be defined by simply calling other @Bean methods in the same class. The simplest possible @Configuration class would read as follows:

使用@Configuration修饰类指明主要目的是作为一个bean的定义。更进一步,@Configuration类允许内部bean依赖通过在同一个类中调用其他的@Bean方法。最简单的例子如下:

 

@Configuration

public class AppConfig {

 

    @Bean

    public MyService myService() {

        return new MyServiceImpl();

    }

 

}

 

The AppConfig class above would be equivalent to the following Spring <beans/> XML:

上面的AppConfig类相当于下面的xml文件片段:

 

<beans>

    <bean id="myService" class="com.acme.services.MyServiceImpl"/>

</beans>

 

Full @Configuration vs 'lite' @Beans mode?

@Configuration vs 简化的@Bean模式

 

When @Bean methods are declared within classes that are not annotated with @Configuration they are referred to as being processed in a 'lite' mode. For example, bean methods declared in a @Component or even in a plain old class will be considered 'lite'.

当一个@Bean的方法定义在一个没有@Configuration修饰的类中时,他们将会以简化的模式被处理。例如,一个定义在@Component中的bean方法或一个普通的类将会被简化处理。

 

Unlike full @Configuration, lite @Bean methods cannot easily declare inter-bean dependencies. Usually one @Bean method should not invoke another @Bean method when operating in 'lite' mode.

与全@Configuration不同,简化的@Bean方法不会定义内部bean的依赖。通常在简化模式下,一个@Bean方法不应该调用另一个@Bean方法。

 

Only using @Bean methods within @Configuration classes is a recommended approach of ensuring that 'full' mode is always used. This will prevent the same @Bean method from accidentally being invoked multiple times and helps to reduce subtle bugs that can be hard to track down when operating in 'lite' mode.

只有@Configuration修饰的类中的@Bean方法才会以full模式的形式被处理。这样可以避免相同的@Bean方法偶尔的被调用多次,也可以减少在lite模式下问题的追踪。

 

The @Bean and @Configuration annotations will be discussed in depth in the sections below. First, however, well cover the various ways of creating a spring container using Java-based configuration.

@Bean注解和@Configuration注解将在后续的章节中介绍。首先,我们介绍一下使用基于java的配置创建spring容器的不同方法。

 

7.12.2 Instantiating the Spring container using AnnotationConfigApplicationContext

使用AnnotationConfigApplicationContext初始化spring容器

 

The sections below document Springs AnnotationConfigApplicationContext, new in Spring 3.0. This versatile ApplicationContext implementation is capable of accepting not only @Configuration classes as input, but also plain @Component classes and classes annotated with JSR-330 metadata.

springAnnotationConfigApplicationContext是在spring3.0中加入的。这个ApplicationContext的实现允许只有@Configuration修饰的类作为输入,也允许普通的@Component类和使用JSR330元数据的注解类。

 

When @Configuration classes are provided as input, the @Configuration class itself is registered as a bean definition, and all declared @Bean methods within the class are also registered as bean definitions.

@Configuration修饰的类作为输入,@Configuration类本身会注册为一个bean的定义,并且所有该类定义的@Bean方法也会注册为bean的定义。

 

When @Component and JSR-330 classes are provided, they are registered as bean definitions, and it is assumed that DI metadata such as @Autowired or @Inject are used within those classes where necessary.

@ComponentJSR330的类被提供,他们会被注册为bean,并且会作为依赖注入的元数据如果有其他类需要他们的时候。

 

Simple construction

简单的构造

 

In much the same way that Spring XML files are used as input when instantiating a ClassPathXmlApplicationContext, @Configuration classes may be used as input when instantiating an AnnotationConfigApplicationContext. This allows for completely XML-free usage of the Spring container:

使用springxml文件作为输入来初始化ClassPathXmlApplicationContext,和使用@Configuration类作为输入来初始化AnnotationConfigApplicationContext是相似的。这样可以完全不依赖于springxml文件:

 

public static void main(String[] args) {

    ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);

    MyService myService = ctx.getBean(MyService.class);

    myService.doStuff();

}

 

As mentioned above, AnnotationConfigApplicationContext is not limited to working only with @Configuration classes. Any @Component or JSR-330 annotated class may be supplied as input to the constructor. For example:

就像上面提到的,AnnotationConfigApplicationContext 并不局限于只处理@Configuration类。任何@Component修饰的类或JSR330注解类都可以作为输入来进行构造。例如:

 

public static void main(String[] args) {

    ApplicationContext ctx = new AnnotationConfigApplicationContext(MyServiceImpl.class, Dependency1.class, Dependency2.class);

    MyService myService = ctx.getBean(MyService.class);

    myService.doStuff();

}

 

The above assumes that MyServiceImpl, Dependency1 and Dependency2 use Spring dependency injection annotations such as @Autowired.

上面的例子假设MyServiceImplDependency1Dependency2使用了类似于@Autowired的注解来进行依赖注入。

 

Building the container programmatically using register(Class<?>?)

使用register(Class<?>?)编程构建容器

 

An AnnotationConfigApplicationContext may be instantiated using a no-arg constructor and then configured using the register() method. This approach is particularly useful when programmatically building an AnnotationConfigApplicationContext.

AnnotationConfigApplicationContext可以使用无参的构造器,然后施一公register方法来进行配置。当使用编程来构造AnnotationConfigApplicationContext时这种方法很有用。

 

public static void main(String[] args) {

    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();

    ctx.register(AppConfig.class, OtherConfig.class);

    ctx.register(AdditionalConfig.class);

    ctx.refresh();

    MyService myService = ctx.getBean(MyService.class);

    myService.doStuff();

}

 

Enabling component scanning with scan(String?)

使用scan(String?)来实现组件扫描

 

To enable component scanning, just annotate your @Configuration class as follows:

为了允许组件扫描,只需要在类上声明@Configuration如下:

 

@Configuration

@ComponentScan(basePackages = "com.acme")

public class AppConfig  {

    ...

}

 

[Tip]

提示

 

Experienced Spring users will be familiar with the XML declaration equivalent from Springs context: namespace

有经验的spring用户会更加熟悉在springcontext中定义命名空间:

 

<beans>

    <context:component-scan base-package="com.acme"/>

</beans>

 

In the example above, the com.acme package will be scanned, looking for any @Component-annotated classes, and those classes will be registered as Spring bean definitions within the container. AnnotationConfigApplicationContext exposes the scan(String?) method to allow for the same component-scanning functionality:

在上面的例子中,com.acme包将会被扫描,需要@Component修饰的类,并且这些类会被注册为bean的定义在容器中。AnnotationConfigApplicationContext允许使用scan方法来实现相同的组件扫描功能。

 

public static void main(String[] args) {

    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();

    ctx.scan("com.acme");

    ctx.refresh();

    MyService myService = ctx.getBean(MyService.class);

}

 

[Note]

注意

 

Remember that @Configuration classes are meta-annotated with @Component, so they are candidates for component-scanning! In the example above, assuming that AppConfig is declared within the com.acme package (or any package underneath), it will be picked up during the call to scan(), and upon refresh() all its @Bean methods will be processed and registered as bean definitions within the container.

记住@Configuration类是@Component的元注解,也就暗示着支持组件扫描。在上面的例子中,假设AppConfig被定义在com.acme包中(或下面的子包),都会在调用scan时被扫描,并且在refresh时所有的@Bean方法都会被注册为bean定义。

 

Support for web applications with AnnotationConfigWebApplicationContext

使用AnnotationConfigWebApplicationContext来支持web应用

 

A WebApplicationContext variant of AnnotationConfigApplicationContext is available with AnnotationConfigWebApplicationContext. This implementation may be used when configuring the Spring ContextLoaderListener servlet listener, Spring MVC DispatcherServlet, etc. What follows is a web.xml snippet that configures a typical Spring MVC web application. Note the use of the contextClass context-param and init-param:

一个AnnotationConfigApplicationContext支持webWebApplicationContextAnnotationConfigWebApplicationContext实现。这个实现可以用在以下情况,如配置springContextLoaderListener servlet监听器、springMVCDispatcherServlet等等。下面是web.xml片段就是典型的springMVCweb应用。注意context-paraminit-param的使用:

 

<web-app>

    <!-- Configure ContextLoaderListener to use AnnotationConfigWebApplicationContext

        instead of the default XmlWebApplicationContext -->

<!-- 使用AnnotationConfigWebApplicationContext来配置ContextLoaderListener,替代原有的XmlWebApplicationContext -->

    <context-param>

        <param-name>contextClass</param-name>

        <param-value>

            org.springframework.web.context.support.AnnotationConfigWebApplicationContext

        </param-value>

    </context-param>

 

    <!-- Configuration locations must consist of one or more comma- or space-delimited

        fully-qualified @Configuration classes. Fully-qualified packages may also be

        specified for component-scanning -->

<!-- 配置location必须包含一个或多个都会或空格分割的全限定@Configuration类。

全限定包名也可以定义在component-scanning-->

    <context-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>com.acme.AppConfig</param-value>

    </context-param>

 

    <!-- Bootstrap the root application context as usual using ContextLoaderListener -->

<!-- 使用通常的ContextLoaderListener来加载根应用上下文 -->

    <listener>

        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

    </listener>

 

    <!-- Declare a Spring MVC DispatcherServlet as usual -->

<!-- 和通常一样定义springMVC转发器 -->

    <servlet>

        <servlet-name>dispatcher</servlet-name>

        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <!-- Configure DispatcherServlet to use AnnotationConfigWebApplicationContext

            instead of the default XmlWebApplicationContext -->

<!-- 使用AnnotationConfigWebApplicationContext来替代默认的XmlWebApplicationContext配置DispatcherServlet -->

        <init-param>

            <param-name>contextClass</param-name>

            <param-value>

                org.springframework.web.context.support.AnnotationConfigWebApplicationContext

            </param-value>

        </init-param>

        <!-- Again, config locations must consist of one or more comma- or space-delimited

            and fully-qualified @Configuration classes -->

<!-- 再一次, 配置location必须包含一个或多个都会或空格分割的全限定@Configuration类。-->

        <init-param>

            <param-name>contextConfigLocation</param-name>

            <param-value>com.acme.web.MvcConfig</param-value>

        </init-param>

    </servlet>

 

    <!-- map all requests for /app/* to the dispatcher servlet -->

<!-- 配置所有以/app/开始的请求都会交友dispatcher来处理 -->

    <servlet-mapping>

        <servlet-name>dispatcher</servlet-name>

        <url-pattern>/app/*</url-pattern>

    </servlet-mapping>

</web-app>

 

7.12.3 Using the @Bean annotation

使用@Bean注解

 

@Bean is a method-level annotation and a direct analog of the XML <bean/> element. The annotation supports some of the attributes offered by <bean/>, such as: init-method, destroy-method, autowiring and name.

@Bean是方法级别的注解和xmlbean元素类似。这个注解支持bean中提供的一些属性,例如:init-methoddestroy-methodautowiringname

 

You can use the @Bean annotation in a @Configuration-annotated or in a @Component-annotated class.

你可以在@Configuration类或@Component类中使用@Bean注解。

 

Declaring a bean

定义一个bean

 

To declare a bean, simply annotate a method with the @Bean annotation. You use this method to register a bean definition within an ApplicationContext of the type specified as the methods return value. By default, the bean name will be the same as the method name. The following is a simple example of a @Bean method declaration:

使用@Bean注解方法简单定义一个bean。你可以通过方法的返回值来使用ApplicationContext来注册一个bean的定义。默认的,bean的名字会和方法名相同。下面就是一个简单的@Bean方法的例子:

 

@Configuration

public class AppConfig {

 

    @Bean

    public TransferService transferService() {

        return new TransferServiceImpl();

    }

 

}

 

The preceding configuration is exactly equivalent to the following Spring XML:

上面的配置和下面的xml中的定义是一样的效果:

 

<beans>

    <bean id="transferService" class="com.acme.TransferServiceImpl"/>

</beans>

 

Both declarations make a bean named transferService available in the ApplicationContext, bound to an object instance of type TransferServiceImpl:

两种方式都会使得transferService这个名字在ApplicationContext中有效,并且绑定TransferServiceImpl的返回对象:

 

transferService -> com.acme.TransferServiceImpl

 

Bean dependencies

Bean的依赖

 

A @Bean annotated method can have an arbitrary number of parameters describing the dependencies required to build that bean. For instance if our TransferService requires an AccountRepository we can materialize that dependency via a method parameter:

一个@Bean修饰的方法可以有多个参数依赖用于构建bean。例如TransferService需要一个AccountRepository作为依赖通过方法参数:

 

@Configuration

public class AppConfig {

 

    @Bean

    public TransferService transferService(AccountRepository accountRepository) {

        return new TransferServiceImpl(accountRepository);

    }

 

}

 

The resolution mechanism is pretty much identical to constructor-based dependency injection, see the relevant section for more details.

这个方法和构造依赖注入是相似的,详见7.4.1章节。

 

Receiving lifecycle callbacks

接收生命周期的回调方法

 

Any classes defined with the @Bean annotation support the regular lifecycle callbacks and can use the @PostConstruct and @PreDestroy annotations from JSR-250, see JSR-250 annotations for further details.

任何定义@Bean注解的类都支持生命周期方法回调,使用JSR250中的@PostConstruct@PreDestroy,详见JSR250注解说明。

 

The regular Spring lifecycle callbacks are fully supported as well. If a bean implements InitializingBean, DisposableBean, or Lifecycle, their respective methods are called by the container.

支持所有常规的spring生命周期回调方法。如果一个bean实现了InitializingBeanDisposableBeanLifecycle,其相应的方法也会被容器调用。

 

The standard set of *Aware interfaces such as BeanFactoryAware, BeanNameAware, MessageSourceAware, ApplicationContextAware, and so on are also fully supported.

也支持*Aware接口,例如BeanFactoryAwareBeanNameAwareMessageSourceAwareApplicationContextAware等等。

 

The @Bean annotation supports specifying arbitrary initialization and destruction callback methods, much like Spring XMLs init-method and destroy-method attributes on the bean element:

@Bean注解支持定义初始化方法或销毁回调方法,很像springxmlbean元素中的init-methoddestroy-method属性。

 

public class Foo {

    public void init() {

        // initialization logic

// 初始化逻辑

    }

}

 

public class Bar {

    public void cleanup() {

        // destruction logic

// 销毁逻辑

    }

}

 

@Configuration

public class AppConfig {

 

    @Bean(initMethod = "init")

    public Foo foo() {

        return new Foo();

    }

 

    @Bean(destroyMethod = "cleanup")

    public Bar bar() {

        return new Bar();

    }

 

}

 

[Note]

注意

 

By default, beans defined using Java config that have a public close or shutdown method are automatically enlisted with a destruction callback. If you have a public close or shutdown method and you do not wish for it to be called when the container shuts down, simply add @Bean(destroyMethod="") to your bean definition to disable the default (inferred) mode.

默认情况下,使用java配置的bean定义有一个公共的关闭方法在销毁时被回调。如果有公共的销毁回调方法,但是你不希望在容器关闭时调用,那么可以使用@Bean(destroyMethod="")来使得你的bean不调用默认关闭方法。

 

You may want to do that by default for a resource that you acquire via JNDI as its lifecycle is managed outside the application. In particular, make sure to always do it for a DataSource as it is known to be problematic on Java EE application servers.

你或许希望将其设置为默认,比如一个资源你通过JNDI获得并且它的生命周期由外部管理。特殊情况下,保证你只处理数据源,在JavaEE应用服务器中可能会有问题。

 

@Bean(destroyMethod="")

public DataSource dataSource() throws NamingException {

    return (DataSource) jndiTemplate.lookup("MyDS");

}

 

Also, with @Bean methods, you will typically choose to use programmatic JNDI lookups: either using Springs JndiTemplate/JndiLocatorDelegate helpers or straight JNDI InitialContext usage, but not the JndiObjectFactoryBean variant which would force you to declare the return type as the FactoryBean type instead of the actual target type, making it harder to use for cross-reference calls in other @Bean methods that intend to refer to the provided resource here.

@Bean方法中,你可以使用JNDI查找:或使用springJndiTemplate/JndiLocatorDelegate来辅助或直接使用JNDI InitialContext,但是JndiObjectFactoryBean不会强制你定义工厂bean的返回类型代替目标类型,使得交叉引用其他的@Bean方法来代替源代码中提供的。

 

Of course, in the case of Foo above, it would be equally as valid to call the init() method directly during construction:

当然,在上面的Foo中,和在构造中直接调用init方法是一样的。

 

@Configuration

public class AppConfig {

    @Bean

    public Foo foo() {

        Foo foo = new Foo();

        foo.init();

        return foo;

    }

 

    // ...

 

}

 

[Tip]

提示

 

When you work directly in Java, you can do anything you like with your objects and do not always need to rely on the container lifecycle!

当你直接使用java代码时,你可以对你的object做任何事情并且不需要依赖容器的生命周期。

 

Specifying bean scope

定义bean的范围

 

Using the @Scope annotation

使用@Scope注解

 

You can specify that your beans defined with the @Bean annotation should have a specific scope. You can use any of the standard scopes specified in the Bean Scopes section.

你使用@Bean定义bean的时候应该定义一个范围。你可以使用bean范围章节中任意一个标准的范围。

 

The default scope is singleton, but you can override this with the @Scope annotation:

默认的范围是单例,但是你可以使用@Scope注解来进行覆盖:

 

@Configuration

public class MyConfiguration {

 

    @Bean

    @Scope("prototype")

    public Encryptor encryptor() {

        // ...

    }

 

}

 

@Scope and scoped-proxy

@Scope和范围代理

 

Spring offers a convenient way of working with scoped dependencies through scoped proxies. The easiest way to create such a proxy when using the XML configuration is the <aop:scoped-proxy/> element. Configuring your beans in Java with a @Scope annotation offers equivalent support with the proxyMode attribute. The default is no proxy ( ScopedProxyMode.NO), but you can specify ScopedProxyMode.TARGET_CLASS or ScopedProxyMode.INTERFACES.

spring提供了一种方便的方式通范围代理定义范围依赖。最简单的方法创建这样的代理是使用xml配置的<aop:scoped-proxy/>元素。使用@Scope注解配置bean也提供了相同的proxyMode属性。默认值是没有代理(ScopedProxyMode.NO),但是你可以定义为ScopeProxyMode.TARGET_CLASSScopeProxyMode.INTERFACES

 

If you port the scoped proxy example from the XML reference documentation (see preceding link) to our @Bean using Java, it would look like the following:

如果你从xml的参考文档看到范围代理的例子,他看起来是这样的:

 

// an HTTP Session-scoped bean exposed as a proxy

@Bean

@SessionScope

public UserPreferences userPreferences() {

    return new UserPreferences();

}

 

@Bean

public Service userService() {

    UserService service = new SimpleUserService();

    // a reference to the proxied userPreferences bean

    service.setUserPreferences(userPreferences());

    return service;

}

 

Customizing bean naming

自定义bean的名字

 

By default, configuration classes use a @Bean methods name as the name of the resulting bean. This functionality can be overridden, however, with the name attribute.

默认,使用@Bean的方法名和bean的名字相同。但是使用name属性可以导致名字被覆盖。

 

@Configuration

public class AppConfig {

 

    @Bean(name = "myFoo")

    public Foo foo() {

        return new Foo();

    }

 

}

 

Bean aliasing

bean的别名

 

As discussed in Section 7.3.1, Naming beans, it is sometimes desirable to give a single bean multiple names, otherwise known as bean aliasing. The name attribute of the @Bean annotation accepts a String array for this purpose.

7.3.1章节中讨论的,命名bean,在有时可能会给单一的一个bean提供多个name,也就是bean的别名。@Beanname属性支持一个字符串数组用于实现bean的别名。

 

@Configuration

public class AppConfig {

 

    @Bean(name = { "dataSource", "subsystemA-dataSource", "subsystemB-dataSource" })

    public DataSource dataSource() {

        // instantiate, configure and return DataSource bean...

    }

 

}

 

Bean description

bean的描述

 

Sometimes it is helpful to provide a more detailed textual description of a bean. This can be particularly useful when beans are exposed (perhaps via JMX) for monitoring purposes.

有时提供一个文字版的bean的描述是有帮助的。当bean被暴露时这很有效(例如通过JMX)。

 

To add a description to a @Bean the @Description annotation can be used:

使用@Description注解在@Bean中可以添加描述,如下这样使用:

 

@Configuration

public class AppConfig {

 

    @Bean

    @Description("Provides a basic example of a bean")

    public Foo foo() {

        return new Foo();

    }

 

}

 

7.12.4 Using the @Configuration annotation

使用@Configuration注解

 

@Configuration is a class-level annotation indicating that an object is a source of bean definitions. @Configuration classes declare beans via public @Bean annotated methods. Calls to @Bean methods on @Configuration classes can also be used to define inter-bean dependencies. See Section 7.12.1, Basic concepts: @Bean and @Configurationfor a general introduction.

@Configuration是一个类级别的注解暗示一个object是一个bean的定义的源码。@Configuration类通过@Bean方法来定义bean。调用@Configuration类中的@Bean方法可以用于定义内部bean的依赖。见7.12.1章节,“基本内容:@Bean@Configuration”有介绍。

 

Injecting inter-bean dependencies

注入内部bean依赖

 

When @Beans have dependencies on one another, expressing that dependency is as simple as having one bean method call another:

当一个@Bean依赖另一个bean,表达依赖的简单方法就是有一个bean方法调用另一个方法:

 

@Configuration

public class AppConfig {

 

    @Bean

    public Foo foo() {

        return new Foo(bar());

    }

 

    @Bean

    public Bar bar() {

        return new Bar();

    }

 

}

 

In the example above, the foo bean receives a reference to bar via constructor injection.

上面的例子中,foobean接收了一个bar的应用通过构造器注入。

 

[Note]

注意

 

This method of declaring inter-bean dependencies only works when the @Bean method is declared within a @Configuration class. You cannot declare inter-bean dependencies using plain @Component classes.

这种方法定义内部bean依赖只使用与@Configuration类中的@Bean方法。你不可以在普通的@Component类中定义内部bean依赖。

 

Lookup method injection

Lookup方法注入

 

As noted earlier, lookup method injection is an advanced feature that you should use rarely. It is useful in cases where a singleton-scoped bean has a dependency on a prototype-scoped bean. Using Java for this type of configuration provides a natural means for implementing this pattern.

和前面注意提示一样,lookup方法注入是一个你很难使用到的高级特性。当单例bean需要原型bean时这个方法很有用。使用Java为这种类型的配置提供了一种自然的方式用于实现这种模式。

 

public abstract class CommandManager {

    public Object process(Object commandState) {

        // grab a new instance of the appropriate Command interface

// 通过适当的Command接口获得一个实例

        Command command = createCommand();

        // set the state on the (hopefully brand new) Command instance

// Command接口设置state

        command.setState(commandState);

        return command.execute();

    }

 

    // okay... but where is the implementation of this method?

// ok,但是这个方法的实现在哪?

    protected abstract Command createCommand();

}

 

Using Java-configuration support , you can create a subclass of CommandManager where the abstract createCommand() method is overridden in such a way that it looks up a new (prototype) command object:

适应java配置支持,你可以创建一个CommandManager的子类重写createCommand方法以这样的方式使得看起来是一个新的(原型的)command object

 

@Bean

@Scope("prototype")

public AsyncCommand asyncCommand() {

    AsyncCommand command = new AsyncCommand();

    // inject dependencies here as required

// 根据需要在这里注入依赖

    return command;

}

 

@Bean

public CommandManager commandManager() {

    // return new anonymous implementation of CommandManager with command() overridden

    // to return a new prototype Command object

// 返回新的匿名的CommandManger覆盖command方法的实现用于返回一个新的原型的Commmand Object

    return new CommandManager() {

        protected Command createCommand() {

            return asyncCommand();

        }

    }

}

 

Further information about how Java-based configuration works internally

如果使得基于java配置在内部工作的更多信息

 

The following example shows a @Bean annotated method being called twice:

下面的例子展示了一个@Bean注解的方法被调用了两次

 

@Configuration

public class AppConfig {

 

    @Bean

    public ClientService clientService1() {

        ClientServiceImpl clientService = new ClientServiceImpl();

        clientService.setClientDao(clientDao());

        return clientService;

    }

 

    @Bean

    public ClientService clientService2() {

        ClientServiceImpl clientService = new ClientServiceImpl();

        clientService.setClientDao(clientDao());

        return clientService;

    }

 

    @Bean

    public ClientDao clientDao() {

        return new ClientDaoImpl();

    }

 

}

 

clientDao() has been called once in clientService1() and once in clientService2(). Since this method creates a new instance of ClientDaoImpl and returns it, you would normally expect having 2 instances (one for each service). That definitely would be problematic: in Spring, instantiated beans have a singleton scope by default. This is where the magic comes in: All @Configuration classes are subclassed at startup-time with CGLIB. In the subclass, the child method checks the container first for any cached (scoped) beans before it calls the parent method and creates a new instance. Note that as of Spring 3.2, it is no longer necessary to add CGLIB to your classpath because CGLIB classes have been repackaged under org.springframework.cglib and included directly within the spring-core JAR.

clientDao方法在clientService1clientService2中各被调用了一次。这个方法用于创建ClientDaoImpl的实例并返回,你正常情况需要两个实例(每个service一个实例)。这种定义是有问题的,在spring中,默认的bean实例化之后是单例的。这就有趣的地方,所有@Configuration类在启动时都会使用CGLIB创建子类。在子类中,子方法首先检查容器是否缓存了bean在调用父方法创建一个新的实例之前。注意在spring3.2中,不需要在类路径中添加CGLIB,因为CGLIB类已经被重新打包放在org.springframework.cglib中并且包括在spring-corejar中。

 

[Note]

注意

 

The behavior could be different according to the scope of your bean. We are talking about singletons here.

由于你的bean的范围,行为也会有些不同。我们在这里讨论的是单例的bean

 

[Tip]

提示

 

There are a few restrictions due to the fact that CGLIB dynamically adds features at startup-time, in particular that configuration classes must not be final. However, as of 4.3, any constructors are allowed on configuration classes, including the use of @Autowired or a single non-default constructor declaration for default injection.

由于CGLIB在启动时动态的添加特性,会导致一些限制,特别如果配置的类不是final的时候。然而,由于4.3节,构造器允许在配置类中使用,包括使用@Autowired或一个没有默认构造器的定义用于依赖注入。

 

If you prefer to avoid any CGLIB-imposed limitations, consider declaring your @Bean methods on non-@Configuration classes, e.g. on plain @Component classes instead. Cross-method calls between @Bean methods wont get intercepted then, so youll have to exclusively rely on dependency injection at the constructor or method level there.

如果你想避免CGLIB强加的限制,考虑在没有@Configuration类中定义@Bean方法,例如,使用普通@Component类作为替代。在@Bean方法中跨方法调用不会拦截,因此你必须避免在构造中依赖注入或方法级别进行依赖注入。

 

7.12.5 Composing Java-based configurations

组合基于Java的配置

 

Using the @Import annotation

使用@Import注解

 

Much as the <import/> element is used within Spring XML files to aid in modularizing configurations, the @Import annotation allows for loading @Bean definitions from another configuration class:

springxmlimport元素用于模块化配置,@Import注解允许从其他配置类中加载bean的定义:

 

@Configuration

public class ConfigA {

 

     @Bean

    public A a() {

        return new A();

    }

 

}

 

@Configuration

@Import(ConfigA.class)

public class ConfigB {

 

    @Bean

    public B b() {

        return new B();

    }

 

}

 

Now, rather than needing to specify both ConfigA.class and ConfigB.class when instantiating the context, only ConfigB needs to be supplied explicitly:

现在,不需要定义ConfigAConfigB类当实例化context,只需要提供ConfigB就可以

 

public static void main(String[] args) {

    ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class);

 

    // now both beans A and B will be available...

// 现在AB都可以获取到

    A a = ctx.getBean(A.class);

    B b = ctx.getBean(B.class);

}

 

This approach simplifies container instantiation, as only one class needs to be dealt with, rather than requiring the developer to remember a potentially large number of @Configuration classes during construction.

这种方法简化了容器的实例化,只需要处理一个类,不在要求开发者在配置时使用多个@Configuration类。

 

[Tip]

提示

 

As of Spring Framework 4.2, @Import also supports references to regular component classes, analogous to the AnnotationConfigApplicationContext.register method. This is particularly useful if youd like to avoid component scanning, using a few configuration classes as entry points for explicitly defining all your components.

spring框架4.2中,@Import也支持引用普通的组件类,模拟了AnnotationConfigApplicationContext的注册方法。如果你想避免组件扫描时将会有很大的帮助,使用一些配置类作为实体点定义所有你的组件。

 

Injecting dependencies on imported @Bean definitions

在引入的bean定义中依赖注入

 

The example above works, but is simplistic. In most practical scenarios, beans will have dependencies on one another across configuration classes. When using XML, this is not an issue, per se, because there is no compiler involved, and one can simply declare ref="someBean" and trust that Spring will work it out during container initialization. Of course, when using @Configuration classes, the Java compiler places constraints on the configuration model, in that references to other beans must be valid Java syntax.

上面的例子可以工作,但是过于简单。在很多实际的场景中,bean之间是跨配置类互相依赖的。当使用xml时,这不是问题,因为还没有编译器的参与,一个bean可以很简单的引用另一个bean,然后spring的容器会完成初始化操作。当然,当使用@Configuration类时,Java编译器会在配置模型中限制,保证引用的另一个bean符合java语法。

 

Fortunately, solving this problem is simple. As we already discussed, @Bean method can have an arbitrary number of parameters describing the bean dependencies. Lets consider a more real-world scenario with several @Configuration classes, each depending on beans declared in the others:

幸运的是解决这个问题也简单。就像我们讨论过的,@Bean方法可以有不定数量的参数依赖。让我们考虑一下更加实际的场景,包含多个@Configuration类,每个又依赖其他的bean

 

@Configuration

public class ServiceConfig {

 

    @Bean

    public TransferService transferService(AccountRepository accountRepository) {

        return new TransferServiceImpl(accountRepository);

    }

 

}

 

@Configuration

public class RepositoryConfig {

 

    @Bean

    public AccountRepository accountRepository(DataSource dataSource) {

        return new JdbcAccountRepository(dataSource);

    }

 

}

 

@Configuration

@Import({ServiceConfig.class, RepositoryConfig.class})

public class SystemTestConfig {

 

    @Bean

    public DataSource dataSource() {

        // return new DataSource

    }

 

}

 

public static void main(String[] args) {

    ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);

    // everything wires up across configuration classes...

// 每一个都跨配置类配置

    TransferService transferService = ctx.getBean(TransferService.class);

    transferService.transfer(100.00, "A123", "C456");

}

 

There is another way to achieve the same result. Remember that @Configuration classes are ultimately just another bean in the container: This means that they can take advantage of @Autowired and @Value injection etc just like any other bean!

这是另外一种获取相同结果的方式。注意@Configuration类知识容器中另一个bean。这意味着可以通过@Autowired@Value注入就像其他的bean一样。

 

[Warning]

警告

 

Make sure that the dependencies you inject that way are of the simplest kind only. @Configuration classes are processed quite early during the initialization of the context and forcing a dependency to be injected this way may lead to unexpected early initialization. Whenever possible, resort to parameter-based injection as in the example above.

保证你注入的依赖是简单的形式。@Configuration类在之前就被处理并且强制依赖注入会导致不可预见的提前初始化。不管何时,依赖于参数注入参考上面的例子。

 

Also, be particularly careful with BeanPostProcessor and BeanFactoryPostProcessor definitions via @Bean. Those should usually be declared as static @Bean methods, not triggering the instantiation of their containing configuration class. Otherwise, @Autowired and @Value wont work on the configuration class itself since it is being created as a bean instance too early.

注意通过@Bean定义的BeanPostProcessorBeanFactoryPostProcessor。他们通常被定义为静态的@Bean方法,不会触发容器配置类的初始化。另外,@Autowired@Value不会对配置类起作用如果很早就创建了bean的实例。

 

@Configuration

public class ServiceConfig {

 

    @Autowired

    private AccountRepository accountRepository;

 

    @Bean

    public TransferService transferService() {

        return new TransferServiceImpl(accountRepository);

    }

 

}

 

@Configuration

public class RepositoryConfig {

 

    private final DataSource dataSource;

 

    @Autowired

    public RepositoryConfig(DataSource dataSource) {

        this.dataSource = dataSource;

    }

 

    @Bean

    public AccountRepository accountRepository() {

        return new JdbcAccountRepository(dataSource);

    }

 

}

 

@Configuration

@Import({ServiceConfig.class, RepositoryConfig.class})

public class SystemTestConfig {

 

    @Bean

    public DataSource dataSource() {

        // return new DataSource

    }

 

}

 

public static void main(String[] args) {

    ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);

    // everything wires up across configuration classes...

// 每一个都跨配置类配置

    TransferService transferService = ctx.getBean(TransferService.class);

    transferService.transfer(100.00, "A123", "C456");

}

 

[Tip]

提示

 

Constructor injection in @Configuration classes is only supported as of Spring Framework 4.3. Note also that there is no need to specify @Autowired if the target bean defines only one constructor; in the example above, @Autowired is not necessary on the RepositoryConfig constructor.

spring框架4.3开始支持在@Configuration类中的构造器注入。注意如果目标bean值定义了一个构造器,则@Autowired可以省略,上面的例子中,RepositoryConfig的构造器中不需要@Autowired

 

In the scenario above, using @Autowired works well and provides the desired modularity, but determining exactly where the autowired bean definitions are declared is still somewhat ambiguous. For example, as a developer looking at ServiceConfig, how do you know exactly where the @Autowired AccountRepository bean is declared? Its not explicit in the code, and this may be just fine. Remember that the Spring Tool Suite provides tooling that can render graphs showing how everything is wired up - that may be all you need. Also, your Java IDE can easily find all declarations and uses of the AccountRepository type, and will quickly show you the location of @Bean methods that return that type.

在上面的场景中,使用@Autowired会更好并提供预期的模块性,但是决定哪些bean是被自动扫描的依然是困难的。例如,作为一个开发者需要一个ServiceConfig,你如何确切的知道在哪里注入AccountRepository?他并没有明确的在代码中,或许这样会好。记住Spring Tool Suite提供了工具可以生成图表来展示是怎么样注入的,这个或许你会需要。而且JavaIDE可以轻松找到所有的定义和使用AccountRepository类型的位置,并且会快速展示@Bean方法的位置并返回相应的类型。

 

In cases where this ambiguity is not acceptable and you wish to have direct navigation from within your IDE from one @Configuration class to another, consider autowiring the configuration classes themselves:

如此这个考虑是可以被解决的而且你希望可以有直接的导航利用你的IDE从一个@Configuration类到另一个,考虑这样配置类:

 

@Configuration

public class ServiceConfig {

 

    @Autowired

    private RepositoryConfig repositoryConfig;

 

    @Bean

    public TransferService transferService() {

        // navigate 'through' the config class to the @Bean method!

// 导航到@Bean方法

        return new TransferServiceImpl(repositoryConfig.accountRepository());

    }

 

}

 

In the situation above, it is completely explicit where AccountRepository is defined. However, ServiceConfig is now tightly coupled to RepositoryConfig; thats the tradeoff. This tight coupling can be somewhat mitigated by using interface-based or abstract class-based @Configuration classes. Consider the following:

在上面的情况中,已经明确的声明了AccountRepository的定义。然而,ServiceConfigRepositoryConfig是绑定的,这是折中的。通过基于接口或基于抽象类的@Configuration类可以减弱这种耦合。考虑下面的例子:

 

@Configuration

public class ServiceConfig {

 

    @Autowired

    private RepositoryConfig repositoryConfig;

 

    @Bean

    public TransferService transferService() {

        return new TransferServiceImpl(repositoryConfig.accountRepository());

    }

}

 

@Configuration

public interface RepositoryConfig {

 

    @Bean

    AccountRepository accountRepository();

 

}

 

@Configuration

public class DefaultRepositoryConfig implements RepositoryConfig {

 

    @Bean

    public AccountRepository accountRepository() {

        return new JdbcAccountRepository(...);

    }

 

}

 

@Configuration

@Import({ServiceConfig.class, DefaultRepositoryConfig.class}) // import the concrete config!

public class SystemTestConfig {

 

    @Bean

    public DataSource dataSource() {

        // return DataSource

    }

 

}

 

public static void main(String[] args) {

    ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);

    TransferService transferService = ctx.getBean(TransferService.class);

    transferService.transfer(100.00, "A123", "C456");

}

 

Now ServiceConfig is loosely coupled with respect to the concrete DefaultRepositoryConfig, and built-in IDE tooling is still useful: it will be easy for the developer to get a type hierarchy of RepositoryConfig implementations. In this way, navigating @Configuration classes and their dependencies becomes no different than the usual process of navigating interface-based code.

现在ServiceConfig和创建的DefaultRepositoryConfig是松耦合的,并且内置的IDE工具依然是有效的:这样可以帮助开发者获得一个RepositoryConfig实现的类型结构。使用这种方式,导航@Configuration类和他们的依赖变得和通常导航基于接口的代码是没有区别的。

 

Conditionally include @Configuration classes or @Bean methods

条件包含@Configuration类或@Bean方法

 

It is often useful to conditionally enable or disable a complete @Configuration class, or even individual @Bean methods, based on some arbitrary system state. One common example of this is to use the @Profile annotation to activate beans only when a specific profile has been enabled in the Spring Environment (see Section 7.13.1, Bean definition profilesfor details).

基于一些结构系统的状态通过条件开启或关闭一个@Configuration类或独立的@Bean方法是很有用的。一个通用的例子就是使用@Profile注解来激活bean通过该特定的profile被允许在spring的环境中(见7.13.1节,“bean定义profiles”)

 

The @Profile annotation is actually implemented using a much more flexible annotation called @Conditional. The @Conditional annotation indicates specific org.springframework.context.annotation.Condition implementations that should be consulted before a @Bean is registered.

@Profile注解实现使用了更加方便的注解叫@Conditional@Conditional注解暗示特定org.springframework.context.annotation.Condition的实现应该在@Bean被注册之前。

 

Implementations of the Condition interface simply provide a matches(?) method that returns true or false. For example, here is the actual Condition implementation used for @Profile:

实现Condition接口只要简单的提供matches方法并返回一个truefalse。例如,下面是使用@ProfileCondition实现。

 

@Override

public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

    if (context.getEnvironment() != null) {

        // Read the @Profile annotation attributes

// 读取@Profile主机的属性

        MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());

        if (attrs != null) {

            for (Object value : attrs.get("value")) {

                if (context.getEnvironment().acceptsProfiles(((String[]) value))) {

                    return true;

                }

            }

            return false;

        }

    }

    return true;

}

 

See the @Conditional javadocs for more detail.

参考@Conditionaljavadocs获得更多信息

 

Combining Java and XML configuration

组合javaxml配置

 

Springs @Configuration class support does not aim to be a 100% complete replacement for Spring XML. Some facilities such as Spring XML namespaces remain an ideal way to configure the container. In cases where XML is convenient or necessary, you have a choice: either instantiate the container in an "XML-centric" way using, for example, ClassPathXmlApplicationContext, or in a "Java-centric" fashion using AnnotationConfigApplicationContext and the @ImportResource annotation to import XML as needed.

spring@Configuration类目的是完全代替xml文件。一些设备例如springxml命名空间仍然保留在容器中。由于xml有时是方便的,你可以有一个选择:例如以xml为中心的形式进行使用,例如,ClassPathXmlApplicationContext或以java为中心的风格使用AnnotationConfigApplicationContext@ImportResource注解来导入需要的xml文件。

 

XML-centric use of @Configuration classes

基于xml为中心使用@Configuration

 

It may be preferable to bootstrap the Spring container from XML and include @Configuration classes in an ad-hoc fashion. For example, in a large existing codebase that uses Spring XML, it will be easier to create @Configuration classes on an as-needed basis and include them from the existing XML files. Below youll find the options for using @Configuration classes in this kind of "XML-centric" situation.

使用xml启动容器然后包含@Configuration类是一种方式。例如,在一个已存在的代码库使用springxml文件,将会更加简单创建基于需要的@Configuration类和包括已存在的xml文件。下面你会找到在以xml为中心的情况下使用@Configuration类。

 

Remember that @Configuration classes are ultimately just bean definitions in the container. In this example, we create a @Configuration class named AppConfig and include it within system-test-config.xml as a <bean/> definition. Because <context:annotation-config/> is switched on, the container will recognize the @Configuration annotation and process the @Bean methods declared in AppConfig properly.

记住@Configuration类只是在容器中的bean的定义。在这个例子中,我们创建@Configuration类名为AppConfig和包括他的system-test-config.xml文件作为bean的定义。因为扫描的功能被打开了,容器会发现@Configuration注解并会处理定义在AppConfig@Bean方法。

 

@Configuration

public class AppConfig {

 

    @Autowired

    private DataSource dataSource;

 

    @Bean

    public AccountRepository accountRepository() {

        return new JdbcAccountRepository(dataSource);

    }

 

    @Bean

    public TransferService transferService() {

        return new TransferService(accountRepository());

    }

 

}

 

system-test-config.xml:

 

<beans>

    <!-- enable processing of annotations such as @Autowired and @Configuration -->

<!-- 允许处理类似于@Autowired@Configuration这样的注解 -->

    <context:annotation-config/>

    <context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>

 

    <bean class="com.acme.AppConfig"/>

 

    <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">

        <property name="url" value="${jdbc.url}"/>

        <property name="username" value="${jdbc.username}"/>

        <property name="password" value="${jdbc.password}"/>

    </bean>

</beans>

 

jdbc.properties:

 

jdbc.url=jdbc:hsqldb:hsql://localhost/xdb

jdbc.username=sa

jdbc.password=

 

public static void main(String[] args) {

    ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/com/acme/system-test-config.xml");

    TransferService transferService = ctx.getBean(TransferService.class);

    // ...

}

 

[Note]

注意

 

In system-test-config.xml above, the AppConfig <bean/> does not declare an id element. While it would be acceptable to do so, it is unnecessary given that no other bean will ever refer to it, and it is unlikely that it will be explicitly fetched from the container by name. Likewise with the DataSource bean - it is only ever autowired by type, so an explicit bean id is not strictly required.

在上面的system-test-config.xml中,bean AppConfig并没有定义id元素。这是可以被接受的,而且没有必要定义因为没有bean会引用到他,而且不应该让容器通过名字引用到他。同样也包括DataSourcebean——只是通过类型注入,因此不需要明确定义beanid

 

Because @Configuration is meta-annotated with @Component, @Configuration-annotated classes are automatically candidates for component scanning. Using the same scenario as above, we can redefine system-test-config.xml to take advantage of component-scanning. Note that in this case, we dont need to explicitly declare <context:annotation-config/>, because <context:component-scan/> enables the same functionality.

因为@Configuration@Component的一个元注解,基于@Configuration类会自动被组件扫描发现。和上面的场景一样,我们重新定义了system-test-config.xml文件来使用组件扫描。注意在这种情况下,我们不需要明确定义<context:annotation-config/>,因为<context:component-scan/>也有相同的功能。

 

system-test-config.xml:

 

<beans>

<!-- picks up and registers AppConfig as a bean definition -->

<!-- 将AppConfig作为bean的定义来处理和注册 -->

    <context:component-scan base-package="com.acme"/>

    <context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>

 

    <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">

        <property name="url" value="${jdbc.url}"/>

        <property name="username" value="${jdbc.username}"/>

        <property name="password" value="${jdbc.password}"/>

    </bean>

</beans>

 

@Configuration class-centric use of XML with @ImportResource

使用@ImportResource引入xml@Configuration类为中心的情况下

 

In applications where @Configuration classes are the primary mechanism for configuring the container, it will still likely be necessary to use at least some XML. In these scenarios, simply use @ImportResource and define only as much XML as is needed. Doing so achieves a "Java-centric" approach to configuring the container and keeps XML to a bare minimum.

如果在应用中以@Configuration类作为主要的策略来配置容器,但仍然需要一些xml文件。在这些场景中,简单的使用@ImportResource来引入xml是有用的。这样可以在以java为中心的前提下最低限度的使用xml

 

@Configuration

@ImportResource("classpath:/com/acme/properties-config.xml")

public class AppConfig {

 

    @Value("${jdbc.url}")

    private String url;

 

    @Value("${jdbc.username}")

    private String username;

 

    @Value("${jdbc.password}")

    private String password;

 

    @Bean

    public DataSource dataSource() {

        return new DriverManagerDataSource(url, username, password);

    }

 

}

 

properties-config.xml

<beans>

    <context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>

</beans>

 

jdbc.properties

jdbc.url=jdbc:hsqldb:hsql://localhost/xdb

jdbc.username=sa

jdbc.password=

 

public static void main(String[] args) {

    ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);

    TransferService transferService = ctx.getBean(TransferService.class);

    // ...

}

 

7.13 Environment abstraction

环境抽象

 

The Environment is an abstraction integrated in the container that models two key aspects of the application environment: profiles and properties.

环境是容器中抽象的模型,应用中环境分为两个关键的部分:profilesproperties

 

A profile is a named, logical group of bean definitions to be registered with the container only if the given profile is active. Beans may be assigned to a profile whether defined in XML or via annotations. The role of the Environment object with relation to profiles is in determining which profiles (if any) are currently active, and which profiles (if any) should be active by default.

profile是一个命名的bean定义的逻辑组合,如果在profile被激活是可以被容器注册。通过xml或注解定义的bean将分配给profile。环境的角色和profile是有关的,而且取决于哪个profile被激活和哪个profile是默认被激活的。

 

Properties play an important role in almost all applications, and may originate from a variety of sources: properties files, JVM system properties, system environment variables, JNDI, servlet context parameters, ad-hoc Properties objects, Maps, and so on. The role of the Environment object with relation to properties is to provide the user with a convenient service interface for configuring property sources and resolving properties from them.

properties在几乎所有的应用起到一个很重要的作用,并且在各种不同的源码中存在:properties文件、java系统properties、系统环境变量、JNDIservlet上下文参数、专用的properties对象、map等等。环境的角色和用户提供的properties是有关的,使用一个方便的服务接口用于配置property源码和处理里面的内容。

 

7.13.1 Bean definition profiles

bean定义的profiles

 

Bean definition profiles is a mechanism in the core container that allows for registration of different beans in different environments. The word environment can mean different things to different users and this feature can help with many use cases, including:

bean定义profile是一种在核心容器中的策略允许注册在不同环境中的不同的bean。环境这个单词可以意味着不同的用户使用不同的内容,这个特性在很多方面有用,包括:

 

    working against an in-memory datasource in development vs looking up that same datasource from JNDI when in QA or production

在开发中使用内置的数据源 vs QA或产品中需找相同的数据源

    registering monitoring infrastructure only when deploying an application into a performance environment

当部署一个应用到一个环境是注册监控的基础组件

    registering customized implementations of beans for customer A vs. customer B deployments

为客户A注册自定义的bean实现 vs 客户B部署

 

Lets consider the first use case in a practical application that requires a DataSource. In a test environment, the configuration may look like this:

我们考虑一个在特定应用中需要数据源的例子。在测试环境,配置或许是这样的:

 

@Bean

public DataSource dataSource() {

    return new EmbeddedDatabaseBuilder()

        .setType(EmbeddedDatabaseType.HSQL)

        .addScript("my-schema.sql")

        .addScript("my-test-data.sql")

        .build();

}

 

Lets now consider how this application will be deployed into a QA or production environment, assuming that the datasource for the application will be registered with the production application servers JNDI directory. Our dataSource bean now looks like this:

让我们考虑一下这样的应用如何部署到QA或生产环境中,假设应用的数据源将会被应用服务器的JNDI注册。我们的数据现在可以是这样的:

 

@Bean(destroyMethod="")

public DataSource dataSource() throws Exception {

    Context ctx = new InitialContext();

    return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");

}

 

The problem is how to switch between using these two variations based on the current environment. Over time, Spring users have devised a number of ways to get this done, usually relying on a combination of system environment variables and XML <import/> statements containing ${placeholder} tokens that resolve to the correct configuration file path depending on the value of an environment variable. Bean definition profiles is a core container feature that provides a solution to this problem.

问题在于如果根据现有的环境切换两种不同的配置。spring花了很长时间提供了很多方法来处理这种情况,通常依赖于系统环境变量和xml中的import定义包括${placeholder}来处理当前的配置文件路径依赖一个系统变量。bean定义profile是一个重要的容器特性提供了这个问题的一种解决方案。

 

If we generalize the example use case above of environment-specific bean definitions, we end up with the need to register certain bean definitions in certain contexts, while not in others. You could say that you want to register a certain profile of bean definitions in situation A, and a different profile in situation B. Lets first see how we can update our configuration to reflect this need.

如果我们使用基于环境的bean定义的例子,我们不需要在特定的上下文注册特定bean的定义。你可以在不同情况下使用不同的profile。让我们首先看一下如何根据我们的需要更新配置。

 

@Profile

 

The @Profile annotation allows you to indicate that a component is eligible for registration when one or more specified profiles are active. Using our example above, we can rewrite the dataSource configuration as follows:

@Profile注解允许你指出一个组件可以被注册,当一个或多个profile被激活时。使用我们上面的例子,我们可以重写数据源的配置如下:

 

@Configuration

@Profile("dev")

public class StandaloneDataConfig {

 

    @Bean

    public DataSource dataSource() {

        return new EmbeddedDatabaseBuilder()

            .setType(EmbeddedDatabaseType.HSQL)

            .addScript("classpath:com/bank/config/sql/schema.sql")

            .addScript("classpath:com/bank/config/sql/test-data.sql")

            .build();

    }

}

 

@Configuration

@Profile("production")

public class JndiDataConfig {

 

    @Bean(destroyMethod="")

    public DataSource dataSource() throws Exception {

        Context ctx = new InitialContext();

        return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");

    }

}

 

[Note]

注意

 

As mentioned before, with @Bean methods, you will typically choose to use programmatic JNDI lookups: either using Springs JndiTemplate/JndiLocatorDelegate helpers or the straight JNDI InitialContext usage shown above, but not the JndiObjectFactoryBean variant which would force you to declare the return type as the FactoryBean type.

就像上面提到的,使用@Bean方法,你可以选择编程查找JNDI:尽管使用springJndiTemplate/JndiLocatorDelegate可以更好的使用Jndi如上,但是JndiObjectFactoryBean变量将会强制返回工厂bean的类型。

 

@Profile can be used as a meta-annotation for the purpose of creating a custom composed annotation. The following example defines a custom @Production annotation that can be used as a drop-in replacement for @Profile("production"):

@Profile也可以被当做元注解用于创建自定义组合注解。下面的例子定义了一个自定义的@Production注解可以替换@Profile("production")

 

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Profile("production")

public @interface Production {

}

 

@Profile can also be declared at the method level to include only one particular bean of a configuration class:

@Profile也可以被定义在方法级别,包括只有一个特定beanconfiguration类中:

 

@Configuration

public class AppConfig {

 

    @Bean

    @Profile("dev")

    public DataSource devDataSource() {

        return new EmbeddedDatabaseBuilder()

            .setType(EmbeddedDatabaseType.HSQL)

            .addScript("classpath:com/bank/config/sql/schema.sql")

            .addScript("classpath:com/bank/config/sql/test-data.sql")

            .build();

    }

 

    @Bean

    @Profile("production")

    public DataSource productionDataSource() throws Exception {

        Context ctx = new InitialContext();

        return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");

    }

}

 

[Tip]

提示

 

If a @Configuration class is marked with @Profile, all of the @Bean methods and @Import annotations associated with that class will be bypassed unless one or more of the specified profiles are active. If a @Component or @Configuration class is marked with @Profile({"p1", "p2"}), that class will not be registered/processed unless profiles 'p1' and/or 'p2' have been activated. If a given profile is prefixed with the NOT operator (!), the annotated element will be registered if the profile is not active. For example, given @Profile({"p1", "!p2"}), registration will occur if profile 'p1' is active or if profile 'p2' is not active.

如果@Configuration类被标注为@Profile,所有的@Bean方法和@Import注解将会和类关联并将忽略一个或多个特定的profile被激活。如果一个@Component@Configuration类被标注了@Profile({"p1", "p2"}),这个类将不会被注册除非两个profile都被激活。如果给定的前缀是非,则注解元素将被注册如果profile没有被激活。例如,定义了@Profile({"p1", "!p2"}),意味着p1被激活而p2不被激活。

 

7.13.2 XML bean definition profiles

xmlbean定义profile

 

The XML counterpart is the profile attribute of the <beans> element. Our sample configuration above can be rewritten in two XML files as follows:

xmlbean元素中有profile属性。上面的例子可以转化为xml文件如下:

 

<beans profile="dev"

    xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:jdbc="http://www.springframework.org/schema/jdbc"

    xsi:schemaLocation="...">

 

    <jdbc:embedded-database id="dataSource">

        <jdbc:script location="classpath:com/bank/config/sql/schema.sql"/>

        <jdbc:script location="classpath:com/bank/config/sql/test-data.sql"/>

    </jdbc:embedded-database>

</beans>

 

<beans profile="production"

    xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:jee="http://www.springframework.org/schema/jee"

    xsi:schemaLocation="...">

 

    <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/>

</beans>

 

It is also possible to avoid that split and nest <beans/> elements within the same file:

当然也可以将不同profile配置到同一个beans元素中在一个文件里:

 

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:jdbc="http://www.springframework.org/schema/jdbc"

    xmlns:jee="http://www.springframework.org/schema/jee"

    xsi:schemaLocation="...">

 

    <!-- other bean definitions -->

<!-- 其他的bean的定义 -->

 

    <beans profile="dev">

        <jdbc:embedded-database id="dataSource">

            <jdbc:script location="classpath:com/bank/config/sql/schema.sql"/>

            <jdbc:script location="classpath:com/bank/config/sql/test-data.sql"/>

        </jdbc:embedded-database>

    </beans>

 

    <beans profile="production">

        <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/>

    </beans>

</beans>

 

The spring-bean.xsd has been constrained to allow such elements only as the last ones in the file. This should help provide flexibility without incurring clutter in the XML files.

spring-bean.xsd包括定义在这个文件中的元素。这可以帮助我们更简单的配置xml文件。

 

Activating a profile

激活一个profile

 

Now that we have updated our configuration, we still need to instruct Spring which profile is active. If we started our sample application right now, we would see a NoSuchBeanDefinitionException thrown, because the container could not find the Spring bean named dataSource.

现在我们更新我们配置,我们依然需要告诉spring哪个profile是激活的。如果我们现在直接启动应用,我们会看到NoSuchBeanDefinitionException异常被抛出,因为容器没有找到springbean和数据源。

 

Activating a profile can be done in several ways, but the most straightforward is to do it programmatically against the Environment API which is available via an ApplicationContext:

激活一个profile有几种方法,但是最直接的方法是通过EnvironmentAPI编程,通过ApplicationContext

 

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();

ctx.getEnvironment().setActiveProfiles("dev");

ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class);

ctx.refresh();

 

In addition, profiles may also be activated declaratively through the spring.profiles.active property which may be specified through system environment variables, JVM system properties, servlet context parameters in web.xml, or even as an entry in JNDI (see Section 7.13.3, PropertySource abstraction). In integration tests, active profiles can be declared via the @ActiveProfiles annotation in the spring-test module (see the section called Context configuration with environment profiles).

额外的,profile可以通过spring.profiles.active属性进行激活,可以作为系统环境变量、JVM系统属性、servlet上下文属性在web.xml中或作为一个实体在JNDI中(见7.13.3节“PropertySource抽象”)。在集成测试中,激活profile可以通过定义@ActiveProfiles注解在spring-test模块中(见章节“使用环境profile的上下文配置”)。

 

Note that profiles are not an "either-or" proposition; it is possible to activate multiple profiles at once. Programmatically, simply provide multiple profile names to the setActiveProfiles() method, which accepts String? varargs:

注意profiles不是二选一的命题,可以一次激活多个profiles。使用编程的方式,简单的在setActiveProfiles方法中提供多个profile名字就可以,该方法接受多个字符串参数:

 

ctx.getEnvironment().setActiveProfiles("profile1", "profile2");

 

Declaratively, spring.profiles.active may accept a comma-separated list of profile names:

相应的,spring.profiles.active也可以接受逗号分隔的profile名字的列表:

 

-Dspring.profiles.active="profile1,profile2"

 

Default profile

默认profile

 

The default profile represents the profile that is enabled by default. Consider the following:

默认的profile代表profile将会默认使用。比如:

 

@Configuration

@Profile("default")

public class DefaultDataConfig {

 

    @Bean

    public DataSource dataSource() {

        return new EmbeddedDatabaseBuilder()

            .setType(EmbeddedDatabaseType.HSQL)

            .addScript("classpath:com/bank/config/sql/schema.sql")

            .build();

    }

}

 

If no profile is active, the dataSource above will be created; this can be seen as a way to provide a default definition for one or more beans. If any profile is enabled, the default profile will not apply.

没有profile被激活,但是数据源将被创建,这可以作为一种方式提供一个默认的定义为一个或多个bean。如果有profile被激活,则默认profile将不会被默认激活。

 

The name of the default profile can be changed using setDefaultProfiles() on the Environment or declaratively using the spring.profiles.default property.

默认profile的名字可以通过EnvironmentsetDefaultProfiles来改变或使用spring.profiles.default属性来定义。

 

7.13.3 PropertySource abstraction

PropertySource抽象

 

Springs Environment abstraction provides search operations over a configurable hierarchy of property sources. To explain fully, consider the following:

spring的环境抽象可以提供查找选型通过配置属性源码的层级。为了更好的说明,考虑下面的例子:

 

ApplicationContext ctx = new GenericApplicationContext();

Environment env = ctx.getEnvironment();

boolean containsFoo = env.containsProperty("foo");

System.out.println("Does my environment contain the 'foo' property? " + containsFoo);

 

In the snippet above, we see a high-level way of asking Spring whether the foo property is defined for the current environment. To answer this question, the Environment object performs a search over a set of PropertySource objects. A PropertySource is a simple abstraction over any source of key-value pairs, and Springs StandardEnvironment is configured with two PropertySource objects??one representing the set of JVM system properties (a la System.getProperties()) and one representing the set of system environment variables (a la System.getenv()).

在上面的片段中,我们看到了一种高级的方法用于从spring查询foo属性是否定义在当前的环境中。为了回答这个问题,环境提供了从属性中查找的功能。一个PropertySource就是一个简单的抽象对任何key-value对,和springStandardEnvironment是由两个PropertySourceobject配置的,一个是JVM的系统属性(System.getPropertieses),另一个是系统环境变量(System.getenv)。

 

[Note]

注意

 

These default property sources are present for StandardEnvironment, for use in standalone applications. StandardServletEnvironment is populated with additional default property sources including servlet config and servlet context parameters. StandardPortletEnvironment similarly has access to portlet config and portlet context parameters as property sources. Both can optionally enable a JndiPropertySource. See the javadocs for details.

默认的PropertySource代表标准环境,用于独立的应用。StandardServletEnvironment由额外的默认属性源码填充包括servlet的配置和servlet的上下文参数。StandardProtleEnvironment类似的访问portlet配置和portlet上下文参数作为属性源码。每一选项都支持JndiPropertySource。详见javadocs

 

Concretely, when using the StandardEnvironment, the call to env.containsProperty("foo") will return true if a foo system property or foo environment variable is present at runtime.

具体说明,当使用StandardEnvironment时,调用env.containsProperty("foo")将会返回true如果foo系统变量或foo环境变量在运行时可见。

 

[Tip]

提示

 

The search performed is hierarchical. By default, system properties have precedence over environment variables, so if the foo property happens to be set in both places during a call to env.getProperty("foo"), the system property value will 'win' and be returned preferentially over the environment variable. Note that property values will not get merged but rather completely overridden by a preceding entry.

查找是层级的。默认的,系统变量会覆盖环境变量,因此如果foo属性在两种set中都存在,则会采用系统变量的值,覆盖环境变量的值。注意,属性不会合并但是可以覆盖。

 

For a common StandardServletEnvironment, the full hierarchy looks as follows, with the highest-precedence entries at the top:

对于一个通常的StandardServletEnvironment,下面是全部的层级,按优先级排列从上到下:

 

    ServletConfig parameters (if applicable, e.g. in case of a DispatcherServlet context)

ServletConfig参数(如果可用,例如DispatcherServlet上下文)

    ServletContext parameters (web.xml context-param entries)

ServletContext参数(web.xml中的context-param属性)

    JNDI environment variables ("java:comp/env/" entries)

JNDI环境变量("java:comp/env/"实体)

    JVM system properties ("-D" command-line arguments)

JVM系统参数("-D"命令行参数)

    JVM system environment (operating system environment variables)

JVM系统环境(操作系统环境变量)

 

Most importantly, the entire mechanism is configurable. Perhaps you have a custom source of properties that youd like to integrate into this search. No problem??simply implement and instantiate your own PropertySource and add it to the set of PropertySources for the current Environment:

最重要的,这个策略是可以配置的。或许你有一个自定义的属性代码你希望可以被搜索。没有问题,简单实现和实例化你自己的PropertySource并且加入PropertySource的集合为当前的环境:

 

ConfigurableApplicationContext ctx = new GenericApplicationContext();

MutablePropertySources sources = ctx.getEnvironment().getPropertySources();

sources.addFirst(new MyPropertySource());

 

In the code above, MyPropertySource has been added with highest precedence in the search. If it contains a foo property, it will be detected and returned ahead of any foo property in any other PropertySource. The MutablePropertySources API exposes a number of methods that allow for precise manipulation of the set of property sources.

在上面的代码中,MyPropertySource被加入了搜索的最高优先级。如果他包含foo属性,他将首先被探测并返回覆盖其他PropertySource中的值。MutablePropertySources暴露了一系列方法允许精确的控制属性源码。

 

7.13.4 @PropertySource

 

The @PropertySource annotation provides a convenient and declarative mechanism for adding a PropertySource to Springs Environment.

@PropertySource注解提供了一个简单的方式用于向spring的环境中添加属性源码。

 

Given a file "app.properties" containing the key/value pair testbean.name=myTestBean, the following @Configuration class uses @PropertySource in such a way that a call to testBean.getName() will return "myTestBean".

提供一个文件app.properties文件包含key-value对如:testbean.name=myTestBean,下面的@Configuration类使用了@PropertySource注解以如下的方式调用了testBean.getName方法,将会返回myTestBean

 

@Configuration

@PropertySource("classpath:/com/myco/app.properties")

public class AppConfig {

    @Autowired

    Environment env;

 

    @Bean

    public TestBean testBean() {

        TestBean testBean = new TestBean();

        testBean.setName(env.getProperty("testbean.name"));

        return testBean;

    }

}

 

Any ${?} placeholders present in a @PropertySource resource location will be resolved against the set of property sources already registered against the environment. For example:

任何在@PropertySource资源中的占位符可以被属性源码在注册时被处理,如下:

 

@Configuration

@PropertySource("classpath:/com/${my.placeholder:default/path}/app.properties")

public class AppConfig {

    @Autowired

    Environment env;

 

    @Bean

    public TestBean testBean() {

        TestBean testBean = new TestBean();

        testBean.setName(env.getProperty("testbean.name"));

        return testBean;

    }

}

 

Assuming that "my.placeholder" is present in one of the property sources already registered, e.g. system properties or environment variables, the placeholder will be resolved to the corresponding value. If not, then "default/path" will be used as a default. If no default is specified and a property cannot be resolved, an IllegalArgumentException will be thrown.

假设"my.placeholder"代表其中一个已经被注册的属性,例如系统参数或环境变量,那占位符将替换为相应的值。如果没有,则"default/path"将被作为默认值。如果灭有默认值可以处理,将会抛出非法参数的异常。

 

7.13.5 Placeholder resolution in statements

在声明中的占位符

 

Historically, the value of placeholders in elements could be resolved only against JVM system properties or environment variables. No longer is this the case. Because the Environment abstraction is integrated throughout the container, its easy to route resolution of placeholders through it. This means that you may configure the resolution process in any way you like: change the precedence of searching through system properties and environment variables, or remove them entirely; add your own property sources to the mix as appropriate.

历史上说,在元素中占位符的值可以通过JVM系统参数或环境变量来处理。不再是这样的。因为环境抽象已经集成在容器,可以更加容器的处理占位符。这意味着你可以配置处理方式根据你的需要:改变查找的优先级或移除他们、添加你自己的属性源码来混合使用。

 

Concretely, the following statement works regardless of where the customer property is defined, as long as it is available in the Environment:

具体的,下面的声明可以作为一个自定义的属性来定义,并且在容器中有效:

 

<beans>

    <import resource="com/bank/service/${customer}-config.xml"/>

</beans>

 

7.14 Registering a LoadTimeWeaver

注册一个LoadTimeWeaver

 

The LoadTimeWeaver is used by Spring to dynamically transform classes as they are loaded into the Java virtual machine (JVM).

spring使用的LoadTimeWeaver用于动态将类加载到java虚拟机。

 

To enable load-time weaving add the @EnableLoadTimeWeaving to one of your @Configuration classes:

允许加载时注入可以在@Configuration类上使用@EnableLoadTimeWeaving注解:

 

@Configuration

@EnableLoadTimeWeaving

public class AppConfig {

 

}

 

Alternatively for XML configuration use the context:load-time-weaver element:

也可以在xml配种使用context:load-time-weaver元素:

 

<beans>

    <context:load-time-weaver/>

</beans>

 

Once configured for the ApplicationContext. Any bean within that ApplicationContext may implement LoadTimeWeaverAware, thereby receiving a reference to the load-time weaver instance. This is particularly useful in combination with Springs JPA support where load-time weaving may be necessary for JPA class transformation. Consult the LocalContainerEntityManagerFactoryBean javadocs for more detail. For more on AspectJ load-time weaving, see Section 11.8.4, Load-time weaving with AspectJ in the Spring Framework.

一旦为ApplicationContext配置了这个选项。任何一个bean可以实现LoadTimeWeaverAware接口,他们接受一个load-time weaver的实例。在组合使用springJPA支持时很有用当load-time weaving可以对JPA类是必要的。详见LocalContainerEntityManagerFactoryBeanjavadocs。关于AspectJ load-time weaving,见11.8.4节,“在spring框架中使用AspectJ实现Load-time weaving”。

 

7.15 Additional Capabilities of the ApplicationContext

ApplicationContext的其他作用

 

As was discussed in the chapter introduction, the org.springframework.beans.factory package provides basic functionality for managing and manipulating beans, including in a programmatic way. The org.springframework.context package adds the ApplicationContext interface, which extends the BeanFactory interface, in addition to extending other interfaces to provide additional functionality in a more application framework-oriented style. Many people use the ApplicationContext in a completely declarative fashion, not even creating it programmatically, but instead relying on support classes such as ContextLoader to automatically instantiate an ApplicationContext as part of the normal startup process of a Java EE web application.

在介绍章节中讨论的,org.springframework.beans.factory包中提供了基本的功能用于管理和操作bean,包括以编程的形式。org.springframework.context包添加了ApplicationContext接口,扩展了BeanFactory接口,用于扩展其他接口提供了额外的功能在更多原生框架的风格。大部分人以声明的风格使用ApplicationContext,不是编程进行创建,而是使用ContextLoader来自动实例化一个应用作为java ee web应用启动过程的一部分。

 

To enhance BeanFactory functionality in a more framework-oriented style the context package also provides the following functionality:

为了增强BeanFactory的功能以原生框架的风格,context包中也提供了以下功能:

 

    Access to messages in i18n-style, through the MessageSource interface.

添加了国际化风格的消息,通过MessageSource接口。

    Access to resources, such as URLs and files, through the ResourceLoader interface.

通过ResourceLoader接口可以访问资源例如URL和文件。

    Event publication to namely beans implementing the ApplicationListener interface, through the use of the ApplicationEventPublisher interface.

通过ApplicationListener接口可以实现对命名bean的事件发布,和ApplicationEventPublisher接口。

    Loading of multiple (hierarchical) contexts, allowing each to be focused on one particular layer, such as the web layer of an application, through the HierarchicalBeanFactory interface.

加载多个上下文,允许每一个关注于特定的层,例如应用的web层通过HierarchicalBeanFactory接口。

 

7.15.1 Internationalization using MessageSource

使用MessageSource实现国际化

 

The ApplicationContext interface extends an interface called MessageSource, and therefore provides internationalization (i18n) functionality. Spring also provides the interface HierarchicalMessageSource, which can resolve messages hierarchically. Together these interfaces provide the foundation upon which Spring effects message resolution. The methods defined on these interfaces include:

ApplicationContext接口继承了MessageSource接口,提供了国际化功能。spring也提供了HierarchicalMessageSource接口,用于处理消息层级。这些接口是spring处理消息的基础。定义在接口中的方法有:

 

    String getMessage(String code, Object[] args, String default, Locale loc): The basic method used to retrieve a message from the MessageSource. When no message is found for the specified locale, the default message is used. Any arguments passed in become replacement values, using the MessageFormat functionality provided by the standard library.

:基本方法用于接收MessageSource的消息。在特定locale中没有消息时,将使用默认的消息。任何传入的参数替换值,使用标准库中的MessageFormate功能。

    String getMessage(String code, Object[] args, Locale loc): Essentially the same as the previous method, but with one difference: no default message can be specified; if the message cannot be found, a NoSuchMessageException is thrown.

:和以一个方面相似,一个区别是,不需要定义默认的消息,如果没有找到消息会抛出NoSuchMessageException异常。

    String getMessage(MessageSourceResolvable resolvable, Locale locale): All properties used in the preceding methods are also wrapped in a class named MessageSourceResolvable, which you can use with this method.

:所有前面的方法中使用的属性可以定义在一个类中,名字为MessageSourceResolvable,这时你可以使用这个方法。

 

When an ApplicationContext is loaded, it automatically searches for a MessageSource bean defined in the context. The bean must have the name messageSource. If such a bean is found, all calls to the preceding methods are delegated to the message source. If no message source is found, the ApplicationContext attempts to find a parent containing a bean with the same name. If it does, it uses that bean as the MessageSource. If the ApplicationContext cannot find any source for messages, an empty DelegatingMessageSource is instantiated in order to be able to accept calls to the methods defined above.

ApplicationContext被加载,将自动寻找定义在上下文中的MessageSource。必须有名为messageSourcebean。如果找到这样的bean,所有前面方法的调用都会委托给消息源。如果没有消息源,ApplicationContext将会常是寻找父容器中包含的同名bean。如果找到则作为MessageSource。如果ApplicationContext没有找到任何消息源,一个空的DelegatingMessageSource将会被初始化用于接受上面定义的方法调用。

 

Spring provides two MessageSource implementations, ResourceBundleMessageSource and StaticMessageSource. Both implement HierarchicalMessageSource in order to do nested messaging. The StaticMessageSource is rarely used but provides programmatic ways to add messages to the source. The ResourceBundleMessageSource is shown in the following example:

spring提供了两个MessageSource实现,ResourceBundleMessageSourceStaticMessageSource。每一个都实现了HierarchicalMessageSource用于嵌入消息。StaticMessageSource很少被使用但是提供了编程的方式用于向源中添加消息。ResourceBundleMessageSource在下面的例子中展示:

 

<beans>

    <bean id="messageSource"

            class="org.springframework.context.support.ResourceBundleMessageSource">

        <property name="basenames">

            <list>

                <value>format</value>

                <value>exceptions</value>

                <value>windows</value>

            </list>

        </property>

    </bean>

</beans>

 

In the example it is assumed you have three resource bundles defined in your classpath called format, exceptions and windows. Any request to resolve a message will be handled in the JDK standard way of resolving messages through ResourceBundles. For the purposes of the example, assume the contents of two of the above resource bundle files are?

这个例子中假设你有三个资源绑定在你的classpath中叫formatexceptionswindows。每个消息的请求都会以JDK标准的方式处理通过ResourceBundles。这个例子的目的,假设上面两个资源绑定的文件是……?

 

# in format.properties

message=Alligators rock!

 

# in exceptions.properties

argument.required=The {0} argument is required.

 

A program to execute the MessageSource functionality is shown in the next example. Remember that all ApplicationContext implementations are also MessageSource implementations and so can be cast to the MessageSource interface.

执行MessageSource功能的程序在下一个例子中。记住所有ApplicationContext的实现也是MessageSource的实现,并且可以转化为MessageSource接口。

 

public static void main(String[] args) {

    MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");

    String message = resources.getMessage("message", null, "Default", null);

    System.out.println(message);

}

 

The resulting output from the above program will be?

上面程序的输出结果是……?

 

Alligators rock!

 

So to summarize, the MessageSource is defined in a file called beans.xml, which exists at the root of your classpath. The messageSource bean definition refers to a number of resource bundles through its basenames property. The three files that are passed in the list to the basenames property exist as files at the root of your classpath and are called format.properties, exceptions.properties, and windows.properties respectively.

简而言之,MessageSource定义在名为beans.xml的文件中,该文件在你classpath的根路径中。messageSourcebean通过他的属性引用了一系列的资源。这三个文件在列表中存在于你的classpath的根目录中名字分别为format.propertiesexceptions.propertieswindows.properties

 

The next example shows arguments passed to the message lookup; these arguments will be converted into Strings and inserted into placeholders in the lookup message.

下面的例子展示了参数用于消息查找,三个参数将会转化为字符串然后替换寻找的消息。

 

<beans>

 

    <!-- this MessageSource is being used in a web application -->

<!-- 这个MessageSource将会用于web应用中 -->

    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">

        <property name="basename" value="exceptions"/>

    </bean>

 

    <!-- lets inject the above MessageSource into this POJO -->

<!-- 让我们把上面的MessageSource注入到这个POJO-->

    <bean id="example" class="com.foo.Example">

        <property name="messages" ref="messageSource"/>

    </bean>

 

</beans>

 

public class Example {

 

    private MessageSource messages;

 

    public void setMessages(MessageSource messages) {

        this.messages = messages;

    }

 

    public void execute() {

        String message = this.messages.getMessage("argument.required",

            new Object [] {"userDao"}, "Required", null);

        System.out.println(message);

    }

 

}

 

The resulting output from the invocation of the execute() method will be?

调用execute方法的输出将会是……?

 

The userDao argument is required.

 

With regard to internationalization (i18n), Springs various MessageSource implementations follow the same locale resolution and fallback rules as the standard JDK ResourceBundle. In short, and continuing with the example messageSource defined previously, if you want to resolve messages against the British (en-GB) locale, you would create files called format_en_GB.properties, exceptions_en_GB.properties, and windows_en_GB.properties respectively.

由于国际化,spring的不同MessageSource实现遵循相同的本地处理方式并且回调规则如标准JDKResourceBundle。简而言之,和前面的messageSource例子通讯,如果你希望消息可以以en-GB处理,你可以创建名字为format_en_GB.propertiesexceptions_en_GB.propertieswindows_en_GB.properties文件。

 

Typically, locale resolution is managed by the surrounding environment of the application. In this example, the locale against which (British) messages will be resolved is specified manually.

通常,本地的处理方法有应用所处的环境决定。在这个例子中,如British的消息需要手动的特殊处理。

 

# in exceptions_en_GB.properties

argument.required=Ebagum lad, the {0} argument is required, I say, required.

 

public static void main(final String[] args) {

    MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");

    String message = resources.getMessage("argument.required",

        new Object [] {"userDao"}, "Required", Locale.UK);

    System.out.println(message);

}

 

The resulting output from the running of the above program will be?

上面程序的输出将会是……?

 

Ebagum lad, the 'userDao' argument is required, I say, required.

 

You can also use the MessageSourceAware interface to acquire a reference to any MessageSource that has been defined. Any bean that is defined in an ApplicationContext that implements the MessageSourceAware interface is injected with the application contexts MessageSource when the bean is created and configured.

你可以使用MessageSourceAware接口来获得任意一个被定义的MessageSource。任意一个实现了MessageSourceAware接口的定义在ApplicationContextbeanbean被创建和配置时都注入到MessageSource的应用上下文中。

 

[Note]

注意

 

As an alternative to ResourceBundleMessageSource, Spring provides a ReloadableResourceBundleMessageSource class. This variant supports the same bundle file format but is more flexible than the standard JDK based ResourceBundleMessageSource implementation. In particular, it allows for reading files from any Spring resource location (not just from the classpath) and supports hot reloading of bundle property files (while efficiently caching them in between). Check out the ReloadableResourceBundleMessageSource javadocs for details.

作为ResourceBundleMessageSource的替代,spring提供了ReloadableResourceBundleMessageSource类。支持相同的bundle文件格式但是更加的方便比标准JDKResourceBundleMessageSource实现。尤其是他支持从任意spring资源位置读取文件(不只是classpath)并且支持热重载资源文件(当有效的缓存之间)。详情见ReloadableResourceBundleMessageSourcejavadocs

 

7.15.2 Standard and Custom Events

标准和自定义事件

 

Event handling in the ApplicationContext is provided through the ApplicationEvent class and ApplicationListener interface. If a bean that implements the ApplicationListener interface is deployed into the context, every time an ApplicationEvent gets published to the ApplicationContext, that bean is notified. Essentially, this is the standard Observer design pattern.

ApplicationEvent类和ApplicationListener接口用于处理ApplicationContext的事件。如果一个bean实现了ApplicationListener接口并部署到上下文中,每次ApplicationEvent发布到ApplicationContext时,这个bean会被通知到。本质上,这是标准的观察者设计模式。

 

[Tip]

提示

 

As of Spring 4.2, the event infrastructure has been significantly improved and offer an annotation-based model as well as the ability to publish any arbitrary event, that is an object that does not necessarily extend from ApplicationEvent. When such an object is published we wrap it in an event for you.

spring4.2中,事件的基础已经被改进并提供了基于注解的模式也可以用于发布事件,这样可以不需要继承ApplicationEvent。这样的object发布后我们会将其包裹为事件。

 

Spring provides the following standard events:

spring提供了以下的标准事件

 

Table 7.7. Built-in Events

内置事件

Event

事件

Explanation

说明

ContextRefreshedEvent

Published when the ApplicationContext is initialized or refreshed, for example, using the refresh() method on the ConfigurableApplicationContext interface. "Initialized" here means that all beans are loaded, post-processor beans are detected and activated, singletons are pre-instantiated, and the ApplicationContext object is ready for use. As long as the context has not been closed, a refresh can be triggered multiple times, provided that the chosen ApplicationContext actually supports such "hot" refreshes. For example, XmlWebApplicationContext supports hot refreshes, but GenericApplicationContext does not.

ApplicationContext被初始化或刷新时被发布,例如在ConfigurableApplicationContext接口中使用refresh方法时。初始化在这里的含义只所有的bean被加载,后处理的bean被探测和激活,单例已经被提前初始化并且ApplicationContext中的object已经可以使用了。如果上下文没有被关闭,refresh可以出发多次,使得ApplicationContext支持热刷新。例如,XmlWebApplicationContext支持热刷新而GenericApplicationContext不支持。

ContextStartedEvent

Published when the ApplicationContext is started, using the start() method on the ConfigurableApplicationContext interface. "Started" here means that all Lifecycle beans receive an explicit start signal. Typically this signal is used to restart beans after an explicit stop, but it may also be used to start components that have not been configured for autostart , for example, components that have not already started on initialization.

ApplicationContext启动时,或使用ConfigurableApplicationContextstart方法时被发布。启动在这里意味着所有生命周期的bean收到了一个明确的start信号。通常这个信号用于在确定的停止后重新启动一个bean,但是他可能重新启动已经配置为自动启动的组件,例如,组件在初始化时没有被start

ContextStoppedEvent

Published when the ApplicationContext is stopped, using the stop() method on the ConfigurableApplicationContext interface. "Stopped" here means that all Lifecycle beans receive an explicit stop signal. A stopped context may be restarted through a start() call.

ApplicationContext停止时,或使用ConfigurableApplicationContext接口的stop方法时被发布。stopped在这里意味着所有生命周期的bean收到了一个明确的停止信号。一个停止的上下文可以通过start的调用重新启动。

ContextClosedEvent

Published when the ApplicationContext is closed, using the close() method on the ConfigurableApplicationContext interface. "Closed" here means that all singleton beans are destroyed. A closed context reaches its end of life; it cannot be refreshed or restarted.

ApplicationContext被关闭或使用ConfigurableApplicationContext接口中的stop方法是被发布。closed在这里意味着所有的单例bean已经被销毁。一个关闭的上下文来到了生命周期的末尾,不能刷新或重启。

RequestHandledEvent

A web-specific event telling all beans that an HTTP request has been serviced. This event is published after the request is complete. This event is only applicable to web applications using Springs DispatcherServlet.

一个特定的web事件告诉所有的bean一个http请求已经被服务了。这个事件在请求完成后发布。这个事件只适用于springDispatcherServletweb应用中。

You can also create and publish your own custom events. This example demonstrates a simple class that extends Springs ApplicationEvent base class:

你可以创建和发布你自己的事件。这个例子描述了一个简单的类继承了springApplicationEvent基类:

 

public class BlackListEvent extends ApplicationEvent {

 

    private final String address;

    private final String test;

 

    public BlackListEvent(Object source, String address, String test) {

        super(source);

        this.address = address;

        this.test = test;

    }

 

    // accessor and other methods...

 

}

 

To publish a custom ApplicationEvent, call the publishEvent() method on an ApplicationEventPublisher. Typically this is done by creating a class that implements ApplicationEventPublisherAware and registering it as a Spring bean. The following example demonstrates such a class:

发布一个自定义的ApplicationEvent,调用ApplicationEventPublisher中的publishEvent方法。通常这个操作是通过创建一个类实现ApplicationEventPublisherAware并且将其注册为springbean。下面的例子展示了这样一个类:

 

public class EmailService implements ApplicationEventPublisherAware {

 

    private List<String> blackList;

    private ApplicationEventPublisher publisher;

 

    public void setBlackList(List<String> blackList) {

        this.blackList = blackList;

    }

 

    public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {

        this.publisher = publisher;

    }

 

    public void sendEmail(String address, String text) {

        if (blackList.contains(address)) {

            BlackListEvent event = new BlackListEvent(this, address, text);

            publisher.publishEvent(event);

            return;

        }

        // send email...

    }

 

}

 

At configuration time, the Spring container will detect that EmailService implements ApplicationEventPublisherAware and will automatically call setApplicationEventPublisher(). In reality, the parameter passed in will be the Spring container itself; youre simply interacting with the application context via its ApplicationEventPublisher interface.

在配置的时候,spring容器将会探测实现ApplicationEventPublisherAwareEmailService并将自动调用setApplicationEventPublisher方法。实际上,传入的参数是容器本身,你只是通过ApplicationEventPublisher接口和应用上下文交互而已。

 

To receive the custom ApplicationEvent, create a class that implements ApplicationListener and register it as a Spring bean. The following example demonstrates such a class:

处理自定义的ApplicationEvent,需要创建一个类实现的ApplicationListener然后注册为一个springbean。下面的例子展示了一个这样的类:

 

public class BlackListNotifier implements ApplicationListener<BlackListEvent> {

 

    private String notificationAddress;

 

    public void setNotificationAddress(String notificationAddress) {

        this.notificationAddress = notificationAddress;

    }

 

    public void onApplicationEvent(BlackListEvent event) {

        // notify appropriate parties via notificationAddress...

// 在适当的时候通过notificationAddress被通知

    }

 

}

 

Notice that ApplicationListener is generically parameterized with the type of your custom event, BlackListEvent. This means that the onApplicationEvent() method can remain type-safe, avoiding any need for downcasting. You may register as many event listeners as you wish, but note that by default event listeners receive events synchronously. This means the publishEvent() method blocks until all listeners have finished processing the event. One advantage of this synchronous and single-threaded approach is that when a listener receives an event, it operates inside the transaction context of the publisher if a transaction context is available. If another strategy for event publication becomes necessary, refer to the JavaDoc for Springs ApplicationEventMulticaster interface.

注意ApplicationListener通常参数化由于你自定义的事件,BlackListEvent。这意味着onApplicationEvent方法可以是类型安全,避免任何向下的类型转换。你可以根据需要注册多个事件监听器,但是注意默认的时间监听器同步的接收事件。这意味着publishEvent方法将会被阻塞直到所有监听器完成事件的处理。这种同步的有点和单个线程方法是当一个监听器接收一个事件,他在发布者事务上下文中进行操作如果事务上下文是存在的。如果另一个事件发布的策略不在必要,参考springApplicationEventMulticaster接口的javadocs文档。

 

The following example shows the bean definitions used to register and configure each of the classes above:

下面的例子展示了bean定义用于注册和配置上面的类:

 

<bean id="emailService" class="example.EmailService">

    <property name="blackList">

        <list>

            <value>known.spammer@example.org</value>

            <value>known.hacker@example.org</value>

            <value>john.doe@example.org</value>

        </list>

    </property>

</bean>

 

<bean id="blackListNotifier" class="example.BlackListNotifier">

    <property name="notificationAddress" value="blacklist@example.org"/>

</bean>

 

Putting it all together, when the sendEmail() method of the emailService bean is called, if there are any emails that should be blacklisted, a custom event of type BlackListEvent is published. The blackListNotifier bean is registered as an ApplicationListener and thus receives the BlackListEvent, at which point it can notify appropriate parties.

将他们放在一起,当emailServicebean中的sendEmail方法被调用时,如果是黑名单中的email地址,一个自定义事件BlackListEvent将会被发布。blackListNotifierbean作为一个ApplicationListener被注册并接收BlackListEvent事件当他在适当的时候被通知。

 

[Note]

注意

 

Springs eventing mechanism is designed for simple communication between Spring beans within the same application context. However, for more sophisticated enterprise integration needs, the separately-maintained Spring Integration project provides complete support for building lightweight, pattern-oriented, event-driven architectures that build upon the well-known Spring programming model.

spring的事件策略的设计是为了在springbean和相同的应用上下文之间进行简单的通信。然而对于比较复杂的企业集成需要,分开管理spring的集成项目提供了全面的支持用于建立轻量级、基于模式、事件驱动的架构,并建立在大家熟悉的spring编程模型上。

 

Annotation-based Event Listeners

基于注解的事件监听器

 

As of Spring 4.2, an event listener can be registered on any public method of a managed bean via the EventListener annotation. The BlackListNotifier can be rewritten as follows:

spring4.2开始,事件监听器可以注册在任意公共方法撒花姑娘通过EventListener注解在一个被管理的bean中。BlackListNotifier可以重写成如下的样子:

 

public class BlackListNotifier {

 

    private String notificationAddress;

 

    public void setNotificationAddress(String notificationAddress) {

        this.notificationAddress = notificationAddress;

    }

 

    @EventListener

    public void processBlackListEvent(BlackListEvent event) {

        // notify appropriate parties via notificationAddress...

    }

 

}

 

As you can see above, the method signature actually infer which even type it listens to. This also works for nested generics as long as the actual event resolves the generics parameter you would filter on.

在上面所见,方法的声明中指定了可以监听什么样的事件。这也使用于嵌套泛型只要实际的事件过滤了相应的泛型参数。

 

If your method should listen to several events or if you want to define it with no parameter at all, the event type(s) can also be specified on the annotation itself:

如果你的方法希望监听多个事件或你不希望方法有参数,事件也可以通过注解本身来本身。

 

@EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})

public void handleContextStart() {

 

}

 

It is also possible to add additional runtime filtering via the condition attribute of the annotation that defines a SpEL expression that should match to actually invoke the method for a particular event.

也可以通过注解的condition属性添加额外的运行时过滤,注解通过定义SpEL表达式来匹配实际的特定事件。

 

For instance, our notifier can be rewritten to be only invoked if the test attribute of the event is equal to foo:

例如,我们的notifier可以重写用于只有当事件的test属性为foo时被调用:

 

@EventListener(condition = "#blEvent.test == 'foo'")

public void processBlackListEvent(BlackListEvent blEvent) {

    // notify appropriate parties via notificationAddress...

}

 

Each SpEL expression evaluates again a dedicated context. The next table lists the items made available to the context so one can use them for conditional event processing:

每个SpEL表达式处理一个相应的上下文。下面的表格列出了项目可以适用于上下文因此可以用于条件事件的处理:

 

Table 7.8. Event SpEL available metadata

事件SpEL可用的元数据

Name

名字

Location

位置

Description

描述

Example

例子

Event

事件

root object

根对象

The actual ApplicationEvent

实际应用事件

#root.event

Arguments array

参数数组

root object

根对象

The arguments (as array) used for invoking the target

用于目标的参数(如数组)

#root.args[0]

Argument name

参数名字

evaluation context

评估上下文

Name of any of the method arguments. If for some reason the names are not available (e.g. no debug information), the argument names are also available under the #a<#arg> where #arg stands for the argument index (starting from 0).

任意方法参数的名字。如果有些情况名字不可用(例如,没有调试信息),参数名也可以在#a<#arg>下当#arg代表参数的索引(从0开始)

#blEvent or #a0 (one can also use #p0 or #p<#arg> notation as an alias).

Note that #root.event allows you to access to the underlying event, even if your method signature actually refers to an arbitrary object that was published.

注意,#root.event允许你访问潜在的事件,即使你的方法签名实际指向了一个已经被发布的object

 

If you need to publish an event as the result of processing another, just change the method signature to return the event that should be published, something like:

如果你需要发布一个事件作为另一个事件的处理结果,只要改变方法的签名返回应该被发布的事件,例如:

 

@EventListener

public ListUpdateEvent handleBlackListEvent(BlackListEvent event) {

    // notify appropriate parties via notificationAddress and

    // then publish a ListUpdateEvent...

}

 

[Note]

注意

 

This feature is not supported for asynchronous listeners.

这个特性不支持异步的监听器

 

This new method will publish a new ListUpdateEvent for every BlackListEvent handled by the method above. If you need to publish several events, just return a Collection of events instead.

这个新的方法会发布一个新的ListUpdateEvent用于每个BlackListEvent被上面的方法处理之后。如果你需要发表多个事件,则返回事件的集合作为代替。

 

Asynchronous Listeners

异步的监听器

 

If you want a particular listener to process events asynchronously, simply reuse the regular @Async support:

如果你希望一个特殊的监听器用于异步处理事件,简单的方法就是使用@Async作为支持:

 

@EventListener

@Async

public void processBlackListEvent(BlackListEvent event) {

    // BlackListEvent is processed in a separate thread

// BlackListEvent在一个分离的线程中进行处理

}

 

Be aware of the following limitations when using asynchronous events:

当使用异步事件处理时应该注意的限制

 

    If the event listener throws an Exception it will not be propagated to the caller, check AsyncUncaughtExceptionHandler for more details.

如果事件监听器抛出了一个异常将不会传播给调用者,详见AsyncUncaughtExceptionHandler

    Such event listener cannot send replies. If you need to send another event as the result of the processing, inject ApplicationEventPublisher to send the event manually.

这样的事件监听器不能发送回复。如你希望发送另一个事件作为处理结果,手动注入ApplicationEventPublisher用于发送事件。

 

Ordering Listeners

监听器的排序

 

If you need the listener to be invoked before another one, just add the @Order annotation to the method declaration:

如果你希望这个监听器在另一个监听器之前执行,需要在方法声明中添加@Order注解:

 

@EventListener

@Order(42)

public void processBlackListEvent(BlackListEvent event) {

    // notify appropriate parties via notificationAddress...

}

 

Generic Events

泛型的事件

 

You may also use generics to further define the structure of your event. Consider an EntityCreatedEvent<T> where T is the type of the actual entity that got created. You can create the following listener definition to only receive EntityCreatedEvent for a Person:

你也会使用泛型来定义你事件的结构。考虑EntityCreatedEvent<T>T作为一个实际的被创建的实体。你可以创建如下的监听器定义用于接收EntityCreatedEvent用于一个Person

 

@EventListener

public void onPersonCreated(EntityCreatedEvent<Person> event) {

    ...

}

 

Due to type erasure, this will only work if the event that is fired resolves the generic parameter(s) on which the event listener filters on (that is something like class PersonCreatedEvent extends EntityCreatedEvent<Person> { ? }).

由于类型的消除,这样将导致这个监听器只会当泛型匹配时被执行如事件监听器过滤某个类PersonCreatedEvent继承了EntityCreatedEvent<Person>

 

In certain circumstances, this may become quite tedious if all events follow the same structure (as it should be the case for the event above). In such a case, you can implement ResolvableTypeProvider to guide the framework beyond what the runtime environment provides:

在确切的情况下,如果所有的事件遵循相同的结构将会非常复杂(因为他应该是上面的事件)。在这种情况下,你可以实现ResolvableTypeProvider用于指导框架当运行时环境被提供:

 

public class EntityCreatedEvent<T>

        extends ApplicationEvent implements ResolvableTypeProvider {

 

    public EntityCreatedEvent(T entity) {

        super(entity);

    }

 

    @Override

    public ResolvableType getResolvableType() {

        return ResolvableType.forClassWithGenerics(getClass(),

                ResolvableType.forInstance(getSource()));

    }

}

 

[Tip]

提示

 

This works not only for ApplicationEvent but any arbitrary object that youd send as an event.

这不仅对ApplicationEvent有效也包括任何你作为事件发送的object

 

7.15.3 Convenient access to low-level resources

方便访问低级别的资源

 

For optimal usage and understanding of application contexts, users should generally familiarize themselves with Springs Resource abstraction, as described in the chapter Chapter 8, Resources.

作为最佳的使用并理解应用上下文,用户应当熟悉他们作为spring的资源抽象,在第8章节资源中有描述。

 

An application context is a ResourceLoader, which can be used to load Resources. A Resource is essentially a more feature rich version of the JDK class java.net.URL, in fact, the implementations of the Resource wrap an instance of java.net.URL where appropriate. A Resource can obtain low-level resources from almost any location in a transparent fashion, including from the classpath, a filesystem location, anywhere describable with a standard URL, and some other variations. If the resource location string is a simple path without any special prefixes, where those resources come from is specific and appropriate to the actual application context type.

一个应用上下文是一个资源加载器,用于加载资源。一个资源本质上JDKjava.net.URL的富版本,实际上,Resource的实现包裹一个适当的java.net.URL的实例。一个资源可以获得低级别的资源来自任何位置包括classpath、一个文件系统、一个标准的URL路径和一些其他的变量。如果资源字符串是一个没有前缀的简单路径,则这些资源来自特定位置取决于实际应用的上下文类型。

 

You can configure a bean deployed into the application context to implement the special callback interface, ResourceLoaderAware, to be automatically called back at initialization time with the application context itself passed in as the ResourceLoader. You can also expose properties of type Resource, to be used to access static resources; they will be injected into it like any other properties. You can specify those Resource properties as simple String paths, and rely on a special JavaBean PropertyEditor that is automatically registered by the context, to convert those text strings to actual Resource objects when the bean is deployed.

你可以配置一个bean定义在应用上下文中实现特定的回调接口,ResourceLoaderAware,用于自动回调在初始化的时候使用应用上下文传递的ResourceLoader。你可以展示资源的属性用于访问静态资源,他们会想其他属性一个被注入。你可以定义这些资源属性以简单的字符串路径并且返回一个特定的JavaBean PropertyEditor可以自动被容器注册,将文本字符串转化为实际的资源objebean被部署的时候。

 

The location path or paths supplied to an ApplicationContext constructor are actually resource strings, and in simple form are treated appropriately to the specific context implementation. ClassPathXmlApplicationContext treats a simple location path as a classpath location. You can also use location paths (resource strings) with special prefixes to force loading of definitions from the classpath or a URL, regardless of the actual context type.

路径或提供给ApplicationContext构造器的路径是实际的资源字符串,在简单的形式将适当的处理用于特定的上下文实现。ClassPathXmlApplicationContext将简单的路径作为classpath的位置。你也可以使用位置路径带有特定的前缀来强制路径定义来自classpath或作为一个URL,而忽略实际的上下文类型。

 

7.15.4 Convenient ApplicationContext instantiation for web applications

用于web应用的方便的ApplicationContext实例化

 

You can create ApplicationContext instances declaratively by using, for example, a ContextLoader. Of course you can also create ApplicationContext instances programmatically by using one of the ApplicationContext implementations.

你可以创建ApplicationContext实例通过,例如,一个ContextLoader。当然你也可以通过使用其中一个ApplicationContext实现来编程创建ApplicationContext实例。

 

You can register an ApplicationContext using the ContextLoaderListener as follows:

你可以而使用ContextLoaderListener注册ApplicationContext如下:

 

<context-param>

    <param-name>contextConfigLocation</param-name>

    <param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value>

</context-param>

 

<listener>

    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>

 

The listener inspects the contextConfigLocation parameter. If the parameter does not exist, the listener uses /WEB-INF/applicationContext.xml as a default. When the parameter does exist, the listener separates the String by using predefined delimiters (comma, semicolon and whitespace) and uses the values as locations where application contexts will be searched. Ant-style path patterns are supported as well. Examples are /WEB-INF/*Context.xml for all files with names ending with "Context.xml", residing in the "WEB-INF" directory, and /WEB-INF/**/*Context.xml, for all such files in any subdirectory of "WEB-INF".

监听器检查contextConfigLocation参数。如果参数不存在,这个监听器将默认使用/WEB-INF/applicationContext.xml。当参数存在的时候,监听器使用之前定义的分隔符(逗号、分行或空格)并使用其值作为路径来寻找应用上下文。任何类型的路径模式都是支持的。例如/WEB-INF/*Context.xml表示所有以Context.xml结尾的文件在WEB-INF目录中,并且/WEB-INF/**/*Context.xml用于子目录的WEB-INF文件夹。

 

7.15.5 Deploying a Spring ApplicationContext as a Java EE RAR file

使用JavaEE RAR文件部署spring的应用上下文

 

It is possible to deploy a Spring ApplicationContext as a RAR file, encapsulating the context and all of its required bean classes and library JARs in a Java EE RAR deployment unit. This is the equivalent of bootstrapping a standalone ApplicationContext, just hosted in Java EE environment, being able to access the Java EE servers facilities. RAR deployment is more natural alternative to scenario of deploying a headless WAR file, in effect, a WAR file without any HTTP entry points that is used only for bootstrapping a Spring ApplicationContext in a Java EE environment.

可以使用RAR文件不是一个springApplicationContext,封装上下文和所有需要的类和JAR库在JavaEE RAR部署包中。这个单独启动一个应用上下文是一样的,只是在JavaEE环境中运行,允许访问JavaEE服务设施。RAR部署时更加自然的代替WAR文件,实际上,WAR文件没有任何HTTP切入点可以只用于在JavaEE环境中启动一个spring的上下文。

 

RAR deployment is ideal for application contexts that do not need HTTP entry points but rather consist only of message endpoints and scheduled jobs. Beans in such a context can use application server resources such as the JTA transaction manager and JNDI-bound JDBC DataSources and JMS ConnectionFactory instances, and may also register with the platforms JMX server - all through Springs standard transaction management and JNDI and JMX support facilities. Application components can also interact with the application servers JCA WorkManager through Springs TaskExecutor abstraction.

RAR部署是一个理想的方式对于不需要HTTP但是包含消息和计划任务的应用。在上下文中的bean可以使用应用服务器资源例如JTA事务管理和绑定JNDIJDBC数据源和JMS连接工厂,并且可以注册平台的JMX服务器——所有通过spring标准事务管理、JNDIJMX支持。应用组件于应用服务器的JCA工作管理可以通过spring的任务执行器抽象相互作用。

 

Check out the JavaDoc of the SpringContextResourceAdapter class for the configuration details involved in RAR deployment.

请查询SpringContextResourceAdapter类的JavaDocs来了解在RAR部署中的配置细节。

 

For a simple deployment of a Spring ApplicationContext as a Java EE RAR file: package all application classes into a RAR file, which is a standard JAR file with a different file extension. Add all required library JARs into the root of the RAR archive. Add a "META-INF/ra.xml" deployment descriptor (as shown in SpringContextResourceAdapters JavaDoc) and the corresponding Spring XML bean definition file(s) (typically "META-INF/applicationContext.xml"), and drop the resulting RAR file into your application servers deployment directory.

对于一个spring应用上下文在JavaEE RAR文件中的简单部署:将所有应用类打包到RAR文件中,是一个标准的JAR文件只是后缀不同。将所有需要的库jar放入RAR的根路径。添加"META-INF/ra.xml"部署描述(在SpringContextResourceAdaptersJavaDocs中有说明)和相应的springxmlbean定义(通常是"META-INF/applicationContext.xml"),然后将RAR文件放入你应用服务器的部署路径中。

 

[Note]

注意

 

Such RAR deployment units are usually self-contained; they do not expose components to the outside world, not even to other modules of the same application. Interaction with a RAR-based ApplicationContext usually occurs through JMS destinations that it shares with other modules. A RAR-based ApplicationContext may also, for example, schedule some jobs, reacting to new files in the file system (or the like). If it needs to allow synchronous access from the outside, it could for example export RMI endpoints, which of course may be used by other application modules on the same machine.

这样的RAR部署单元通常是自包含的:他们不需要向外界暴露组件,不需要相同应用的其他模块。基于RAR应用上下文通常使用JMS目的地来共享其他模块。一个基于RAR的应用上下文也可以计划某些任务,对在文件系统中的新文件做出反应。如果他需要允许同步访问外部,可以暴露RMI来使得其他引用模块在同一台机器上可以被使用。

 

7.16 The BeanFactory

 

The BeanFactory provides the underlying basis for Springs IoC functionality but it is only used directly in integration with other third-party frameworks and is now largely historical in nature for most users of Spring. The BeanFactory and related interfaces, such as BeanFactoryAware, InitializingBean, DisposableBean, are still present in Spring for the purposes of backward compatibility with the large number of third-party frameworks that integrate with Spring. Often third-party components that can not use more modern equivalents such as @PostConstruct or @PreDestroy in order to remain compatible with JDK 1.4 or to avoid a dependency on JSR-250.

BeanFactory提供了潜在的基础对于springIOC功能但是他只能直接使用在集成第三方框架时并且对于大部分spring用户来说具有悠久的历史。BeanFactory和相应的接口如BeanFactoryAwareInitializingBeanDisposableBean是一致在spring中使用用于向后兼容大多数第三方和spring集成的框架。通常第三方组件不能使用新的特性例如@PostConstruct@PreDestroy以保持对JDK1.4的支持或防止与JSR250独立。

 

This section provides additional background into the differences between the BeanFactory and ApplicationContext and how one might access the IoC container directly through a classic singleton lookup.

这一节展示了BeanFactoryApplicationContext的不同点,如何直接访问IOC容器通过传统的单例查找。

 

7.16.1 BeanFactory or ApplicationContext?

 

Use an ApplicationContext unless you have a good reason for not doing so.

除非你有足够好的理由否则请使用ApplicationContext

 

Because the ApplicationContext includes all functionality of the BeanFactory, it is generally recommended over the BeanFactory, except for a few situations such as in embedded applications running on resource-constrained devices where memory consumption might be critical and a few extra kilobytes might make a difference. However, for most typical enterprise applications and systems, the ApplicationContext is what you will want to use. Spring makes heavy use of the BeanPostProcessor extension point (to effect proxying and so on). If you use only a plain BeanFactory, a fair amount of support such as transactions and AOP will not take effect, at least not without some extra steps on your part. This situation could be confusing because nothing is actually wrong with the configuration.

因为ApplicationContext包括所有BeanFactory的功能,通常建议使用BeanFactory除了一些情况例如在嵌入式应用运行在资源匮乏的设备上,其中内存的消耗是很重要的,而且几个kilobytes就会导致不同的特殊情况。然而对于大部分典型的企业应用和系统中,ApplicationContext是可以使用的。spring使用了BeanPostProcessor扩展点(用于代理或其他的)。如果你只是使用普通的BeanFactory,一些事务和AOP将不会有效至少一些额外的操作是必要的。这种情况是困扰的因为没有实际的错误在配置中。

 

The following table lists features provided by the BeanFactory and ApplicationContext interfaces and implementations.

下面的表展示的BeanFactoryApplicationContext接口和实现的特性:

 

Table 7.9. Feature Matrix

特性矩阵

Feature

特性

BeanFactory

ApplicationContext

Bean instantiation/wiring

Bean的初始化和注入

Yes

Yes

Automatic BeanPostProcessor registration

自动BeanPostProcessor注册

No

Yes

Automatic BeanFactoryPostProcessor registration

自动BeanFactoryPostProcessor注册

No

Yes

Convenient MessageSource access (for i18n)

方便的消息源访问(对于国际化)

No

Yes

ApplicationEvent publication

应用事件的发布

No

Yes

To explicitly register a bean post-processor with a BeanFactory implementation, you need to write code like this:

明确注册一个bean通过BeanFactory的实现,你需要像如下这样写代码:

 

DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

// populate the factory with bean definitions

// 填充bean定义中的工厂

 

// now register any needed BeanPostProcessor instances

// 现在注册需要BeanPostProcessor的实例

MyBeanPostProcessor postProcessor = new MyBeanPostProcessor();

factory.addBeanPostProcessor(postProcessor);

 

// now start using the factory

// 现在开始使用工厂

 

To explicitly register a BeanFactoryPostProcessor when using a BeanFactory implementation, you must write code like this:

明确注册一个BeanFactoryPostProcessor当使用BeanFactory实现,你必须像如下这样写代码:

 

DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);

reader.loadBeanDefinitions(new FileSystemResource("beans.xml"));

 

// bring in some property values from a Properties file

// 从属性文件中读入一些属性值

PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();

cfg.setLocation(new FileSystemResource("jdbc.properties"));

 

// now actually do the replacement

// 现在实际开始替换

cfg.postProcessBeanFactory(factory);

 

In both cases, the explicit registration step is inconvenient, which is one reason why the various ApplicationContext implementations are preferred above plain BeanFactory implementations in the vast majority of Spring-backed applications, especially when using BeanFactoryPostProcessors and BeanPostProcessors. These mechanisms implement important functionality such as property placeholder replacement and AOP.

在两个例子中,明确的注册步骤是不方便的,也是一个原因为什么不同的ApplicationContext实现比普通的BeanFactory实现要好在不同spring-backed应用,尤其是使用BeanFactoryPostProcessorsBeanPostProcessors。这些策略实现是重要的例如属性替换和AOP

 

7.16.2 Glue code and the evil singleton

粘合的代码和错误的单例

 

It is best to write most application code in a dependency-injection (DI) style, where that code is served out of a Spring IoC container, has its own dependencies supplied by the container when it is created, and is completely unaware of the container. However, for the small glue layers of code that are sometimes needed to tie other code together, you sometimes need a singleton (or quasi-singleton) style access to a Spring IoC container. For example, third-party code may try to construct new objects directly ( Class.forName() style), without the ability to get these objects out of a Spring IoC container.If the object constructed by the third-party code is a small stub or proxy, which then uses a singleton style access to a Spring IoC container to get a real object to delegate to, then inversion of control has still been achieved for the majority of the code (the object coming out of the container). Thus most code is still unaware of the container or how it is accessed, and remains decoupled from other code, with all ensuing benefits. EJBs may also use this stub/proxy approach to delegate to a plain Java implementation object, retrieved from a Spring IoC container. While the Spring IoC container itself ideally does not have to be a singleton, it may be unrealistic in terms of memory usage or initialization times (when using beans in the Spring IoC container such as a Hibernate SessionFactory) for each bean to use its own, non-singleton Spring IoC container.

最好将大部分应用代码实现成依赖注入的方式,当这些代码在springioc容器外部时,有独立的依赖通过容器当他们创建的时候并且没有意识到容器的存在。然而,对于小的粘合层代码有时需要和其他代码耦合,你有时需要单例(或准单例)风格来访问springioc容器。例如,第三方代码或许视图直接创建一个新的object(使用Class.forName的形式),不在从springioc容器中获得这些object。如果通过第三方代码创建的object是代理使用单例的风格访问springioc容器来获得被委托的真正object,那么反转注入风格依然是代码的重要部分(object来源自容器外)。大部分代码依然不知道容器的存在及他们是如何被访问的,并且和其他的代码是解耦的,有很多的好处。EJB可以使用stub或代理访问普通的Java实现object,从springioc容器中获得。springioc容器理想上不是必须是单例的,对于内存的使用是不现实或初始化次数(当在springioc容器中施一公类似于HibernateSessionFactory),对于每个bean使用非单例的springioc容器。

 

Looking up the application context in a service locator style is sometimes the only option for accessing shared Spring-managed components, such as in an EJB 2.1 environment, or when you want to share a single ApplicationContext as a parent to WebApplicationContexts across WAR files. In this case you should look into using the utility class ContextSingletonBeanFactoryLocator locator that is described in this Spring team blog entry.

查看应用上下文在服务定位器模式在有时是唯一的选项用于访问spring管理的组件,例如在EJB2.1环境中或当你希望共享一个单独的ApplicationContext作为一个WebApplicationContexts的父类,通过WAR文件。在这种情况你应该使用单元类ContextSingletonBeanFactoryLocator定位在spring的小组博客中讨论的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 简介 1.1. 概览 1.2. 使用场景 2. Spring 2.0 的新特性 2.1. 简介 2.2. 控制反转(IoC)容器 2.2.1. 更简单的XML配置 2.2.2. 新的bean作用域 2.2.3. 可扩展的XML编写 2.3. 面向切面编程(AOP) 2.3.1. 更加简单的AOP XML配置 2.3.2. 对@AspectJ 切面的支持 2.4. 中间层 2.4.1. 在XML里更为简单的声明性事务配置 2.4.2. JPA 2.4.3. 异步的JMS 2.4.4. JDBC 2.5. Web层 2.5.1. Spring MVC的表单标签库 2.5.2. Spring MVC合理的默认值 2.5.3. Portlet 框架 2.6. 其他特性 2.6.1. 动态语言支持 2.6.2. JMX 2.6 .3. 任务规划 2.6.4. 对Java 5(Tiger)的支持 2.7. 移植到Spring 2.0 2.7.1. 一些变化 2.7.1.1. Jar包 2.7.1.2. XML配置 2.7.1.3. Deprecated的类和方法 2.7.1.4. Apache OJB 2.7.1.5. iBatis 2.8. 更新的样例应用 2.9. 改进的文档 I. 核心技术 3. 控制反转容器 3.1. 简介 3.2. 容器和bean的基本原理 3.2.1. 容器 3.2.1.1. 配置元数据 3.2.2. 实例化容器 3.2.2.1. 组成基于XML配置元数据 3.2.3. 多种bean 3.2.3.1. 命名bean 3.2.3.2. 实例化bean 3.2.4. 使用容器 3.3. 依赖 3.3.1. 注入依赖 3.3.1.1. Setter注入 3.3.1.2. 构造器注入 3.3.1.3. 一些例子 3.3.2. 构造器参数的解析 3.3.2.1. 构造器参数类型匹配 3.3.2.2. 构造器参数的索引 3.3.3. bean属性及构造器参数详解 3.3.3.1. 直接量(基本类型、Strings类型等。) 3.3.3.2. 引用其它的bean(协作者) 3.3.3.3. 内部bean 3.3.3.4. 集合 3.3.3.5. Nulls 3.3.3.6. XML-based configuration metadata shortcuts 3.3.3.7. 组合属性名称 3.3.4. 使用depends-on 3.3.5. 延迟初始化bean 3.3.6. 自动装配(autowire)协作者 3.3.6.1. 设置Bean使自动装配失效 3.3.7. 依赖检查 3.3.8. 方法注入 3.3.8.1. Lookup方法注入 3.3.8.2. 自定义方法的替代方案 3.4. bean的作用域 3.4.1. Singleton作用域 3.4.2. Prototype作用域 3.4.3. 其他作用域 3.4.3.1. 初始化web配置 3.4.3.2. Request作用域 3.4.3.3. Session作用域 3.4.3.4. global session作用域 3.4.3.5. 作用域bean与依赖 3.4.4. 自定义作用域 3.5. 定制bean特性 3.5.1. Lifecycle接口 3.5.1.1. 初始化回调 3.5.1.2. 析构回调 3.5.2. 了解自己 3.5.2.1. BeanFactoryAware 3.5.2.2. BeanNameAware 3.6. bean定义的继承 3.7. 容器扩展点 3.7.1. 用BeanPostProcessor定制bean 3.7.1.1. 使用BeanPostProcessor的Hello World示例 3.7.1.2. RequiredAnnotationBeanPostProcessor示例 3.7.2. 用BeanFactoryPostProcessor定制配置元数据 3.7.2.1. PropertyPlaceholderConfigurer示例 3.7.2.2. PropertyOverrideConfigurer示例 3.7.3. 使用FactoryBean定制实例化逻辑 3.8. ApplicationContext 3.8.1. 利用MessageSource实现国际化 3.8.2. 事件 3.8.3. 底层资源的访问 3.8.4. ApplicationContext在WEB应用中的实例化 3.9. 粘合代码和可怕的singleton 3.9.1. 使用Singleton-helper类 4. 资源 4.1. 简介 4.2. Resource 接口 4.3. 内置 Resource 实现 4.3.1. UrlResource 4.3.2. ClassPathResource 4.3.3. FileSystemResource 4.3.4. ServletContextResource 4.3.5. InputStreamResource 4.3.6. ByteArrayResource 4.4. ResourceLoader 4.5. ResourceLoaderAware 接口 4.6. 把Resource作为属性来配置 4.7. Application context 和Resource 路径 4.7.1. 构造application context 4.7.1.1. 创建 ClassPathXmlApplicationContext 实例 - 简介 4.7.2. Application context构造器中资源路径的通配符 4.7.2.1. Ant风格的pattern 4.7.2.2. classpath*: 前缀 4.7.2.3. 其他关于通配符的说明 4.7.3. FileSystemResource 提示 5. 校验,数据绑定,BeanWrapper,与属性编辑器 5.1. 简介 5.2. 使用Spring的Validator接口进行校验 5.3. 从错误代码到错误信息 5.4. Bean处理和BeanWrapper 5.4.1. 设置和获取属性值以及嵌套属性 5.4.2. 内建的PropertyEditor实现 5.4.2.1. 注册用户自定义的PropertyEditor 6. 使用Spring进行面向切面编程(AOP) 6.1. 简介 6.1.1. AOP概念 6.1.2. Spring AOP的功能和目标 6.1.3. Spring的AOP代理 6.2. @AspectJ支持 6.2.1. 启用@AspectJ支持 6.2.2. 声明一个切面 6.2.3. 声明一个切入点(pointcut) 6.2.3.1. 切入点指定者的支持 6.2.3.2. 合并切入点表达式 6.2.3.3. 共享常见的切入点(pointcut)定义 6.2.3.4. 示例 6.2.4. 声明通知 6.2.4.1. 前置通知(Before advice) 6.2.4.2. 返回后通知(After returning advice) 6.2.4.3. 抛出后通知(After throwing advice) 6.2.4.4. 后通知(After (finally) advice) 6.2.4.5. 环绕通知(Around Advice) 6.2.4.6. 通知参数(Advice parameters) 6.2.4.7. 通知(Advice)顺序 6.2.5. 引入(Introductions) 6.2.6. 切面实例化模型 6.2.7. 例子 6.3. Schema-based AOP support 6.3.1. 声明一个切面 6.3.2. 声明一个切入点 6.3.3. 声明通知 6.3.3.1. 通知(Advice) 6.3.3.2. 返回后通知(After returning advice) 6.3.3.3. 抛出异常后通知(After throwing advice) 6.3.3.4. 后通知(After (finally) advice) 6.3.3.5. 通知 6.3.3.6. 通知参数 6.3.3.7. 通知顺序 6.3.4. 引入 6.3.5. 切面实例化模型 6.3.6. Advisors 6.3.7. 例子 6.4. AOP声明风格的选择 6.4.1. Spring AOP还是完全用AspectJ? 6.4.2. Spring AOP中使用@AspectJ还是XML? 6.5. 混合切面类型 6.6. 代理机制 6.7. 编程方式创建@AspectJ代理 6.8. 在Spring应用中使用AspectJ 6.8.1. 在Spring中使用AspectJ来为domain object进行依赖注入 6.8.1.1. @Configurable object的单元测试 6.8.1.2. 多application context情况下的处理 6.8.2. Spring中其他的AspectJ切面 6.8.3. 使用Spring IoC来配置AspectJ的切面 6.8.4. 在Spring应用中使用AspectJ Load-time weaving(LTW) 6.9. 其它资源 7. Spring AOP APIs 7.1. 简介 7.2. Spring中的切入点API 7.2.1. 概念 7.2.2. 切入点实施 7.2.3. AspectJ切入点表达式 7.2.4. 便利的切入点实现 7.2.4.1. 静态切入点 7.2.4.2. 动态切入点 7.2.5. 切入点的基类 7.2.6. 自定义切入点 7.3. Spring的通知API 7.3.1. 通知的生命周期 7.3.2. Spring里的通知类型 7.3.2.1. 拦截around通知 7.3.2.2. 前置通知 7.3.2.3. 异常通知 7.3.2.4. 后置通知 7.3.2.5. 引入通知 7.4. Spring里的advisor(Advisor) API 7.5. 使用ProxyFactoryBean创建AOP代理 7.5.1. 基础 7.5.2. JavaBean属性 7.5.3. 基于JDK和CGLIB的代理 7.5.4. 对接口进行代理 7.5.5. 对类进行代理 7.5.6. 使用“全局”advisor 7.6. 简化代理定义 7.7. 使用ProxyFactory通过编程创建AOP代理 7.8. 操作被通知对象 7.9. 使用“自动代理(autoproxy)”功能 7.9.1. 自动代理bean定义 7.9.1.1. BeanNameAutoProxyCreator 7.9.1.2. DefaultAdvisorAutoProxyCreator 7.9.1.3. AbstractAdvisorAutoProxyCreator 7.9.2. 使用元数据驱动的自动代理 7.10. 使用TargetSources 7.10.1. 热交换目标源 7.10.2. 池化目标源 7.10.3. 原型目标源 7.10.4. ThreadLocal目标源 7.11. 定义新的通知类型 7.12. 更多资源 8. 测试 8.1. 简介 8.2. 单元测试 8.3. 集成测试 8.3.1. Context管理和缓存 8.3.2. 测试fixture的依赖注入 8.3.3. 事务管理 8.3.4. 方便的变量 8.3.5. 示例 8.3.6. 运行集成测试 8.4. 更多资源 II. 中间层数据访问 9. 事务管理 9.1. 简介 9.2. 动机 9.3. 关键抽象 9.4. 使用资源同步的事务 9.4.1. 高层次方案 9.4.2. 低层次方案 9.4.3. TransactionAwareDataSourceProxy 9.5. 声明式事务管理 9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. <tx:advice/> 有关的设置 9.5.6. 使用 @Transactional 9.5.6.1. @Transactional 有关的设置 9.5.7. 插入事务操作 9.5.8. 结合AspectJ使用 @Transactional 9.6. 编程式事务管理 9.6.1. 使用 TransactionTemplate 9.6.2. 使用 PlatformTransactionManager 9.7. 选择编程式事务管理还是声明式事务管理 9.8. 与特定应用服务器集成 9.8.1. BEA WebLogic 9.8.2. IBM WebSphere 9.9. 公共问题的解决方案 9.9.1. 对一个特定的 DataSource 使用错误的事务管理器 9.10. 更多的资源 10. DAO支持 10.1. 简介 10.2. 一致的异常层次 10.3. 一致的DAO支持抽象类 11. 使用JDBC进行数据访问 11.1. 简介 11.1.1. Spring JDBC包结构 11.2. 利用JDBC核心类实现JDBC的基本操作和错误处理 11.2.1. JdbcTemplate类 11.2.2. NamedParameterJdbcTemplate类 11.2.3. SimpleJdbcTemplate类 11.2.4. DataSource接口 11.2.5. SQLExceptionTranslator接口 11.2.6. 执行SQL语句 11.2.7. 执行查询 11.2.8. 更新数据库 11.3. 控制数据库连接 11.3.1. DataSourceUtils类 11.3.2. SmartDataSource接口 11.3.3. AbstractDataSource类 11.3.4. SingleConnectionDataSource类 11.3.5. DriverManagerDataSource类 11.3.6. TransactionAwareDataSourceProxy类 11.3.7. DataSourceTransactionManager类 11.4. 用Java对象来表达JDBC操作 11.4.1. SqlQuery类 11.4.2. MappingSqlQuery类 11.4.3. SqlUpdate类 11.4.4. StoredProcedure类 11.4.5. SqlFunction类 12. 使用ORM工具进行数据访问 12.1. 简介 12.2. Hibernate 12.2.1. 资源管理 12.2.2. 在Spring的application context中创建 SessionFactory 12.2.3. HibernateTemplate 12.2.4. 不使用回调的基于Spring的DAO实现 12.2.5. 基于Hibernate3的原生API实现DAO 12.2.6. 编程式的事务划分 12.2.7. 声明式的事务划分 12.2.8. 事务管理策略 12.2.9. 容器资源 vs 本地资源 12.2.10. 在应用服务器中使用Hibernate的注意点 12.3. JDO 12.3.1. 建立PersistenceManagerFactory 12.3.2. JdoTemplate和JdoDaoSupport 12.3.3. 基于原生的JDO API实现DAO 12.3.4. 事务管理 12.3.5. JdoDialect 12.4. Oracle TopLink 12.4.1. SessionFactory 抽象层 12.4.2. TopLinkTemplate 和 TopLinkDaoSupport 12.4.3. 基于原生的TopLink API的DAO实现 12.4.4. 事务管理 12.5. iBATIS SQL Maps 12.5.1. iBATIS 1.x和2.x的概览与区别 12.5.2. iBATIS SQL Maps 1.x 12.5.2.1. 创建SqlMap 12.5.2.2. 使用 SqlMapTemplate 和 SqlMapDaoSupport 12.5.3. iBATIS SQL Maps 2.x 12.5.3.1. 创建SqlMapClient 12.5.3.2. 使用 SqlMapClientTemplate 和 SqlMapClientDaoSupport 12.5.3.3. 基于原生的iBATIS API的DAO实现 12.6. JPA 12.6.1. 在Spring环境中建立JPA 12.6.1.1. LocalEntityManagerFactoryBean 12.6.1.2. LocalContainerEntityManagerFactoryBean 12.6.1.3. 处理多个持久化单元 12.6.2. JpaTemplate 和 JpaDaoSupport 12.6.3. 基于原生的JPA实现DAO 12.6.4. 异常转化 12.6.5. 事务管理 12.6.6. JpaDialect III. Web 13. Web框架 13.1. 介绍 13.1.1. 与其他web框架的集成 13.1.2. Spring Web MVC框架的特点 13.2. DispatcherServlet 13.3. 控制器 13.3.1. AbstractController 和 WebContentGenerator 13.3.2. 其它的简单控制器 13.3.3. MultiActionController 13.3.4. 命令控制器 13.4. 处理器映射(handler mapping) 13.4.1. BeanNameUrlHandlerMapping 13.4.2. SimpleUrlHandlerMapping 13.4.3. 拦截器(HandlerInterceptor) 13.5. 视图与视图解析 13.5.1. 视图解析器 13.5.2. 视图解析链 13.5.3. 重定向(Rediret)到另一个视图 13.5.3.1. RedirectView 13.5.3.2. redirect:前缀 13.5.3.3. forward:前缀 13.6. 本地化解析器 13.6.1. AcceptHeaderLocaleResolver 13.6.2. CookieLocaleResolver 13.6.3. SessionLocaleResolver 13.6.4. LocaleChangeInterceptor 13.7. 使用主题 13.7.1. 简介 13.7.2. 如何定义主题 13.7.3. 主题解析器 13.8. Spring对分段文件上传(multipart file upload)的支持 13.8.1. 介绍 13.8.2. 使用MultipartResolver 13.8.3. 在表单中处理分段文件上传 13.9. 使用Spring的表单标签库 13.9.1. 配置标签库 13.9.2. form标签 13.9.3. input标签 13.9.4. checkbox标签 13.9.5. radiobutton标签 13.9.6. password标签 13.9.7. select标签 13.9.8. option标签 13.9.9. options标签 13.9.10. textarea标签 13.9.11. hidden标签 13.9.12. errors标签 13.10. 处理异常 13.11. 惯例优先原则(convention over configuration) 13.11.1. 对控制器的支持: ControllerClassNameHandlerMapping 13.11.2. 对模型的支持:ModelMap (ModelAndView) 13.11.3. 对视图的支持: RequestToViewNameTranslator 13.12. 其它资源 14. 集成视图技术 14.1. 简介 14.2. JSP和JSTL 14.2.1. 视图解析器 14.2.2. 'Plain-old' JSPs versus JSTL 'Plain-old' JSP与JSTL 14.2.3. 帮助简化开发的额外的标签 14.3. Tiles 14.3.1. 需要的资源 14.3.2. 如何集成Tiles 14.3.2.1. InternalResourceViewResolver 14.3.2.2. ResourceBundleViewResolver 14.4. Velocity和FreeMarker 14.4.1. 需要的资源 14.4.2. Context 配置 14.4.3. 创建模板 14.4.4. 高级配置 14.4.4.1. velocity.properties 14.4.4.2. FreeMarker 14.4.5. 绑定支持和表单处理 14.4.5.1. 用于绑定的宏 14.4.5.2. 简单绑定 14.4.5.3. 表单输入生成宏 14.4.5.4. 重载HTML转码行为并使你的标签符合XHTML 14.5. XSLT 14.5.1. 写在段首 14.5.1.1. Bean 定义 14.5.1.2. 标准MVC控制器代码 14.5.1.3. 把模型数据转化为XML 14.5.1.4. 定义视图属性 14.5.1.5. 文档转换 14.5.2. 小结 14.6. 文档视图(PDF/Excel) 14.6.1. 简介 14.6.2. 配置和安装 14.6.2.1. 文档视图定义 14.6.2.2. Controller 代码 14.6.2.3. Excel视图子类 14.6.2.4. PDF视图子类 14.7. JasperReports 14.7.1. 依赖的资源 14.7.2. 配置 14.7.2.1. 配置ViewResolver 14.7.2.2. 配置View 14.7.2.3. 关于报表文件 14.7.2.4. 使用 JasperReportsMultiFormatView 14.7.3. 构造ModelAndView 14.7.4. 使用子报表 14.7.4.1. 配置子报表文件 14.7.4.2. 配置子报表数据源 14.7.5. 配置Exporter的参数 15. 集成其它Web框架 15.1. 简介 15.2. 通用配置 15.3. JavaServer Faces 15.3.1. DelegatingVariableResolver 15.3.2. FacesContextUtils 15.4. Struts 15.4.1. ContextLoaderPlugin 15.4.1.1. DelegatingRequestProcessor 15.4.1.2. DelegatingActionProxy 15.4.2. ActionSupport 类 15.5. Tapestry 15.5.1. 注入 Spring 托管的 beans 15.5.1.1. 将 Spring Beans 注入到 Tapestry 页面中 15.5.1.2. 组件定义文件 15.5.1.3. 添加抽象访问方法 15.5.1.4. 将 Spring Beans 注入到 Tapestry 页面中 - Tapestry 4.0+ 风格 15.6. WebWork 15.7. 更多资源 16. Portlet MVC框架 16.1. 介绍 16.1.1. 控制器 - MVC中的C 16.1.2. 视图 - MVC中的V 16.1.3. Web作用范围的Bean 16.2. DispatcherPortlet 16.3. ViewRendererServlet 16.4. 控制器 16.4.1. AbstractController和PortletContentGenerator 16.4.2. 其它简单的控制器 16.4.3. Command控制器 16.4.4. PortletWrappingController 16.5. 处理器映射 16.5.1. PortletModeHandlerMapping 16.5.2. ParameterHandlerMapping 16.5.3. PortletModeParameterHandlerMapping 16.5.4. 增加 HandlerInterceptor 16.5.5. HandlerInterceptorAdapter 16.5.6. ParameterMappingInterceptor 16.6. 视图和它们的解析 16.7. Multipart文件上传支持 16.7.1. 使用PortletMultipartResolver 16.7.2. 处理表单里的文件上传 16.8. 异常处理 16.9. Portlet应用的部署 IV. 整合 17. 使用Spring进行远程访问与Web服务 17.1. 简介 17.2. 使用RMI暴露服务 17.2.1. 使用 RmiServiceExporter 暴露服务 17.2.2. 在客户端链接服务 17.3. 使用Hessian或者Burlap通过HTTP远程调用服务 17.3.1. 为Hessian配置DispatcherServlet 17.3.2. 使用HessianServiceExporter暴露你的bean 17.3.3. 客户端连接服务 17.3.4. 使用Burlap 17.3.5. 对通过Hessian或Burlap暴露的服务使用HTTP基础认证 17.4. 使用HTTP调用器暴露服务 17.4.1. 暴露服务对象 17.4.2. 在客户端连接服务 17.5. Web服务 17.5.1. 使用JAXI-RPC暴露服务 17.5.2. 访问Web服务 17.5.3. 注册bean映射 17.5.4. 注册自己的处理方法 17.5.5. 使用XFire来暴露Web服务 17.6. 对远程接口不提供自动探测 17.7. 在选择这些技术时的一些考虑 18. Enterprise Java Bean(EJB)集成 18.1. 简介 18.2. 访问EJB 18.2.1. 概念 18.2.2. 访问本地的无状态Session Bean(SLSB) 18.2.3. 访问远程SLSB 18.3. 使用Spring提供的辅助类实现EJB组件 19. JMS 19.1. 简介 19.2. 使用Spring JMS 19.2.1. JmsTemplate 19.2.2. 连接工厂 19.2.3. (消息)目的地管理 19.2.4. 消息侦听容器 19.2.4.1. SimpleMessageListenerContainer 19.2.4.2. DefaultMessageListenerContainer 19.2.4.3. ServerSessionMessageListenerContainer 19.2.5. 事务管理 19.3. 发送一条消息 19.3.1. 使用消息转换器 19.3.2. SessionCallback 和ProducerCallback 19.4. 接收消息 19.4.1. 同步接收 19.4.2. 异步接收 - 消息驱动的POJOs 19.4.3. SessionAwareMessageListener 接口 19.4.4. MessageListenerAdapter 19.4.5. 事务中的多方参与 20. JMX 20.1. 介绍 20.2. 输出bean到JMX 20.2.1. 创建一个MBeanServer 20.2.2. 复用现有的MBeanServer 20.2.3. MBean的惰性初始化 20.2.4. MBean的自动注册 20.2.5. 控制注册行为 20.3. 控制bean的管理接口 20.3.1. MBeanInfoAssembler 接口 20.3.2. 使用源码级元数据 20.3.3. 使用JDK 5.0注解 20.3.4. 源代码级的元数据类型 20.3.5. 接口AutodetectCapableMBeanInfoAssembler 20.3.6. 用Java接口定义管理接口 20.3.7. 使用MethodNameBasedMBeanInfoAssembler 20.4. 控制bean的 ObjectName 20.4.1. 从Properties中读取ObjectName 20.4.2. 使用 MetadataNamingStrategy 20.5. JSR-160连接器 20.5.1. 服务器端连接器 20.5.2. 客户端连接器 20.5.3. 基于Burlap/Hessian/SOAP的JMX 20.6. 通过代理访问MBeans 20.7. 通知 20.7.1. 为通知注册监听器 20.7.2. 发布通知 20.8. 更多资源 21. JCA CCI 21.1. 介绍 21.2. 配置CCI 21.2.1. 连接器配置 21.2.2. 在Spring中配置ConnectionFactory 21.2.3. 配置CCI连接 21.2.4. 使用一个 CCI 单连接 21.3. 使用Spring的 CCI访问支持 21.3.1. 记录转换 21.3.2. CciTemplate 类 21.3.3. DAO支持 21.3.4. 自动输出记录生成 21.3.5. 总结 21.3.6. 直接使用一个 CCI Connection 接口和Interaction接口 21.3.7. CciTemplate 使用示例 21.4. 建模CCI访问为操作对象 21.4.1. MappingRecordOperation 21.4.2. MappingCommAreaOperation 21.4.3. 自动输出记录生成 21.4.4. 总结 21.4.5. MappingRecordOperation 使用示例 21.4.6. MappingCommAreaOperation 使用示例 21.5. 事务 22. Spring邮件抽象层 22.1. 简介 22.2. Spring邮件抽象结构 22.3. 使用Spring邮件抽象 22.3.1. 可插拔的MailSender实现 22.4. 使用 JavaMail MimeMessageHelper 22.4.1. 创建一条简单的MimeMessage,并且发送出去 22.4.2. 发送附件和嵌入式资源(inline resources) 23. Spring中的定时调度(Scheduling)和线程池(Thread Pooling) 23.1. 简介 23.2. 使用OpenSymphony Quartz 调度器 23.2.1. 使用JobDetailBean 23.2.2. 使用 MethodInvokingJobDetailFactoryBean 23.2.3. 使用triggers和SchedulerFactoryBean来包装任务 23.3. 使用JDK Timer支持类 23.3.1. 创建定制的timers 23.3.2. 使用 MethodInvokingTimerTaskFactoryBean类 23.3.3. 打包:使用TimerFactoryBean来设置任务 23.4. SpringTaskExecutor抽象 23.4.1. TaskExecutor接口 23.4.2. 何时使用TaskExecutor接口 23.4.3. TaskExecutor类型 23.4.4. 使用TaskExecutor接口 24. 动态语言支持 24.1. 介绍 24.2. 第一个例子 24.3. 定义动态语言支持的bean 24.3.1. 公共概念 24.3.1.1. <lang:language/> 元素 24.3.1.2. Refreshable bean 24.3.1.3. 内置动态语言源文件 24.3.1.4. 理解dynamic-language-backed bean context的构造器注入 24.3.2. JRuby beans 24.3.3. Groovy beans 24.3.4. BeanShell beans 24.4. 场景 24.4.1. Spring MVC控制器脚本化 24.4.2. Validator脚本化 24.5. 更多的资源 25. 注解和源代码级的元数据支持 25.1. 简介 25.2. Spring的元数据支持 25.3. 注解 25.3.1. @Required 25.3.2. Spring中的其它@Annotations 25.4. 集成Jakarta Commons Attributes 25.5. 元数据和Spring AOP自动代理 25.5.1. 基本原理 25.5.2. 声明式事务管理 25.5.3. 缓冲 25.5.4. 自定义元数据 25.6. 使用属性来减少MVC web层配置 25.7. 元数据属性的其它用法 25.8. 增加对额外元数据API的支持 A. XML Schema-based configuration A.1. Introduction A.2. XML Schema-based configuration A.2.1. Referencing the schemas A.2.2. The util schema A.2.2.1. <util:constant/> A.2.2.2. <util:property-path/> A.2.2.3. <util:properties/> A.2.2.4. <util:list/> A.2.2.5. <util:map/> A.2.2.6. <util:set/> A.2.3. The jee schema A.2.3.1. <jee:jndi-lookup/> (simple) A.2.3.2. <jee:jndi-lookup/> (with single JNDI environment setting) A.2.3.3. <jee:jndi-lookup/> (with multiple JNDI environment settings) A.2.3.4. <jee:jndi-lookup/> (complex) A.2.3.5. <jee:local-slsb/> (simple) A.2.3.6. <jee:local-slsb/> (complex) A.2.3.7. <jee:remote-slsb/> A.2.4. The lang schema A.2.5. The tx (transaction) schema A.2.6. The aop schema A.2.7. The tool schema A.2.8. The beans schema A.3. Setting up your IDE A.3.1. Setting up Eclipse A.3.2. Setting up IntelliJ IDEA A.3.3. Integration issues A.3.3.1. XML parsing errors in the Resin v.3 application server B. Extensible XML authoring B.1. Introduction B.2. Authoring the schema B.3. Coding a NamespaceHandler B.4. Coding a BeanDefinitionParser B.5. Registering the handler and the schema B.5.1. META-INF/spring.handlers B.5.2. META-INF/spring.schemas C. spring-beans-2.0.dtd D. spring.tld D.1. Introduction D.2. The bind tag D.3. The escapeBody tag D.4. The hasBindErrors tag D.5. The htmlEscape tag D.6. The message tag D.7. The nestedPath tag D.8. The theme tag D.9. The transform tag E. spring-form.tld E.1. Introduction E.2. The checkbox tag E.3. The errors tag E.4. The form tag E.5. The hidden tag E.6. The input tag E.7. The label tag E.8. The option tag E.9. The options tag E.10. The password tag E.11. The radiobutton tag E.12. The select tag E.13. The textarea tag F. Spring 2.0 开发手册中文化项目 F.1. 声明 F.2. 致谢 F.3. 参与人员及任务分配 F.4. Spring 2.0 正式版开发手册翻译说明 F.5. 项目历程 F.5.1. Spring 2.0 RC2 开发手册翻译项目 F.5.2. Spring 2.0 正式版开发手册翻译项目

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值