Spring 容器、Bean與生命週期

Spring 容器、Bean與生命週期

簡介

Spring最重要的部分之一就是提供了IoC容器,爲何須要IoC容器呢?IoC是依賴倒置,或者說是控制反轉的意思,控制反轉這個詞也許咱們耳朵已經聽出繭子了,也正是由於如此,也阻礙了咱們從新思考這個詞。java

如今,咱們從新思考一下什麼是"控制反轉"?咱們不下定義,咱們就結合業務場景來思考,例如,咱們的web應用,在Controller層會依賴Service層的邏輯,不一樣的Controller可能會依賴相同的service層對象。例如,庫存和積分的Controller都會依賴用戶的Service。web

若是沒有Spring,咱們常見的作法是在每個Controller中都建立用戶的Service,這些建立邏輯可能比較複雜。spring

這樣帶來的問題就是,建立對象的邏輯分散的處處都是,每一地方都會建立新的對象。springboot

Spring怎麼解決這個問題的呢?使用IoC容器。依賴倒置提如今什麼地方?原來是Controller依賴Service,如今不依賴了麼?不是,不過控制權轉移了,都是有Spring來管理,Spring建立對象,而後注入到須要的對象之中。mvc

這樣的好處是顯而易見的,建立邏輯都不用咱們管了,依賴對象也不用咱們關心了,不少對象能夠共享,不用重複建立、銷燬。app

Spring IoC容器建立流程

Spring工廠初始化

BeanDefinition

BeanDefinition

BeanDefinition解析

BeanDefinition解析有2個重要的接口,它們分別是BeanDefinitionReader和BeanDefinitionParser。ide

BeanDefinitionReader的做用是讀取bean的信息,例如,BeanDefinitionReader的間接實現類XmlBeanDefinitionReader就是從xml文件中讀取bean的信息。ui

讀取到bean信息了,還須要把這些信息解析爲BeanDefinition,這個過程是BeanDefinitionParser的職責,例如,AnnotationDrivenBeanDefinitionParser就是從註解中解析BeanDefinition。this

在實際的解析中可能具體的解析類是其餘的,例如XmlBeanDefinitionReader,實際註冊是利用BeanDefinitionDocumentReader接口的實現類DefaultBeanDefinitionDocumentReader。spa

DefaultBeanDefinitionDocumentReader實際上只處理了一些標籤,例如beans、alias、name、import、resource、profile等。

像常見的標籤bean、ref等標籤實際是BeanDefinitionParserDelegate處理的,BeanDefinitionParserDelegate也不會處理所有標籤。

BeanDefinitionParserDelegate會經過NamespaceHandler來處理一些自定義標籤,像下面的標籤都是經過對應的NamespaceHandler實現類來處理的。

<tx:annotation-driven/>
<tx:advice id="txAdvice" transaction-manager="myTracnsactionManager">
<aop:config>
<dubbo:reference id="xxxService" interface="xxx.XxxService"/>
<context:annotation-config />
<mvc:interceptors>

NamespaceHandler會經過NamespaceHandlerSupport來找到一個合適的BeanDefinitionParser,而後經過BeanDefinitionParser的parse方法來解析出對應的BeanDefinition。

Spring Bean建立

有了BeanDefinition,怎樣經過BeanDefinition建立真正的bean的呢?

bean建立

Spring生命週期

Spring鉤子

BeanFactoryPostProcessor

BeanPostProcessor

BeanFactoryAware

BeanNameAware

InitializingBean

DisposableBean

InstantiationAwareBeanPostProcessorAdapter

InstantiationAwareBeanPostProcessor

bean注入

@Resource

  1. 若是同時指定了name和type,則從Spring上下文中找到惟一匹配的bean進行裝配,找不到則拋出異常
  2. 若是指定了name,則從上下文中查找name匹配的bean進行裝配,找不到則拋出異常
  3. 若是指定了type,則從上下文中查找type匹配的惟一bean進行裝配,找不到或者找到多個,都會拋出異常
  4. 若是既沒有指定name也沒有指定type,那麼先按name方式,後安type方式,找不到則拋異常

@Autowired

