Spring Core 之 Java-based Container Configuration(基于java的容器配置)

文章目录

  • 一、Basic Concepts: @Bean and @Configuration(基础概念:@Bean和@Configuration)
  • 二、Instantiating the Spring Container by Using AnnotationConfigApplicationContext(使用AnnotationConfigApplicationContext初始化容器)
    • 1、Simple Construction(简单构造器)
    • 2、Building the Container Programmatically by Using register(Class…​)(通过使用register方法编程式的构建容器)
    • 3、Enabling Component Scanning with scan(String…​)(通过scan()启用组件扫描)
  • 三、Using the @Bean Annotation(使用@Bean注解)
    • 1、Declaring a Bean(声明一个Bean)
    • 2、Bean Dependencies(Bean的依赖)
    • 3、Receiving Lifecycle Callbacks(接收生命周期回调)
    • 4、Specifying Bean Scope(指定Bean的作用域)
    • 5、Customizing Bean Naming(自定义bean的名称)
    • 6、Bean Description(给bean定义描述信息)
  • 四、Using the @Configuration annotation(使用@Configuration注解)
    • 1、Injecting Inter-bean Dependencies(定义bean之间的依赖)
    • 2、Lookup Method Injection(查找方法注入)
    • 3、Further Information About How Java-based Configuration Works Internally(关于基于 Java 的配置如何在内部工作的更多信息)
    • 4、Composing Java-based Configurations(编写基于 Java 的配置)
    • 5、Injecting Dependencies on Imported @Bean Definitions(对导入的 @Bean 定义注入依赖)
    • 6、Conditionally Include @Configuration Classes or @Bean Methods(有条件地包含@Configuration 类或@Bean 方法)
    • 7、@Configuration Class-centric Use of XML with @ImportResource( 以@Configuration类为主要配置, XML 为次要配置的 @ImportResource 的使用)

一、Basic Concepts: @Bean and @Configuration(基础概念:@Bean和@Configuration)

The central artifacts in Spring’s new Java-configuration support are @Configuration-annotated classes and @Bean-annotated methods.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 Spring’s XML configuration, the @Bean annotation plays the same role as the element. You can use @Bean-annotated methods with any Spring @Component. However, they are most often used with @Configuration beans.Annotating a class with @Configuration indicates that its primary purpose is as a source of bean definitions. Furthermore, @Configuration classes let inter-bean dependencies be defined by calling other @Bean methods in the same class. The simplest possible @Configuration class reads as follows:

在spring新版本中支持基于java配置的核心工具是@Configuration和@Bean注解。@Bean注解用于指明一个方法进行实例化、配置和初始化一个被springIOC容器管理的对象。与Spring XML配置中的元素扮演的是同样的角色。你可以在注有@Component的类中使用@Bean,但通常是使用的是@Configuration和@Bean结合。@Configuration的主要作用是指明某类当中的信息为bean的定义信息。最简单的@Configuration使用示列如下:

@Configuration
public class AppConfig {

    @Bean
    public MyService myService() {
        return new MyServiceImpl();
    }
}

The preceding AppConfig class is equivalent to the following Spring XML:

其等同于下面的XML配置:

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

二、Instantiating the Spring Container by Using AnnotationConfigApplicationContext(使用AnnotationConfigApplicationContext初始化容器)

This versatile AnnotationConfigApplicationContext is capable of accepting not only @Configuration classes as input but also plain @Component classes and classes annotated with JSR-330 metadata.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.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.

功能丰富的AnnotationConfigApplicationContext 不仅能够接收@Configuration注解的类作为输入,也能够接收@Component注解的类或者JSR-330注解的类作为输入。当@Configuration注解的类作为输入时,该类本身会被注册为一个bean定义,并且其内部@Bean标注的方法都会产生注册为并定义。当提供@Component 和JSR-330 注解的类时,它们被注册为bean 定义,并且假定在这些类中必要时使用DI 元数据,例如@Autowired 或@Inject。

1、Simple Construction(简单构造器)

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

