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的主要内容,如果未能解决你的问题,请参考以下文章