按照類型匹配,默認必須找到,找不到就拋異常,若是不是必須,能夠設置require=false。這個和經過xml配置autowire屬性(也就是@Bean的autowire屬性。)差很少。

不過xml方式autowire必須有setter方法,而@Autowired能夠不用setter方法,而且@Autowired只有經過type注入,要經過name方式還得多加一個@Qualifier("name")註解。

@Autowired的註解處理器是AutowiredAnnotationBeanPostProcessor。

在AbstractAutowireCapableBeanFactory中有一個ignoreDependencyInterface方法,能夠設置不容許setter注入,這個主要是爲了不一些特殊的類被隨意注入了,例如ApplicationContext、BeanFactory等。這樣要獲取ApplicationContext必須實現ApplicationContextAware,而不只僅是在類中添加一個ApplicationContext屬性就能夠了。

數據類型轉換

最先的數據類型轉換是使用的PropertyEditor,支持的是String和Object之間的轉換,在Spring中主要用在2個地方。

  1. Spring xml bean配置屬性,從xml的property的字符串轉換爲對象
  2. Spring MVC中HTTP request請求參數字符串轉換爲對象

通常不會直接實現PropertyEditor接口,而是直接繼承PropertyEditorSupport類。

PropertyEditor是經過org.springframework.beans.factory.config.CustomEditorConfigurer註冊的。也能夠實現PropertyEditorRegistrar,而後將PropertyEditorRegistrar設置到CustomEditorConfigurer中。

注意PropertyEditorRegistry和PropertyEditorRegistrar,Registry是登記處,Registrar是以ar結尾,表示登記員的意思。因此顧名思義PropertyEditorRegistry是註冊PropertyEditor的地方,PropertyEditorRegistrar的做用是把PropertyEditor註冊到本身管理的PropertyEditorRegistry中。

PropertyEditor

Spring 3開始增長了一個Converter接口,能夠完成任意2個類型之間的轉換,這點比PropertyEditor強,PropertyEditor只能是String與Object之間的轉換。

Converter的通常玩法是,實現ConverterFactory接口,在實現類中給一個靜態內部類實現Converter。ConverterFactory的getConverter返回這個Converter就能夠了。

若是是更加複雜的轉換能夠考慮GenericConverter和ConditionalConverter接口。

ConversionService接口爲類型轉換提供統一轉換API來執行運行時的轉換邏輯,使用的是外觀模式(facade)。配置ConversionService只須要配置一個id爲conversionService的org.springframework.context.support.ConversionServiceFactoryBean就能夠了。自定義的Converter也能夠經過ConversionServiceFactoryBean設置。

org.springframework.format.Formatter接口和PropertyEditor接口差很少,不過結構更加清晰,PropertyEditor接口有不少GUI相關的方法,而Spring的Formatter接口,就是繼承了從類型T到String的Printer接口和從String到類型T的Parser接口。

註解驅動的Formatter能夠實現AnnotationFormatterFactory提供支持,Formatter也有registry和registrar,它們分別是FormatterRegistry和FormatterRegistrar。

Spring MVC的AnnotationDrivenBeanDefinitionParser中若是,若是包含「conversion-service」就會註冊一個FormattingConversionServiceFactoryBean,FormattingConversionServiceFactoryBean持有一個FormattingConversionService。

MVC數據轉換

mvc中的數據轉換是HttpInputMessage、HttpOutputMessage和Java數據類型之間的轉換,實現HttpMessageConverter接口就能夠了。

SpringMVC數據轉換

咱們知道MVC中有2個重要的接口一個是HandlerAdapter,另外一個是HandlerMapping。簡化點說HandlerMapping作的事情就是把請求URL找到對應的method來處理。HandlerAdapter看名字有點像適配器模式,實際上更像是代理模式。

HandlerAdapter的做用就是處理一些公共的邏輯,例如解析@RequestParam、@PathVariable、@RequestBody、@ResponseBody等註解...

想想HTTP協議或者直接經過Servlet處理須要處理的邏輯,再對比一下咱們使用@Controller和@RequestMapping註解以後的方法的邏輯,就知道HandlerAdapter作了多少事情了。正是由於如此、HandlerAdapter的能夠定製的程度也高。

