Bean 註冊
註冊Bean的常用註解有@Component、@Service、@Controller、@Repository,通過掃描包的方式對這些註解進行解析註冊Bean。
註解ApplicationContext:AnnotationConfigApplicationContext
常用註解
@Configuration
聲明Bean Difinition的配置文件,相當於一個xml文件
@Bean
<code>@Configuration
public class CustomConfig {
@Bean
public Person person() {
return new Person();
}
}
/<code>
相當於xml bean內容
<code><beans>
<bean>
/<beans>
/<code>
bean的名稱默認為方法名稱,也可以通過@Bean(value="person")或者@Bean("person")進行指定
@ComponentScan
指定掃描路徑
<code>@Configuration
@ComponentScan("top.felixfly.spring.annotation")
public class ScanConfiguration {
}
/<code>
相當於xml component-scan
<code><beans>
<component-scan>
/<beans>
/<code>
@ComponentScans
多個掃描路徑,值為ComponentScan的數組,1.8以後可以用多個@ComponentScan代替此註解
@Scope
指定Bean的作用域,默認為singleton
- singleton org.springframework.beans.factory.config.ConfigurableBeanFactory#SCOPE_SINGLETON
- prototype org.springframework.beans.factory.config.ConfigurableBeanFactory#SCOPE_PROTOTYPE
- request org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST
- session org.springframework.web.context.WebApplicationContext#SCOPE_SESSION
<code>@Configuration
public class CustomConfig {
@Bean
@Scope("singleton")
public Person person() {
return new Person();
}
}
/<code>
相當於xml中bean中scope屬性
<code><beans>
<bean>
/<beans>
/<code>
@Lazy
懶加載,針對singleton Bean進行懶加載,默認情況下單實例Bean直接加載
<code>@Configuration
public class CustomConfig {
@Bean
@Lazy
public Person person() {
return new Person();
}
}
/<code>
相當於xml中bean的lazy-init屬性
<code><beans>
<bean>
/<beans>
/<code>
@DependsOn
依賴關係註解
<code>@Configuration
public class CustomConfig {
@Bean
@DependsOn("person")
public Manager manager(){
return new Manager();
}
@Bean
public Person person(){
return new Person();
}
}
/<code>
相當於xml中bean的depends-on屬性
<code><beans>
<bean>
/<beans>
/<code>
@Order
Bean的排序,或者說是優先級,兩個接口org.springframework.core.Ordered以及org.springframework.core.PriorityOrdered,主要使用優先級的內容
- org.springframework.beans.factory.config.BeanPostProcessor
- org.springframework.http.converter.HttpMessageConverter
@Conditional
條件裝配Bean
- 實現org.springframework.context.annotation.Condition接口public class CustomCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // true 進行裝配,false不進行裝配 return false; } }
- Bean上配置@Conditional(Condition.class)@Configuration public class CustomConfig { @Conditional(CustomCondition.class) @Bean public Person person() { return new Person(); } }
當matches方法返回true的時候進行註冊當前@Bean,否則不註冊。該註解也可以放到配置類上,matches方法返回true的時候進行註冊當前配置類,否側不註冊。
@Profile
環境註解,底層使用的是@Conditional
@Import
快捷註冊Bean,默認名稱為類的全路徑
- 直接導入類@Configuration @Import(Person.class) public class CustomConfig { }
- 導入實現org.springframework.context.annotation.ImportSelector類public class CustomImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { return new String[]{Person.class.getName()}; } } @Configuration @Import(CustomImportSelector.class) public class CustomConfig { }
- 導入實現org.springframework.context.annotation.ImportBeanDefinitionRegistrar類public class CustomImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) { // 自行註冊BeanDefinition RootBeanDefinition beanDefinition = new RootBeanDefinition(Person.class); registry.registerBeanDefinition("person",beanDefinition); } } @Configuration @Import(CustomImportBeanDefinitionRegistrar.class) public class CustomConfig { }
@ImportResource
導入資源xml文件
資源文件名稱spring/application-spring.xml
<code><beans>
<bean>
<constructor-arg>
<constructor-arg>
/<bean>
/<beans>
/<code>
<code>@Configuration
@ImportResource("classpath:/spring/application-spring.xml")
public class CustomConfig {
}
/<code>
常見問題
@Configuration、其他註解與@Bean結合使用有什麼不同
答:@Configuration註解使用的其實也是一個Bean,但本身是BeanFatory,是經過CGLIB進行增強的Bean,其他註解(@Component、@Service、@Controller、@Repository)使用的就是一個簡單的Bean
Bean 依賴注入
常用註解
@Autowired
Spring自帶的自動注入,註解的屬性required來支持是否必須要進行依賴注入。根據以下規則進行查找進行注入
- 根據類型查找,只查詢一個直接返回
- 根據名稱查找
<code>@Service
public class PersonService {
@Autowired
private PersonMapper personMapper;
}
/<code>
可以結合以下註解進行使用
- @Qualifier指定名稱進行依賴注入@Service public class PersonService { @Autowired @Qualifier("personMapper") private PersonMapper personMapper; }
- @Primary指定優先進行依賴注入@Service public class PersonService { @Autowired private PersonMapper personMapper; } @Configuration @ComponentScan({"top.felixfly.spring.annotation.mapper","top.felixfly.spring.annotation.service"}) public class CustomConfig { // 優先注入 @Bean("personMapper2") @Primary public PersonMapper personMapper(){ return new PersonMapper(); } }
只有一個有參構造器時,@Autowired可以省略,可以自動進行注入
@Resource
Java規範(JSR250)的註解,默認按照屬性的名稱進行依賴查找匹配,也可以用屬性name進行強制指定,但不支持與@Primary註解結合使用和required是否必須要進行依賴注入
<code>@Service
public class PersonService {
@Resource
private PersonMapper personMapper;
}
@Service
public class PersonService {
\t// 強制指定Bean
@Resource(name="personMapper2")
private PersonMapper personMapper;
}
/<code>
@Inject
Java規範的註解(JSR330),功能與@Autowired一樣,但不支持required是否必須要進行依賴注入。需要引入javax.inject
<code><dependency>
<groupid>javax.inject/<groupid>
<artifactid>javax.inject/<artifactid>
<version>1/<version>
/<dependency>
/<code>
<code>@Service
public class PersonService {
@Inject
private PersonMapper personMapper;
}
/<code>
注入方式
構造器注入
<code>@Configuration
public class AppConfig {
@Bean
public BeanOne beanOne() {
// 構造器注入
return new BeanOne(beanTwo());
}
@Bean
public BeanOne beanThree(BeanTwo beanTwo) {
// 構造器注入
return new BeanOne(beanTwo);
}
@Bean
public BeanTwo beanTwo() {
return new BeanTwo();
}
}
/<code>
Setter方法注入
<code>public class BeanTwo {
@Autowired
public void setBeanOne(BeanOne beanOne) {
this.beanOne = beanOne;
}
}
/<code>
Aware接口
自定義組件注入Spring底層的組件,比如ApplicationContext,這些Aware接口一般通過Processor進行處理。ApplicationContextAwareProcessor處理EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware
ApplicationContextAwareApplicationContextApplicationEventPublisherAwareApplicationContext事件發佈器BeanClassLoaderAware類加載器BeanFactoryAwareBean 工廠BeanNameAwareBean 名稱BootstrapContextAwareBootstrapContextMessageSourceAware國際化管理NotificationPublisherAwareSpring JMX通知發佈器ResourceLoaderAware資源加載器EmbeddedValueResolverAware@Value解析器EnvironmentAware環境變量
常見問題
循環依賴的問題
答:循環依賴的產生,BeanA依賴BeanB,BeanB依賴BeanC,而BeanC又依賴於BeanA,這時候就會產生循環依賴的問題,單例Bean中通過構造器注入會產生循環依賴的問題,會產生BeanCurrentlyInCreationException,通過Setter方法注入不會產生異常,可以解決循環依賴問題。原型@Bean通過Setter方法注入依然會產生BeanCurrentlyInCreationException,沒辦法解決循環依賴問題。
Bean 生命週期
Bean的生命週期包含實例化–>初始化–>銷燬,單實例Bean實例化在容器創建的時候進行實例化以及初始化,銷燬在容器關閉的時候進行調用;多實例Bean在獲取Bean的時候進行實例化以及初始化,銷燬需要自行進行調用。
初始化和銷燬常用方法
- @Bean指定initMethod和destroyMethod@Configuration public class CustomConfig { @Bean(initMethod = "init",destroyMethod = "destroy") public Person person(){ return new Person(); } } 相當於xml中配置init-method和destroy-method屬性<beans> <bean> /<beans>
- 實現InitializingBean和DisposableBeanpublic class Person implements InitializingBean, DisposableBean { public Person() { } @Override public void afterPropertiesSet () throws Exception { } @Override public void destroy() throws Exception { } }
- 使用@PostConstruct和@PreDestroy註解使用InitDestroyAnnotationBeanPostProcessor進行解析處理,父類CommonAnnotationBeanPostProcessorpublic class Person { public Person() { } @PostConstruct public void postConstruct(){ } @PreDestroy public void preDestroy(){ } }
BeanPostProcessor
- postProcessBeforeInitialization 初始化之前執行方法
- postProcessAfterInitialization 初始化之後執行方法
<code>public class CustomBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
/<code>
<code>@Configuration
@Import(CustomBeanPostProcessor.class)
public class CustomConfig {
@Bean
public Person person(){
return new Person();
}
}
/<code>
執行方法若是返回null值,後續的BeanPostProcessor不會進行執行,源代碼執行如下:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory
<code>@Override
\tpublic Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
\t\t\tthrows BeansException {
\t\tObject result = existingBean;
\t\tfor (BeanPostProcessor processor : getBeanPostProcessors()) {
\t\t\tObject current = processor.postProcessBeforeInitialization(result, beanName);
\t\t\tif (current == null) {
\t\t\t\treturn result;
\t\t\t}
\t\t\tresult = current;
\t\t}
\t\treturn result;
\t}
\t@Override
\tpublic Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
\t\t\tthrows BeansException {
\t\tObject result = existingBean;
\t\tfor (BeanPostProcessor processor : getBeanPostProcessors()) {
\t\t\tObject current = processor.postProcessAfterInitialization(result, beanName);
\t\t\tif (current == null) {
\t\t\t\treturn result;
\t\t\t}
\t\t\tresult = current;
\t\t}
\t\treturn result;
\t}
/<code>
常見問題
生命週期執行方法順序
答:初始化方法執行順序
- @PostConstruct
- 實現InitializingBean接口的方法
- @Bean指定initMethod
銷燬方法執行順序
- @PreDestroy
- 實現DisposableBean接口的方法
- @Bean指定destroyMethod
Multiple lifecycle mechanisms configured for the same bean, with different initialization methods, are called as follows:
Methods annotated with @PostConstructafterPropertiesSet() as defined by the InitializingBean callback interfaceA custom configured init() method
Destroy methods are called in the same order:
Methods annotated with @PreDestroydestroy() as defined by the DisposableBean callback interfaceA custom configured destroy() method
資源屬性賦值
常用註解
@Value
屬性進行賦值,可以有如下三種寫法
- 直接賦值public class Person { @Value("張三") private String name; }
- SpEL表達式 #{}public class Person { @Value("#{20-2}") private String age; }
- ${} 文件屬性賦值(通常在環境變量Enviroment中),要配合@PropertySource使用public class Person { @Value("${person.age}") private String age; }
@PropertySource
引入配置文件,配置文件下根路徑下person.properties
<code>@PropertySource("classpath:/person.properties")
public class CustomConfig {
}
/<code>
相當於xml中的context:property-placeholder
<code><property-placeholder>
/<code>
@PropertySources
多個配置文件引入,值為PropertySource的數組,1.8以後可以用多個@PropertySource代替此註解
常見問題
配置文件屬性亂碼
答:註解@PropertySource通過屬性encoding進行配置文件編碼,該配置在4.3版本引入;xml配置文件中通過屬性file-encoding配置文件編碼
粉絲福利:
為粉絲講解福利資源:特講解教程教你如何學習 ,源碼、分佈式、微服務、性能優化、多線程併發,從0到1, 帶你領略底層精髓。
詳情點擊鏈接:https://shimo.im/docs/VqQR6tPrpR3C3tjq/
閱讀更多 Java高級架構 的文章