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同时使用,只须要使用一个就能够了。

相关文章
相关标签/搜索