Spring学习笔记8_基于java的容器配置(Java-based Container Configuration)

文章参考来源:Spring Framework官方文档

本节介绍如何在Java代码中使用注释来配置Spring容器。它包括以下主题:

  • AnnotationConfigApplicationContext——实例化Spring容器
  • @Bean
  • @Configuration
  • 编写基于java的配置

1. AnnotationConfigApplicationContext

Spring 3.0中开始引入的AnnotationConfigApplicationContext,这个通用的ApplicationContext实现不仅能够接受@Configuration类作为输入,还能够接受普通的@Component类和用JSR-330元数据注释的类。
(1)当接受@Configuration类作为输入去实例化容器时:

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
    MyService myService = ctx.getBean(MyService.class);
    myService.doStuff();
}
@Configuration
@ComponentScan(basePackages = "com.acme") 
public class AppConfig  {
    // ...
}

(2)同样,也可以接受@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();
}

在初始化AnnotationConfigApplicationContext时,甚至可以使用它的无参构造方法,然后调用register()方法进行配置,用scan(…​)进行包扫描。

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

2. @Bean

@Bean注解作用于:对方法实例化、配置和初始化新对象,而这些对象会被Spring IoC容器管理。对于那些熟悉Spring的 XML配置的人来说,@Bean注释扮演着与< beans />相同的角色。可以在任何Spring 的@Component中使用@ bean注解。不过,@Bean最常与@Configuration一起使用。
一个@Bean和@Configuration同使用的例子:

@Configuration
public class AppConfig {

	/**默认情况下,该bean的id名称为:transferService(方法名),返回值为:TransferServiceImpl
	不过也可以自定义名称,比如自定义为:myTransferService*/
   // @Bean("myTransferService")
    @Bean
    public TransferServiceImpl transferService() {
        return new TransferServiceImpl();
    }
}

等效于:

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

@ bean注释的方法甚至可以有任意数量的参数,用于描述构建该bean所需的依赖项。比如transferService依赖AccountRepository ,如下:

@Configuration
public class AppConfig {

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

Spring默认bean作用域为单例,但是也可以覆盖自定义,如下:

@Configuration
public class MyConfiguration {

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

在bean命名上,也允许多个别名存在:

@Configuration
public class AppConfig {

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

bean允许添加描述:

@Configuration
public class AppConfig {

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

3. @Configuration

用@Configuration注释表明它的主要用途是作为bean定义的。此外,@Configuration类允许通过调用同一类中的其他@Bean方法来定义bean间的依赖关系。最简单的@Configuration类如下所示:

@Configuration
public class AppConfig {

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

上述等价于XML的配置如下:

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

所有的@Configuration类在启动时都是用CGLIB子类化的。
CGLIB在启动时会动态地添加特性,因此对于非final的配置类存在一些限制。然而,从4.3开始,配置类上允许使用任何构造函数,包括使用@Autowired或单个非默认构造函数声明来进行默认注入。

如果想避免cglib进行强加的限制,可以考虑在non-@Configuration类上声明@Bean方法(例如,在普通的@Component类上声明)。然后@Bean方法之间的跨方法调用不会被拦截,因此必须在构造函数或方法级别上完全依赖依赖注入。

4. 编写基于java的配置

(1)@Import注解的使用
@Import可以将其他配置加载到当前配置类中,比如:


@Configuration
public class ConfigA {

    @Bean
    public A a() {
        return new A();
    }
}
//配置类A被加载到配置B中
@Configuration
@Import(ConfigA.class)
public class ConfigB {

    @Bean
    public B b() {
        return new B();
    }
}

容器实例化时,只加载配置B,就可以使用Bean A和Bean B:简化了配置加载

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

一个稍微复杂点的例子(涉及跨配置类的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");
}

被@Configuration标注的配置类也只是容器中的一个bean,这也就意味着其他Bean能用的@Autowired 和@Value,@Configuration标注类也可以使用/被使用。

@Configuration
public class ServiceConfig {

	//@Configuration标注类被@Autowired“使用”,同时ServiceConfig是一个@Configuration标注类,它使用到了“@Autowired”
    @Autowired
    private RepositoryConfig repositoryConfig;

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

@Configuration
public class RepositoryConfig {

    private final DataSource dataSource;

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

即使@Configuration类是配置容器的主要机制,但或多或少还是会使用到一些XML配置文件。注解@ImportResource的使用,可以将XML配置文件纳入到容器实例化过程中。下面给的就是一个使用到:@Configuration配置类,@ImportResource注解将XML引入配置类的例子:
@Configuration配置类

@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.properties
jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
jdbc.username=sa
jdbc.password=

启动main方法:

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
    TransferService transferService = ctx.getBean(TransferService.class);
    // ...
}

你可能感兴趣的:(Spring学习笔记,spring,java,后端)