spring ioc

188 阅读5分钟

ioc (控制反转),用来管理所有对象及其依赖关系,利用Java的反射来实例化bean和建立bean之间的关系,还提供bean实例缓存,生命周期管理等等服务。

依赖注入:setter注入,构造函数注入。

手动注入:

setter注入:被注入的对象必须有set函数,支持简单类型和引用类型,是在bean实例化后注入。

构造函数注入:spring会根据参数去寻找对应的构造函数,构造函数有多个参数时,对于<constructor-arg>标签来讲,他们的注入顺序并不重要(在xml中写的前后顺序),

特殊情况:当类中有两个构造函数参数类型和个数都一样,只是顺序不一样,这在类的定义中是允许的,但是spring容器在寻找的过程中就会出现不知道调用那个构造参数的情况,就需要加上index参数给<constructor-arg>。          循环依赖,当在构造函数中出现A类中依赖于B类,同时B类也依赖于A类,那么在A类被创建的时候,B类还没有创建好(反之也是),spring容器就会抛出异常。

自动注入:

在xml上的bean节点上配置autowire,bytype需要配合set函数一起使用,spring会通过反射去查找bean相同的类型注入,当出现同名bean的时候,使用autowire-candidate过滤。byname寻找同名的注入,没有找到相同的bean,就为null,byconstructor,和构造器注入一样,当只有一个实例bean时,按照类型来注入,当出现多个不同名同类项的bean时,按照名称来注入。否则使用标签来过滤。

使用注解@Autowired&@Resource&@Value,@Autowrite默认按照类型注入,如需要按名称配合@Quafiler使用,@Resource有两个属性name和type可以指定,默认name,@value可以注入基本数据类型和文件中的变量。


beanfactory:

beanfactory是面向spring

通过 BeanFactory 装载配置文件,启动 Spring IoC 容器:

public class BeanFactoryTest { 
    public static void main(String[] args) throws Throwable{
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        Resource res = resolver.getResource("classpath:com/baobaotao/beanfactory/beans.xml"); 
        BeanFactory bf = new XmlBeanFactory(res);
        System.out.println("init BeanFactory.");
        Car car = bf.getBean("car",Car.class);
        System.out.println("car bean is ready for use!");
}


ApplicationContext

ApplicationContext 由 BeanFactory 派生而来,提供了更多面向实际应用的功能。

在BeanFactory 中,很多功能需要以编程的方式实现,而在 ApplicationContext 中则可以通过配置的方式实现。

  • ClassPathXmlApplicationContext:默认从类路径加载配置文件
  • FileSystemXmlApplicationContext:默认从文件系统中装载配置文件

WebApplicationContext 

是专门为 Web 应用准备的,它允许从相对于 Web 根目录的路径中装载配置文件完成初始化工作。从WebApplicationContext 中可以获得 ServletContext 的引用,整个 Web 应用上下文对象将作为属性放置到 ServletContext 中,以便 Web 应用环境可以访问 Spring 应用上下文。 WebApplicationContext 定义了一个常量ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,在上下文启动时, WebApplicationContext 实例即以此为键放置在 ServletContext 的属性列表中,因此我们可以直接通过以下语句从 Web 容器中获取WebApplicationContext:


bean的生命周期


IOC容器工作机制

容器启动过程

web环境下Spring容器、SpringMVC容器启动过程:

  1. 首先,对于一个web应用,其部署在web容器中,web容器提供其一个全局的上下文环境,这个上下文就是ServletContext,其为后面的spring IoC容器提供宿主环境;
  2. 其次,在web.xml中会提供有contextLoaderListener(或ContextLoaderServlet)。在web容器启动时,会触发容器初始化事件,此时contextLoaderListener会监听到这个事件,其contextInitialized方法会被调用,在这个方法中,spring会初始化一个启动上下文,这个上下文被称为根上下文,即WebApplicationContext,这是一个接口类,确切的说,其实际的实现类是XmlWebApplicationContext。这个就是spring的IoC容器,其对应的Bean定义的配置由web.xml中的context-param标签指定。在这个IoC容器初始化完毕后,spring容器以WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE为属性Key,将其存储到ServletContext中,便于获取;
  3. 再次,contextLoaderListener监听器初始化完毕后,开始初始化web.xml中配置的Servlet,这个servlet可以配置多个,以最常见的DispatcherServlet为例(Spring MVC),这个servlet实际上是一个标准的前端控制器,用以转发、匹配、处理每个servlet请求。DispatcherServlet上下文在初始化的时候会建立自己的IoC上下文容器,用以持有spring mvc相关的bean,这个servlet自己持有的上下文默认实现类也是XmlWebApplicationContext。在建立DispatcherServlet自己的IoC上下文时,会利用WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE先从ServletContext中获取之前的根上下文(即WebApplicationContext)作为自己上下文的parent上下文(即第2步中初始化的XmlWebApplicationContext作为自己的父容器)。有了这个parent上下文之后,再初始化自己持有的上下文(这个DispatcherServlet初始化自己上下文的工作在其initStrategies方法中可以看到,大概的工作就是初始化处理器映射、视图解析等)。初始化完毕后,spring以与servlet的名字相关(此处不是简单的以servlet名为Key,而是通过一些转换)的属性为属性Key,也将其存到ServletContext中,以便后续使用。这样每个servlet就持有自己的上下文,即拥有自己独立的bean空间,同时各个servlet共享相同的bean,即根上下文定义的那些bean。

总结

  • Spring IOC容器主要有继承体系底层的BeanFactory、高层的ApplicationContext和WebApplicationContext
  • Bean有自己的生命周期
  • 容器启动原理:Spring应用的IOC容器通过tomcat的Servlet或Listener监听启动加载;Spring MVC的容器由DispatchServlet作为入口加载;Spring容器是Spring MVC容器的父容器
  • 容器加载Bean原理:
  1. BeanDefinitionReader读取Resource所指向的配置文件资源,然后解析配置文件。配置文件中每一个<bean>解析成一个BeanDefinition对象,并保存到BeanDefinitionRegistry中;
  2. 容器扫描BeanDefinitionRegistry中的BeanDefinition;调用InstantiationStrategy进行Bean实例化的工作;使用BeanWrapper完成Bean属性的设置工作;
  3. 单例Bean缓存池:Spring 在 DefaultSingletonBeanRegistry 类中提供了一个用于缓存单实例 Bean 的缓存器,它是一个用 HashMap 实现的缓存器,单实例的 Bean 以 beanName 为键保存在这个HashMap 中。