Spring 註解編程IOC

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來支持是否必須要進行依賴注入。根據以下規則進行查找進行注入

  1. 根據類型查找,只查詢一個直接返回
  2. 根據名稱查找
<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>

常見問題

生命週期執行方法順序

答:初始化方法執行順序

  1. @PostConstruct
  2. 實現InitializingBean接口的方法
  3. @Bean指定initMethod

銷燬方法執行順序

  1. @PreDestroy
  2. 實現DisposableBean接口的方法
  3. @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/


分享到:


相關文章: