Spring IOC

Posted 记录点点滴滴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring IOC相关的知识,希望对你有一定的参考价值。

1  什么是ioc:ioc就是将对象的创建及对象之间的关系交给容器管理

2 BeanFactory与ApplicationContext,及FactoryBean

     一般来说,我们称BeanFactory为ioc容器 而ApplicationContext成为Spring容器。

  ApplicationContext主要的实现类是ClassPathXmlApplicationContext和FileSystemXmlApplicationContext,前者默认从类路径加载配置文件,后者默认从文件系统加载配置文件。

在获取ApplicationContext实例后,就可以像BeanFactory一样调用getBean(beanName)方法来获取bean了,ApplicationContext和BeanFactory初始化有一个重大区别:BeanFactory初始化容器时 并未实例化bean,直到第一次访问某个bean时才实例化目标bean,

而ApplicationContext 则在初始化应用上下文时就初始化所有单实例的bean,因此ApplicationContext的初始化时间要比BeanFactory的初始化长一些,后面要使用ApplicationContext的bean时 可以直接去缓存中获取bean。

  FactoryBean是一种特殊的bean接口,其作用也是创建bean,包含FactoryBean<T> 包含三个方法

  boolean isSingleton(); 返回所创建的bean是否是单例的,

  T getObject() 返回又FactoryBean所创建的bean实例,如果isSingleton方法返回true,那么bean实例将会被放到spring容器的缓存池中,

  Class<?> getObejctType();返回创建bean的类型。

  当一个需要被注入到容器的bean实现了FactoryBean接口时,通过getBean()方法返回的不是FactoryBean本身,而是FactoryBean.getObject()返回的对象,也就是说FactoryBean.getObject()代理了getBean()方法。

3 Bean的生命周期

  BeanFactory中的bean的生命周期

package com.bujiang.magic;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class Car implements BeanFactoryAware ,BeanNameAware,InitializingBean,DisposableBean{
    
    private String brand;
    private String color;
    private int maxSpeed;
    private BeanFactory beanFactory;
    private String beanName;
    public Car() {
        System.out.println("调用Car的构造方法");
    }
    public String getBrand() {
        return brand;
    }
    public void setBrand(String brand) {
        System.out.println("调用setBrand() 方法");
        this.brand = brand;
    }
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
    public int getMaxSpeed() {
        return maxSpeed;
    }
    public void setMaxSpeed(int maxSpeed) {
        this.maxSpeed = maxSpeed;
    }
    public BeanFactory getBeanFactory() {
        return beanFactory;
    }
    public void setBeanFactory(BeanFactory beanFactory) {
        System.out.println("调用BeanFactoryAware的setBeanFactory方法");
        this.beanFactory = beanFactory;
    }
    public String getBeanName() {
        return beanName;
    }
    public void setBeanName(String beanName) {
        System.out.println("调用BeanNameAware的setBeanName方法");
        this.beanName = beanName;
    }
    @Override
    public void destroy() throws Exception {
        System.out.println("调用DisposableBean的destroy方法");
        
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("调用InitializingBean的afterPropertiesSet方法");
        
    }
    
    public void myInit() {
        System.out.println("调用car的init-method指向的myInit方法");
    }
    
    public void myDestroy() {
        System.out.println("调用car的destroy-method指向的myDestroy方法");
    }
    @Override
    public String toString() {
        return "Car [brand=" + brand + ", color=" + color + ", maxSpeed=" + maxSpeed + ", beanFactory=" + beanFactory
                + ", beanName=" + beanName + "]";
    }
    
    

}
package com.bujiang.magic;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPostProcessor  implements BeanPostProcessor{
    public Object postProcessBeforeInitialization(Object bean,String beanName)throws BeansException {
        if(beanName.equals("car")) {
            Car car = (Car)bean;
            if(car.getColor()==null) {
                System.out.println("调用MyBeanPostProcessor的postProcessBeforeInitialization方法,为bean设置属性color,为黑黑黑");
                car.setColor("黑黑黑");
            }
        }
        return bean;
    }
    
    public Object postProcessAfterInitialization(Object bean,String beanName)throws BeansException {
        if(beanName.equals("car")) {
            Car car = (Car)bean;
            if(car.getMaxSpeed()>=200) {
                System.out.println("调用MyBeanPostProcessor的postProcessAfterInitialization方法,为bean设置属性MaxSpeed,为999");
                car.setMaxSpeed(999);
            }
        }
        return bean;
    }
}
package com.bujiang.magic;

import java.beans.PropertyDescriptor;

import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;

public class MyInsttabtiationAwareBeanPostProcessor  implements InstantiationAwareBeanPostProcessor{
    
    public Object postProcessBeforeInstantiation(Class beanClass,String beanName) throws BeansException {
        if("car".equals(beanName)) {
            System.out.println("调用MyInsttabtiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法");
        }
        return null;
    }
    