和实例化一个ClassPathXmlApplicationContext时使用xml文件作为入参非常类似,你可以使用@Configuration标注的类作为入参来实例化一个AnnotationConfigApplicationContext。这允许完全不通过 XML 来使用 Spring 容器,如以下示例所示:

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
    MyService myService = ctx.getBean(MyService.class);
    myService.doStuff();
}

As mentioned earlier, 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, as the following example shows:

正如前面所提到的,AnnotationConfigApplicationContext 不仅接收@Configuration标注的类作为入参,任何@Component或JSR-330注解的类都可以作为入参,如下所示:

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(MyServiceImpl.class, Dependency1.class, Dependency2.class);
    MyService myService = ctx.getBean(MyService.class);
    myService.doStuff();
}

2、Building the Container Programmatically by Using register(Class…​)(通过使用register方法编程式的构建容器)

You can instantiate an AnnotationConfigApplicationContext by using a no-arg constructor and then configure it by using the register() method. This approach is particularly useful when programmatically building an AnnotationConfigApplicationContext. The following example shows how to do so:

你可以不传递参数来实例化一个AnnotationConfigApplicationContext ,再通过使用register方法来配置。该方法在需要编程式的构建容器时非常有用,如下所示:

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

3、Enabling Component Scanning with scan(String…​)(通过scan()启用组件扫描)

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

为了启用之间扫描,你可以在@Configuration注解的类上再添加@ComponentScan注解:

@Configuration
@ComponentScan(basePackages = "com.acme") 
public class AppConfig  {
    ...
}

AnnotationConfigApplicationContext exposes the scan(String…​) method to allow for the same component-scanning functionality, as the following example shows:

AnnotationConfigApplicationContext 也提供了 scan(String… ) 方法以允许相同的组件扫描功能,如以下示例所示:

public static void main(String[] args) {
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
    ctx.scan("com.acme");
    ctx.refresh();
    MyService myService = ctx.getBean(MyService.class);
}

三、Using the @Bean Annotation(使用@Bean注解)

@Bean is a method-level annotation and a direct analog of the XML element. The annotation supports some of the attributes offered by , such as: * init-method * destroy-method * autowiring * name.You can use the @Bean annotation in a @Configuration-annotated or in a @Component-annotated class.

@Bean是一个方法级别的注解,并且与XML配置中的元素功能一样。该注解支持\ 提供的一些属性,例如: * init-method * destroy-method * autowiring * name。你可以在 @Configuration-annotated 或 @Component-annotated 类中使用 @Bean 注解。

1、Declaring a Bean(声明一个Bean)

To declare a bean, you can 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 method’s return value. By default, the bean name is the same as the method name. The following example shows a @Bean method declaration:

为了声明一个 bean,你可以使用 @Bean 注解来标注一个方法。你使用的此方法会导致在ApplicationContext 中注册 一个方法返回值类型的bean 定义。默认情况下,bean 名称与方法名称相同。以下示例显示了 @Bean 方法声明:

@Configuration
public class AppConfig {

    @Bean
    public TransferServiceImpl transferService() {
        return new TransferServiceImpl();
    }
}

You can also declare your @Bean method with an interface (or base class) return type, as the following example shows:

你也可以使用接口(或基类)作为返回类型声明 @Bean 方法,如以下示例所示:

@Configuration
public class AppConfig {

    @Bean
    public TransferService transferService() {
        return new TransferServiceImpl();
    }
}

2、Bean Dependencies(Bean的依赖)

A @Bean-annotated method can have an arbitrary number of parameters that describe the dependencies required to build that bean. For instance, if our TransferService requires an AccountRepository, we can materialize that dependency with a method parameter, as the following example shows:

@Bean注解的 方法可以有任意数量的参数来描述构建该 bean 所需的依赖项。例如,如果我们的 TransferService 需要 AccountRepository,我们可以使用方法参数具体化该依赖项,如以下示例所示:

@Configuration
public class AppConfig {

    @Bean
    public TransferService transferService(AccountRepository accountRepository) {
        return new TransferServiceImpl(accountRepository);
    }
}