如今spring mvc中默認使用的HandlerAdapter和HandlerMapping是: RequestMappingHandlerAdapter RequestMappingHandlerMapping 這2個類是在DispatcherServlet.properties配置的。

使用http://www.javashuo.com/tag/mvc:annotation-driven標籤,默認註冊的也是這2個類,前面已經介紹了這種標籤的解析,感興趣能夠本身查看一下MvcNamespaceHandler和AnnotationDrivenBeanDefinitionParser這2個類,NamespaceHandler是在META-INF的spring.handler中配置的,自定義NamespaceHandler的時候注意建立對應的xsd和spring.handler文件。

spring mvc中處理參數和返回值的主要接口和類:

HandlerMethodReturnValueHandlerComposite
HandlerMethodReturnValueHandler
HandlerMethodArgumentResolverComposite
HandlerMethodArgumentResolver

典型的組合模式,不過Composite中採用的不是遍歷,而是找到第一個支持的Handler來處理。 看RequestMappingHandlerAdapter源碼中有下面2個方法,用來初始化默認的HandlerMethodReturnValueHandler和HandlerMethodArgumentResolver。

RequestMappingHandlerAdapter#getDefaultArgumentResolvers
RequestMappingHandlerAdapter#getDefaultReturnValueHandlers

還有一個HttpMessageConverter集合,是用來給RequestResponseBodyMethodProcessor、RequestPartMethodArgumentResolver、HttpEntityMethodProcessor、ResponseBodyEmitterReturnValueHandler這幾個參數返回值處理器使用的。@ResponseBody和@RequestBody很是常見,通常咱們知道出問題是在什麼地方,可是當參數和返回值是HttpEntity的時候,也會使用到HttpMessageConverter,這個須要注意,例如,使用HttpEntity做爲返回值傳輸文件,就得看一下有沒有配置ByteArrayHttpMessageConverter這個轉換器。

其餘

FactoryBean 與 BeanFactory

BeanFactory,以Factory結尾,表示它是一個工廠類(接口),用於管理Bean的一個工廠。在Spring中,BeanFactory是IOC容器的核心接口,它的職責包括:實例化、定位、配置應用程序中的對象及創建這些對象間的依賴。

FactoryBean,以Bean結尾,表示它是一個Bean,不一樣於普通Bean的是它實現了FactoryBean<T>接口的Bean,根據該Bean的ID從BeanFactory中獲取的其實是FactoryBean的getObject()返回的對象,而不是FactoryBean自己,若是要獲取FactoryBean對象,請在id前面加一個&符號來獲取。

Environment

Environment主要是讀取系統變量和屬性,固然也會出來classpath或者指定路徑下的properties文件,主要涉及的類有:

  1. StandardServletEnvironment
  2. StandardEnvironment
  3. PropertyResolver
  4. PropertyPlaceholderHelper
  5. @PropertySource
  6. @TestPropertySource
  7. @ConfigurationProperties
@PropertySource({"classpath:base.properties"})
@Component
public class BaseBean {

    @Value("${host:127.0.0.1}")
    private String host;

    @Value("${base.host:127.0.0.1}")
    private String baseHost;

    @Value("#{'Hello World'.concat('!')}")
    private String helloWorld;

    @Value("#{'${base.server.name}'.split(',')}")
    private List<String> servers;

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public String getBaseHost() {
        return baseHost;
    }

    public void setBaseHost(String baseHost) {
        this.baseHost = baseHost;
    }

    public String getHelloWorld() {
        return helloWorld;
    }

    public void setHelloWorld(String helloWorld) {
        this.helloWorld = helloWorld;
    }

    public List<String> getServers() {
        return servers;
    }

    public void setServers(List<String> servers) {
        this.servers = servers;
    }

    @Override
    public String toString() {
        return "BaseBean{" +
                "host='" + host + '\'' +
                ", baseHost='" + baseHost + '\'' +
                ", helloWorld='" + helloWorld + '\'' +
                ", servers=" + servers +
                '}';
    }
}

@ConfigurationProperties是springboot的中的,不能和@Value同時使用,只須要使用一個就能夠了。

相關文章
相關標籤/搜索