    public boolean postProcessAfterInstantiation(Object bean,String beanName) throws BeansException {
        if("car".equals(beanName)) {
            System.out.println("调用MyInsttabtiationAwareBeanPostProcessor的postProcessAfterInstantiation方法");
        }
        return true;
    }
    
    public PropertyValues postProcessPropertyValues(PropertyValues pvs,PropertyDescriptor[] pds,Object bean,String beanName)throws BeansException {
        if("car".equals(beanName)) {
            System.out.println("调用MyInsttabtiationAwareBeanPostProcessor的postProcessPropertyValues方法");
        }
        return pvs;
    }

}

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd" default-autowire="byName">
    
    <bean id="car" class="com.bujiang.magic.Car" init-method="myInit" destroy-method="myDestroy" p:brand="红旗CA72" p:maxSpeed="200" scope="singleton" />
    <!-- <bean id="car" class="com.bujiang.magic.Car" init-method="myInit" destroy-method="myDestroy" p:brand="红旗CA72" p:maxSpeed="200" scope="prototype" /> -->
</beans>
package com.bujiang.magic;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

public class BeanLifeCycle {
    private static void lifeTest() {
        //加载配置文件并启动容器
        Resource res = new ClassPathResource("com/bujiang/magic/beans.xml");
        BeanFactory bf = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader((DefaultListableBeanFactory)bf);
        reader.loadBeanDefinitions(res);
        
        //向容器注册MyBeanPostProcessor后置处理器,如果容器不注册那么BeanPostProcessor所有的方法都不执行
        ((ConfigurableBeanFactory) bf).addBeanPostProcessor(new MyBeanPostProcessor());
        //向容器注册MyInsttabtiationAwareBeanPostProcessor后置处理器,如果容器不注册那么InstantiationAwareBeanPostProcessor所有的方法都不执行
        ((ConfigurableBeanFactory) bf).addBeanPostProcessor(new MyInsttabtiationAwareBeanPostProcessor());
        
        //第一次从容器中获取bean对象,将触发实例化bean的生命周期方法的调用
        Car car1 = (Car) bf.getBean("car");
        System.out.println(car1.toString());
        car1.setColor("红色");
        
        //第二次从容器中获取bean,直接从缓存中获取,不会触发生命周期方法
        Car car2 = (Car) bf.getBean("car");
        System.out.println("car1=car2?"+(car1==car2));
        
        //关闭容器
        ((DefaultListableBeanFactory)bf).destroySingletons();
    }
    
    public static void main(String[] args) {
        lifeTest();
    }

}

输出结果

调用MyInsttabtiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法
调用Car的构造方法
调用MyInsttabtiationAwareBeanPostProcessor的postProcessAfterInstantiation方法
调用MyInsttabtiationAwareBeanPostProcessor的postProcessPropertyValues方法
调用setBrand() 方法
调用BeanNameAware的setBeanName方法
调用BeanFactoryAware的setBeanFactory方法
调用MyBeanPostProcessor的postProcessBeforeInitialization方法,为bean设置属性color,为黑黑黑
调用InitializingBean的afterPropertiesSet方法
调用car的init-method指向的myInit方法
调用MyBeanPostProcessor的postProcessAfterInitialization方法,为bean设置属性MaxSpeed,为999
Car [brand=红旗CA72, color=黑黑黑, maxSpeed=999, beanFactory=org.springframework.beans.factory.support.DefaultListableBeanFactory@11c20519: defining beans [car]; root of factory hierarchy, beanName=car]
car1=car2?true
调用DisposableBean的destroy方法
调用car的destroy-method指向的myDestroy方法

  当通过getBean获取bean时:

  1 调用InstantiationAwareBeanPostProcessor接口的postProcessBeforeInstantiation()方法

  2 调用调用构造函数或者其他方式实例化bean

  3 调用InstantiationAwareBeanPostProcessor接口的postProcessAfterInstantiation()方法

  4 调用InstantiationAwareBeanPostProcessor接口的postProcessPropertyValues()方法     

  5 调用bean的设置属性值的方法 setXXX()  

  6 调用BeanFactoryAware的setBeanName()方法

  7 调用BeanFactoryAware的setBeanFactory()方法

  8 调用BeanPostProcessor的postProcessBeforeInitialization方法

  9 调用InitializingBean的afterPropertiesSet方法

  10 调用bean指定的init-method方法

  11 调用BeanPostProcessor的postProcessAfterInitialization方法

  12如果bean的作用范围是多例(prototype),那么将bean返回给调用者 Spring不再管理这个bean的生命周期,如果是单例(singleton) 则将bean放入到ioc容器的缓存池中,并将bean的引用返回给调用者,ioc容器继续管理这个bean的生命周期

  13 当容器关闭时,触发DisposableBean的destroy方法

  14 执行bean的destroy-method指定的方法。

 以上方法可以分为以下4类

  1 Bean自身的方法:如构造方法,setXXX方法 init-method指定的方法 destroy-method指定的方法

     2 Bean级别生命周期接口方法: BeanFactoryAware ,BeanNameAware,InitializingBean,DisposableBean接口方法,执行方法由bean类直接实现

  3 容器级别的生命周期方法:如BeanPostProcessor,InstantiationAwareBeanPostProcessor的方法,这些方法一般成为类的后置处理器,当IOC容器创建任何bean的时候,这些后置处理器都会起作用,就是说这些处理器的影响是全局性的

  4 工厂后处理器接口方法,工厂后处理器也是容器级的,在应用上下文装配配置文件后立即调用

  

