文章目錄
本篇博客僅記錄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》作者:楊開振