3、Receiving Lifecycle Callbacks(接收生命周期回调)

Any classes defined with the @Bean annotation support the regular lifecycle callbacks and can use the @PostConstruct and @PreDestroy annotations. If a bean implements InitializingBean, DisposableBean, or Lifecycle, their respective methods are called by the container.The standard set of *Aware interfaces (such as BeanFactoryAware, BeanNameAware, MessageSourceAware, ApplicationContextAware, and so on) are also fully supported.The @Bean annotation supports specifying arbitrary initialization and destruction callback methods, much like Spring XML’s init-method and destroy-method attributes on the bean element, as the following example shows:

任何使用了@Bean注解的类都支持常规的生命周期回调和@PostConstruct、@PreDestroy注解。如果一个Bean实现了InitializingBean,DisposableBean或者其他生命周期相关接口,各个实现方法将会被容器调用。标准的Aware接口(例如BeanFactoryAware,BeanNameAware,MessageSourceAware,ApplicationContextAware)也完全支持。@Bean注解支持任意的初始化和销毁回调方法,就像在xml中bean元素的init-method和destroy-method属性一样,下面是一个小例子:

public class BeanOne {

    public void init() {
        // initialization logic
    }
}

public class BeanTwo {

    public void cleanup() {
        // destruction logic
    }
}

@Configuration
public class AppConfig {

    @Bean(initMethod = "init")
    public BeanOne beanOne() {
        return new BeanOne();
    }

    @Bean(destroyMethod = "cleanup")
    public BeanTwo beanTwo() {
        return new BeanTwo();
    }
}

By default, beans defined with Java configuration 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, you can add @Bean(destroyMethod="") to your bean definition to disable the default (inferred) mode.

默认情况下,通过java配置的bean有一个公共的close或者shutdown方法,在销毁的时候会自动被调用。如果你不希望容器关闭时自动调用它们,可以通过@Bean(destroyMethod="")来配置bean:

@Bean(destroyMethod="")
public DataSource dataSource() throws NamingException {
    return (DataSource) jndiTemplate.lookup("MyDS");
}

4、Specifying Bean Scope(指定Bean的作用域)

Spring includes the @Scope annotation so that you can specify the scope of a bean.The default scope is singleton, but you can override this with the @Scope annotation, as the following example shows:

Spring拥有@Scope注解以便你对一个bean指定作用域,默认的作用域是singleton,但是你可以通过@Scope注解重写指定,如下所示:

@Configuration
public class MyConfiguration {

    @Bean
    @Scope("prototype")
    public Encryptor encryptor() {
        // ...
    }
}

5、Customizing Bean Naming(自定义bean的名称)

By default, configuration classes use a @Bean method’s name as the name of the resulting bean. This functionality can be overridden, however, with the name attribute, as the following example shows:

默认情况下,配置类使用 @Bean 方法的名称作为结果 bean 的名称。但是,可以使用 name 属性覆盖此功能,如以下示例所示:

@Configuration
public class AppConfig {

    @Bean(name = "myThing")
    public Thing thing() {
        return new Thing();
    }
}

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. The following example shows how to set a number of aliases for a bean:

有时需要给单个 bean 多个名称,也称为 bean 别名。为此,@Bean 注释的 name 属性接受一个 String 数组。以下示例显示如何为 bean 设置多个别名:

@Configuration
public class AppConfig {

    @Bean({"dataSource", "subsystemA-dataSource", "subsystemB-dataSource"})
    public DataSource dataSource() {
        // instantiate, configure and return DataSource bean...
    }
}

6、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 through JMX) for monitoring purposes.To add a description to a @Bean, you can use the @Description annotation, as the following example shows:

有时,提供 bean 的更详细的文本描述会很有帮助。当 bean 被公开(可能通过 JMX)用于监视目的时,这可能特别有用。要向 @Bean 添加描述,您可以使用 @Description 注释,如以下示例所示:

@Configuration
public class AppConfig {

    @Bean
    @Description("Provides a basic example of a bean")
    public Thing thing() {
        return new Thing();
    }
}

