Java Spring Bean的实例化
Spring框架支持两种方式去进行Bean的管理:BeanFactory、ApplicationContext
BeanFactory:pom文件引入spring-context坐标,创建对应的待IOC类,然后在bean.xml注入,最后在调用处初始化BeanFactory及xml加载获取
ApplicationContext:内部封装了BeanFactory,在基础上进行了扩展,ApplicationContext的API更加方便使用继承关系和扩展关系
联系:ApplicationContext封装BeanFactory
区别:Bean的初始化时机不同,BeanFactory(懒汉)是首次调用getBean()进行创建,ApplicationContext(饱汉)是加载配置文件,容器创建就将Bean实例化初始化
Bean 实例化的基本流程:
Spring容器在进行初始化时,会将xml配置的bean的信息封装成一个BeanDefinition对象,所有的BeanDefinition存储到一个名为beanDefinitionMap的Map集合中去,Spring框架在对该Map进行遍历,使用反射创建Bean实例对象,创建好的Bean对象存储在一个名为singletonObjects的Map集合中,当调用getBean方法时则最终从该Map集合中取出Bean实例对象返回
Bean的作用范围:默认情况下,单纯的Spring环境Bean的作用范围有两个:Slingleton和Prototype,在Spring-webmvc中还有request和session
Slingleton:单例,默认值,Spring容器创建时进行Bean的实例化,存到Spring容器内部的singletonObjects单例池中,每次getBean都是从单例池中获取相同的Bean实例
Prototype:原型,Spring容器初始化时不创建Bean实例,调用getBean时实例化Bean,每次getBean都会创建一个新的Bean的实例
Spring Bean的实例化(指的是BeanFactory内)有两种方向:构造方式实例化、工厂方式实例化
其中工厂方式实例化时,又可以区分几种类型:静态工厂方式、非静态工厂、实现FactoryBean接口
构造方式实例化:底层通过构造方法对Bean进行实例化,配置类路径通过反射加载通过构造方法创建
public class PeopleServiceImpl implements PeopleService {
public String name;
public PeopleServiceImpl() {
}
public PeopleServiceImpl(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
<bean id="peopleService" class="com.service.impl.PeopleServiceImpl">
<constructor-arg name="name" value="Wang"></constructor-arg>
</bean>
获取时直接调用getBean()方法,里面指定peopleService信息
静态工厂方式:单例池中Key为工厂名,value为Bean对象
public class MyBeanFactory {
public static PeopleServiceImpl peopleService(){
return new PeopleServiceImpl();
}
}
<bean id="myBeanFactory" class="com.factory.MyBeanFactory" factory-method="peopleService"></bean>
获取时直接调用getBean()方法,里面指定myBeanFactory信息
非静态工厂:bean.xml中配置两个,单例池中存在两个
public class MyBeanFactory2 {
public PeopleServiceImpl peopleService(){
return new PeopleServiceImpl();
}
}
<bean id="myBeanFactory2" class="com.itheima.factory.MyBeanFactory2"></bean>
<bean id="peopleService2" factory-bean="myBeanFactory2" factory-method="peopleService"></bean>
获取时直接调用getBean()方法,里面指定peopleService2信息
实现FactoryBean接口:在getBean()时创建,即延迟创建
public class MyBeanFactory3 implements FactoryBean {
public Object getObject() throws Exception {
return new PeopleServiceImpl();
}
public Class<?> getObjectType() {
return PeopleServiceImpl.class;
}
}
<bean id="myBeanFactory3" class="com.itheima.factory.MyBeanFactory3"></bean>
通过断点观察发现Spring容器创建时,FactoryBean被实例化了,并存储到了单例池singletonObjects中,但是getObject() 方法尚未被执行,PeopleServiceImpl也没被实例化,当首次用到PeopleServiceImpl时,才调用getObject() ,此工厂方式产生的Bean实例不会存储到单例池singletonObjects中,会存储到 factoryBeanObjectCache 缓存池中,并且后期每次使用到PeopleService都从该缓存池中返回的是同一个PeopleService实例