ApplicationContext中的bean的生命周期

  bean在ApplicationContext的生命周期与在BeanFactory中的生命周期类似,不同的是如果bean 实现了ApplicationContextAware接口,则会增加该接口的setApplicationContext方法,该方法在上面生命周期的第七步之后,第八步之前。ApplicationContext与BeanFactory的另外一个最大的不同是 前者会利用java反射机制自动识别配置文件中定义的工厂后置处理器,并自动将他们注册到上下文,而后者需要手动的addBeanPostProcessor方法才行,因此应用开发中普遍使用ApplicationContext而不是BeanFactory。如果配置文件定义了多个工厂后置处理器,那么让它们实现import org.springframework.core.Ordered接口,如果不实现这个接口那么,那么的先后顺序将由它们在xml中定义的位置确定,先定义的先执行。

IOC装配bean

  

  Spring启动时读取应用程序提供的bean的配置信息,并在容器中生成一份相应的bean注册表,然后根据注册表实例化bean,装配好bean之间的依赖关系,为应用提供运行环境。Bean的配置信息就是bean的元数据信息,元数据信息在容器内部对应的是一个个BeanDefinition形成的注册表,Spring通过元数据和外部bean定义实现解耦。

依赖注入,spring支持两种依赖注入的方式(属性注入和构造函数注入),此外 还支持工厂方法注入。

  属性注入,属性注入是通过setXXX方法将bean的属性或者依赖的对象注入到bean中,属性注入比较于构造器注入是更灵活的。属性注入要求Bean提供一个默认的无参构造函数,并且要注入的属性提供setXXX方法,Spring先利用构造方法实例化Bean对象,然后利用反射方式调用Setter方法注入属性值。使用属性注入时,Spring 只会检查bean中是否有对应的setter方法,至于Bean中是否有这个属性则不做要求,对于属性注入时的属性名,spring希望变量前两个字母要么全部大写,要么全部小写,如brand,IDCode是合法的,而iC,iDCard是不合法的,当我们使用不合法的属性名,启动Spring 会报Invalid property \'iDCard\' of bean class,

  构造函数注入,相较与属性注入,构造函数注入比较繁琐,这里不做介绍

  工厂方法注入

    1 静态工厂方法注入

    <bean id = "carFactory" class="xxxx.CarFactory"></bean>
    <!-- 由于普通工厂方法是非静态的,所以需要先实例化工厂类 -->
    <bean id="car" factory-bean="carFactory" factory-method="createCar"></bean>

    2 静态工厂方法注入

    <!-- 由于普通工厂方法是静态的,所以可以直使用方法方法注入 -->
    <bean id="car" factory-method="xxx.CarFactory。createCar"></bean>

Bean的作用域

  singleton

    传统开发中,由于dao类中持有Connection这个非现场安全的变量,因此往往是不能采用单例模式的,但是spring 利用aop和ThreadLocal 对非线程安全的变量进行了特殊的处理(这个后面再说),使这些变成了线程安全的类,这哥原因也是为什么大部分bean都能以单例模式运行的原因。

  prototype

    这种是非单例的模式,spring容器将这种bean初始化之后交给调用者,其后续的生命周期spring不再管理。

  其他作用域 request,session,gloalSession 这些与WebApplicationContext相关的作用域

注解

@Component 等价于一下注解配置

<bean id = "carFactory" class="xxxx.CarFactory"></bean>

此外spring还提供一下三个注解,功能等价于@Component ,作用仅仅是表名各个层中的bean的用途意义,完全可以用@Component替代他们

@Respository,@Service ,@Controller。

@Autowired 自动装配,默认使用byType方式,按照类型匹配来注入bean。@Autowired 支持在属性和方法上使用,作用都是自动注入。

@Resource ,@Inject ,这两者与@Autowired 作用基本一致,@Resource是byName注入,@Inject 用的比较少

@Qualifier 指定注入bean的名称。、

基于java类的注解配置

@Configuration 这个注解的作用是将一个pojo标注为spring配置类,

@Bean 这个注解是返回一个bean,bean的名称默认是方法名,

以上是关于Spring IOC的主要内容,如果未能解决你的问题,请参考以下文章

Spring之IOC原理及代码详解

Spring IOC源代码具体解释之整体结构

Spring 框架学习——IOC思想原型及实质

Spring IOC源代码具体解释之容器依赖注入

[Spring 源解系列] 重温 IOC 设计理念

Spring IoC