四、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 through @Bean annotated methods. Calls to @Bean methods on @Configuration classes can also be used to define inter-bean dependencies.

@Configuration 是一个类级别的注解,表明一个对象是 bean 定义的来源。 @Configuration 类中通过@Bean 注解方法声明bean。对@Configuration 类上的@Bean 方法的调用也可用于定义bean 间的依赖关系。

1、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, as the following example shows:

当 bean 相互依赖时,表达这种依赖就像让一个 bean 方法调用另一个方法一样简单,如下例所示:

@Configuration
public class AppConfig {

    @Bean
    public BeanOne beanOne() {
        return new BeanOne(beanTwo());
    }

    @Bean
    public BeanTwo beanTwo() {
        return new BeanTwo();
    }
}

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

这种声明 bean 间依赖关系的方法只有在 @Configuration 类中声明了 @Bean 方法时才有效。你不能使用普通的 @Component 类来声明 bean 间的依赖关系。

2、Lookup Method Injection(查找方法注入)

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. The following example shows how to use lookup method injection:

正如之前所提过的,查找方法注入可能是一个你很少使用的高级特性。它在一个单例bean依赖一个原型bean时很有用,使用java进行配置为这种情况提供了一种自然的方法。下面的例子展示了如何使用查找方法注入:

public abstract class CommandManager {
    public Object process(Object commandState) {
        // grab a new instance of the appropriate Command interface
        Command command = createCommand();
        // set the state on the (hopefully brand new) Command instance
        command.setState(commandState);
        return command.execute();
    }

    // okay... but where is the implementation of this method?
    protected abstract Command createCommand();
}

By using Java configuration, 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. The following example shows how to do so:

提过使用java配置,您可以创建一个 CommandManager 的子类,其中抽象的 createCommand() 方法以查找新(原型)命令对象的方式被覆盖。以下示例显示了如何执行此操作:

@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 createCommand()
    // overridden to return a new prototype Command object
    return new CommandManager() {
        protected Command createCommand() {
            return asyncCommand();
        }
    }
}

3、Further Information About How Java-based Configuration Works Internally(关于基于 Java 的配置如何在内部工作的更多信息)

Consider the following example, which shows a @Bean annotated method being called twice:

思考一下下面的代码,其中一个@Bean注解的方法被调用了两次:

@Configuration
public class AppConfig {
    @Bean
    public ClientDao clientDao() {
        return new ClientDaoImpl();
    }
    
    @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;
    }

}

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 to have two 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.

clientDao()在clientService1()中调用了一次,在clientService2()中也被调用了一次,你可能会期望对于两个service各自有一个clientDao实例。这肯定是有问题的,在spring当中,实例化的bean默认为单例作用域,所有@Configuration 注解的类在启动时会使用 CGLIB 进行子类化。子方法在调用父方法并创建新实例之前,首先会检查容器中是否有任何缓存的(作用域)bean。

There are a few restrictions due to the fact that CGLIB dynamically adds features at startup-time. In particular, 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 或用于默认注入的单个非默认构造函数声明。

4、Composing Java-based Configurations(编写基于 Java 的配置)

Spring’s Java-based configuration feature lets you compose annotations, which can reduce the complexity of your configuration.

Spring 基于 Java 的配置功能允许你编写注解,这可以降低配置的复杂性。

Using the @Import Annotation
Much as the element is used within Spring XML files to aid in modularizing configurations, the @Import annotation allows for loading @Bean definitions from another configuration class, as the following example shows:

就像在 Spring XML 文件中使用 元素来帮助模块化配置一样,@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, as the following example shows:

现在,无需在实例化上下文时同时指定 ConfigA.class 和 ConfigB.class,只需显式提供 ConfigB,如下例所示:

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class);

    // now both beans A and B will be available...
    A a = ctx.getBean(A.class);
    B b = ctx.getBean(B.class);
}

5、Injecting Dependencies on Imported @Bean Definitions(对导入的 @Bean 定义注入依赖)

