文章目录
- @ComponentScan
- @Autowired
- Bean生命周期
- 使用属性文件
- @Value
- @ConfigurationProperties
- @PropertySource
- 条件装配Bean
- 引入XML配置Bean(@ImportResource)
本篇博客仅记录Spring Boot中一些需要特殊注意的点,更多详细的Bean装配相关内容,可见本人之前博客:
Spring高级装配
@ComponentScan
- Boolean lazyInit
默认为false,此时在Spring IOC容器初始化时,Bean就会执行实例化和依赖注入。若设置为true,则不会,只有在 - Filter[] includeFilters
Filter[] excludeFilters
上述两个属性用于限定当满足/不满足过滤器的条件时扫描
其限制条件设置依赖内部注解 @Filter 定义:
- 过滤器类型,可以按注解类型或正则式等过滤 FilterType type
- 定义过滤的类 Class<?>[] value/classes
- 匹配方式 String[] pattrn
使用方式如下:
@ComponentScan(includeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {"com.springboot.practice.demo.test.class"}, pat)})
@SpringBootApplication
中包含@Component,其包含四个属性:
- exclude:通过类型排除自动配置类
- excludeName:通过命名排除自动配置类
- scanBasePackages:定义扫描包
- ScanBasePackageClasses:定义被扫描的类
@Autowired
- 先通过类型去查找匹配bean;
- 类型匹配不唯一会去根据名称匹配;
Bean生命周期
- Bean定义
- Bean初始化
- Bean生存期
- Bean销毁
整个Bean生命周期所涉及的流程:
下述样例可以测试Bean的生命周期:
- 定义一个Bean,涉及到上图中setBeanName、setBeanFactory、setApplicationContext、自定义初始化、afterPropertiesSet、自定义销毁、destroy过程
@Component
public class MyBean implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("【" + this.getClass().getSimpleName() + "】调用BeanFactoryAware的setBeanFactory");
}
@Override
public void destroy() throws Exception {
System.out.println("【" + this.getClass().getSimpleName() + "】DisposableBean方法");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("【" + this.getClass().getSimpleName() + "】调用InitializingBean的afterPropertiesSet");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("【" + this.getClass().getSimpleName() + "】调用ApplicationContextAware的setApplicationContext");
}
@Override
public void setBeanName(String name) {
System.out.println("【" + this.getClass().getSimpleName() + "】调用BeanNameAware的setBeanName");
}
@PostConstruct
public void init(){
System.out.println("【" + this.getClass().getSimpleName() + "】注解@PostConstruct定义的自定义初始化方法");
}
@PreDestroy
public void destroy1(){
System.out.println("【" + this.getClass().getSimpleName() + "】注解@PreDestroy定义的自定义销毁方法");
}
}
- 定义一个处理类,涉及上图中postProcessBeforeInitialization(预初始化)、postProcessAfterInitialization(后初始化)过程。
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor调用postProcessBeforeInitialization方法,参数【" + bean.getClass().getSimpleName() + "】【" + beanName + "】");
return bean;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor调用postProcessAfterInitialization方法,参数【" + bean.getClass().getSimpleName() + "】【" + beanName + "】");
return bean;
}
}
- 运行结果如下
BeanPostProcessor调用postProcessAfterInitialization方法,参数【ServletWebServerFactoryConfiguration$EmbeddedTomcat$$EnhancerBySpringCGLIB$$4506f63e】【org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat】
BeanPostProcessor调用postProcessBeforeInitialization方法,参数【ServletWebServerFactoryConfiguration$EmbeddedTomcat$$EnhancerBySpringCGLIB$$4506f63e】【org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat】
BeanPostProcessor调用postProcessAfterInitialization方法,参数【TomcatServletWebServerFactory】【tomcatServletWebServerFactory】
...
省略部分其它Bean的预初始化和后初始化日志。
BeanPostProcessor调用postProcessAfterInitialization方法,参数【BaseConfig$$EnhancerBySpringCGLIB$$ec4dd4fe】【baseConfig】
BeanPostProcessor调用postProcessBeforeInitialization方法,参数【BaseConfig$$EnhancerBySpringCGLIB$$ec4dd4fe】【baseConfig】
【MyBean】调用BeanNameAware的setBeanName
【MyBean】调用BeanFactoryAware的setBeanFactory
【MyBean】调用ApplicationContextAware的setApplicationContext
BeanPostProcessor调用postProcessAfterInitialization方法,参数【MyBean】【myBean】
【MyBean】注解@PostConstruct定义的自定义初始化方法
【MyBean】调用InitializingBean的afterPropertiesSet
BeanPostProcessor调用postProcessBeforeInitialization方法,参数【MyBean】【myBean】
BeanPostProcessor调用postProcessAfterInitialization方法,参数【WebConfig$$EnhancerBySpringCGLIB$$b79cfd7d】【webConfig】
BeanPostProcessor调用postProcessBeforeInitialization方法,参数【WebConfig$$EnhancerBySpringCGLIB$$b79cfd7d】【webConfig】
【MyBean】注解@PreDestroy定义的自定义销毁方法
【MyBean】DisposableBean方法
从上述日志可以看出:
1)后置处理器(BeanPostProcess)对所有Bean生效;
2)在容器初始化过程中,会按照上面流程图中的顺序,依次调用各方法。
⚠️:若Bean的定义是第三方类,使用@Bean属性来自定义初始化和销毁方法:@Bean(initMethod = "init", destroyMethod = "destroy")
使用属性文件
读取属性配置上下文所需的maven依赖
<dependency> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration- processor</artifactId>
<optional>true</optional>
</dependency>
有了依赖,就可以引用application.properties文件中配置的属性了,有以下两种方式:
@Value
使用${}
占位符读取配置在属性文件的内容
@ConfigurationProperties
此方式可以减少一些配置代码:
- application.properties中配置
# custom properties
myproperties.name=yanzy
myproperties.text=testProperties
- model类匹配属性配置
@Component
@ConfigurationProperties("myproperties")
public class MyProperties {
private String name;
private String text;
省略setter/getter方法
}
- 引用配置属性
@Autowired
MyProperties myProperties;
@RestController
public class BaseController {
@Autowired
MyProperties myProperties;
@GetMapping("/properties")
public void getConfigProperties(){
System.out.println(String.format("------------- Name: %s, Text: %s ---------------", myProperties.getName(), myProperties.getText()));
}
}
- 调用结果:
------------- Name: yanzy, Text: testProperties ---------------
上述样例可见,Spring将根据注解中配置属性和POJO属性名称组成全限定名去配置文件中查找,并读取到POJO中。
@PropertySource
使用@PropertySource
可以指定要读取的属性文件。
- 自定义配置文件myProperties.properties:
specified.myproperties.name=Syanzy
specified.myproperties.text=specifiedMyProperties
- model类匹配属性配置
@PropertySource(value = "classpath:myProperties.properties", ignoreResourceNotFound = true)
@Component
@ConfigurationProperties("specified.myproperties")
public class SpecifiedMyProperties {
private String name;
private String text;
省略setter/getter方法
}
- 引用配置属性
@Autowired
SpecifiedMyProperties specifiedMyProperties;
@GetMapping("/specified/properties")
public void getSpecifiedConfigProperties(){
System.out.println(String.format("------------- Name: %s, Text: %s ---------------", specifiedMyProperties.getName(), specifiedMyProperties.getText()));
}
- 调用结果
------------- Name: Syanzy, Text: specifiedMyProperties ---------------
上述样例可以看出,引用自定义的属性文件成功了。
条件装配Bean
在上面关于@ConfigurationProperties的样例中,将model类修改如下:
@Component
@ConfigurationProperties("myproperties")
@Conditional(MyPropertiesCondition.class)
public class MyProperties {
private String name;
private String text;
省略setter/getter方法
}
添加@Conditional
注解,并指定条件类MyPropertiesCondition
,其内容如下:
public class MyPropertiesCondition implements Condition {
/**
*
* @param context 条件上下文
* @param metadata 注释类型的元数据
* @return true装配bean,否则不装配
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 取出环境配置
Environment env = context.getEnvironment();
// 判断属性文件是否存在对应的数据配置
return env.containsProperty("myproperties.open");
}
}
使用了此限定条件,在我们的myProperties.properties文件中未配置myproperties.open时,会出现如下错误:
Description:
Field myProperties in com.springboot.practice.demo.Controller.BaseController required a bean of type 'com.springboot.practice.demo.model.MyProperties' that could not be found.
说明此时MyProperties这个Bean未加载。
引入XML配置Bean(@ImportResource)
- 要声明为Bean的类
public class XmlConfigClass {
public void description(){
System.out.println(String.format("----------------- %s------------------", "this is a xml config bean"));
}
}
- xml配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="xmlConfigClass" class="com.springboot.practice.demo.model.XmlConfigClass"/>
</beans>
- 引入xml配置
@Configuration
@ComponentScan
@ImportResource(value = {"classpath:xmlProperties.xml"})
public class BaseConfig {
}
此处@ImportResource
注解的value属性指定了要引入的xml配置文件,其位置在resource目录下。
- 注入Bean
@Autowired
XmlConfigClass xmlConfigClass;
@GetMapping("/xml")
public void getXmlConfigBean(){
xmlConfigClass.description();
}
- 调用结果
----------------- this is a xml config bean------------------
参考书籍:《深入浅出Spring Boot2.x》作者:杨开振