SpringBoot-Configuration
前面提到,对于Spring
项目来说,项目的功能取决于Spring容器
中有哪些bean
,每一个bean
都是一个功能模块的实例化对象。所以问题就来到了如何向Spring容器
中添加bean
。
XML 配置文件
XML配置文件
是最原始的添加bean
的方式。使用XML配置文件
符合了配置文件分离
的原则。可以通过修改XML配置文件
直接修改程序的功能,而不需要将项目重新编译。
在XML配置文件
中通过<bean>
标签来声明一个bean
,并指定其类名、属性、依赖关系等信息,将该bean
注册到Spring
容器中。
1 |
|
此处定义了一个bean
,为com.example.MyBean
类的实例对象,其标识符通过id
属性指定。通过<property>
标签,可以对其成员变量进行属性注入。对于基础数据类型,可以直接使用value
属性进行赋值;对于对象数据类型,可以使用ref
属性进行引用,属性值为另一个容器中bean
的id
。也可以通过设置bean
的autowire
属性来指定是否采用自动注入。例如可以指定autowire="byType"
来采用类型匹配自动注入。如果容器中符合成员变量类型的bean
只有一个,那么就可以自动赋值。
启动时,通过指定XML配置文件
,即可启动Spring容器
。
1 |
|
在定义bean
时,还有许多可配置属性。但作为便于理解的笔记,这部分内容此处不再深入,可以在需要的时候去查相关文档。
id
:指定 bean 的唯一标识符,用于在容器中进行引用。class
:指定 bean 的类名,用于实例化 bean 对象。scope
:指定 bean 的作用域,包括 singleton(单例,默认值)、prototype(原型)、request(请求)、session(会话)等。init-method
:指定 bean 初始化时调用的方法。destroy-method
:指定 bean 销毁时调用的方法。property
:用于设置 bean 的属性值。
其中可以指定bean
的初始化init-method
和销毁方法destroy-method
,这也是上篇提到的管理bean
生命周期的功能。
组件扫描
如果需要往容器中添加一百个bean
,那么需要在XML配置文件
中写一百个<bean>
标签,过程十分繁琐。实际项目中,需要添加到容器中的bean
往往是自己写的Java类
,这些Java类
在类路径
上通常有特点,例如处于某个包之下。指定某个类路径/包
下的所有Java类
都加入到Spring容器中
这个想法就十分自然。这种批量添加bean
的方式叫组件扫描。
XML配置文件
中开启组件扫描:
1 |
|
使用注解@ComponentScan
开启组件扫描:
1 |
|
组件扫描需要搭配@Component
使用,这是一个类注解。只有扫描路径下带有@Component
注解的类才会被添加到容器,没有的类则会被忽略。组件扫描@ComponentScan
和@Component
组合使用可以灵活地控制路径下哪些类会被添加入容器。
除了@Component
,还可以通过设置@ComponentScan
的includeFilters
和excludeFilters
属性,来灵活地自定义扫描路径下的过滤规则。
配置类@Configuration
Java
的注解特性太过便捷,Spring
项目逐渐从传统XML配置文件
方式向注解方式迁移,这种大量依赖注解来配置和管理Spring容器
中的Bean
的方式叫注解驱动
。
在注解驱动
下,一个XML配置文件
对应于一个带有@Configuration
注解的Java类
。XML配置文件
中所有的标签,都有对应的定义方式。其中最重要的<bean>
标签,在配置类中对应一个方法。这个方法会被添加@bean
注解,并且要求返回一个对象实例
或对象的工厂bean
。
1 |
|
需要一提的是,配置类本身也是一个bean
,存在于容器中。
基于单一职责原则,一般一个配置类往往只负责一类高度相关的功能。要开启某个功能往往就是把这个功能对应的配置类加入到容器中。配置类就会自动把功能相关的bean注册到容器中。
@ImportResource
实际项目开发中,可能会同时运用XML配置文件
和@Configuration配置类
。配置类
作为主流的导入bean
方式,那么就需要提供在其中引入XML配置文件
的方法。@ImportResource
就是这个作用。
1 |
|
在公司项目中,提供的对外Dubbo服务没有采用配置类
的方式,而是将其写在了XML配置文件
。通过在XML文件
引入xmlns:dubbo
,在文件内部可以使用dubbo提供的特定标签<dubbo:service>
来注册服务。然后通过@ImportResource("classpath:appCtx-dubbo.xml")
将生产者和消费者对应的bean
加入到容器中。
@Import
在Java配置类上使用@Import
注解,将其他Java配置类引入当前配置类中,从而将这些配置类中定义的Bean
一同注册到Spring容器
中。@Import
也能导入非配置类。
1 |
|
相较于@bean
的方式,@Import
要简单很多。由于@bean
注解在方法之上,可以通过编程式对每个bean
进行细粒度的配置,而@Import
就没法进行细粒度的控制。
@Import
通常也用于注解之上,使其变得更容易理解。例如@Import(AspectJAutoProxyRegistrar.class)
就是@EnableAspectJAutoProxy
上的注解。开启自动代理功能,本质就是导入了AspectJAutoProxyRegistrar.class
注册器。注册器中,通过重载了registerBeanDefinitions
的回调方法,向容器中动态注册了AnnotationAwareAspectJAutoProxyCreator
,从而开了AspectJ
代理功能。相较于@Import(AspectJAutoProxyRegistrar.class)
,@EnableAspectJAutoProxy
更具有语义化。实际上,大部分的@Enablexxx
本质都是利用了@Import
导入了一些特殊的bean
。
实现BeanFactoryPostProcessor接口
这种方式作为用户不常用。一般作为开发者设计第三方库时的选择。
通过自定义一个实现了BeanFactoryPostProcessor
接口的类,在其postProcessBeanFactory()
方法中使用BeanDefinitionRegistry
接口手动注册Bean到Spring容器中。例如:
1 |
|
实际上还有ImportBeanDefinitionRegistrar
。由于这部分内容找到的资料不多且良莠不齐,在此不深入讨论。
总的来说,这类方式是通过实现接口中预先定义的回调函数,在Spring容器
启动过程的早期阶段会调用这些函数。在这些函数中,可以获取到Spring容器
,并通过Spring容器
的注册方法向其中注册自定义bean
。
这部分内容令人感到困惑的原因是,Spring容器
本身有多个接口和实现类,其中有许多都提供了注册方法。
总结
Spring
应用的功能取决于其中的bean
。向容器中添加/注册bean
可以通过许多形式。其中最常用的是通过@Configuration
的方式自定义配置类。结合SpringBoot
的AutoConfiguration
,可以很容易将各种应用集成到Spring
中。由于AutoConfiguration
内容太复杂,限于篇幅放到下一篇。