The preceding example works but is simplistic. In most practical scenarios, beans have dependencies on one another across configuration classes. When using XML, this is not an issue, because no compiler is involved, and you can declare ref=“someBean” and trust Spring to work it out during container initialization. When using @Configuration classes, the Java compiler places constraints on the configuration model, in that references to other beans must be valid Java syntax.Fortunately, solving this problem is simple. As we already discussed, a @Bean method can have an arbitrary number of parameters that describe the bean dependencies. Consider the following more real-world scenario with several @Configuration classes, each depending on beans declared in the others:

前边的例子有效但是非常简单,在大部分实际的场景中,bean拥有跨配置类的依赖。使用XML配置的时候,这不是一个问题,因为不涉及编译器,只需要声明ref=“someBean”,其他的spring在初始化容器时会处理好。当使用@Configuration配置类时,java编译器对配置类有一些限制,引用其他类必须符合java语法。幸运的是,解决该问题很简单,正如我们已经讨论的,一个@Bean标注的方法可以有任意个参数用来描述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");
}

也就是说只要保证各个配置类中的bean能被加载到容器,就能解决跨配置类的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. The following example shows how to do so:

如果这种含糊不清的注入是不可接受的,并且你希望在 IDE 中从一个 @Configuration 类直接导航到另一个,可以考虑通过配置类本身进行注入,如下所示:

@Configuration
public class ServiceConfig {

    @Autowired
    private RepositoryConfig repositoryConfig;

    @Bean
    public TransferService transferService() {
        // navigate 'through' the config class to the @Bean method!
        return new TransferServiceImpl(repositoryConfig.accountRepository());
    }
}

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

在前面的例子中,AccountRepository被明确指明。然而,ServiceConfig现在紧密耦合了RepositoryConfig,这是一个需要权衡的地方。可以通过使用接口配置类或抽象类的配置来消除这种耦合,参考以下例子:

@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: You can easily 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 类及其依赖项与导航基于接口的代码的通常过程没有什么不同。

6、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.The @Profile annotation is actually implemented by 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.Implementations of the Condition interface provide a matches(…​) method that returns true or false. For example, the following listing shows the actual Condition implementation used for @Profile:

基于一些任意的系统状态有条件地启用或禁用完整的 @Configuration 类甚至单个 @Bean 方法通常很有用。一个常见的例子是,只有在 Spring Environment 中启用了特定配置文件时,才激活使用 @Profile 注解限定的bean。@Profile 注解实际上是通过使用一个更灵活的注解@Conditional 来实现的。@Conditional 注解指明在注册 @Bean 之前应该咨询的特定 org.springframework.context.annotation.Condition 实现。Condition 接口的实现提供了一个matches(… ) 方法,该方法返回true 或false。例如,以下清单显示了用于 @Profile 的实际 Condition 实现:

@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    // Read the @Profile annotation attributes
    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;
}

7、@Configuration Class-centric Use of XML with @ImportResource( 以@Configuration类为主要配置, XML 为次要配置的 @ImportResource 的使用)

In applications where @Configuration classes are the primary mechanism for configuring the container, it is still likely necessary to use at least some XML. In these scenarios, you can use @ImportResource and define only as much XML as you need. Doing so achieves a “Java-centric” approach to configuring the container and keeps XML to a bare minimum. The following example (which includes a configuration class, an XML file that defines a bean, a properties file, and the main class) shows how to use the @ImportResource annotation to achieve “Java-centric” configuration that uses XML as needed:

在@Configuration 类是配置容器主要机制的应用程序中,仍然可能需要至少使用一些 XML。在这些场景中,您可以使用 @ImportResource 并根据需要定义随意多的 XML。这样做可以实现“以 Java 为中心”的方法来配置容器并将 XML 保持在最低限度。下面的示例(包括一个配置类、一个定义 bean 的 XML 文件、一个属性文件和主类)展示了如何使用 @ImportResource 注释来实现根据需要使用 XML 的“以 Java 为中心”的配置:

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

你可能感兴趣的:(spring,java)