实例化Bean
单例bean,并且lazy-init为false(默认是false),则 ApplicationContext在刷新的时候就实例化该Bean,并且将实例化的Bean放到缓存中,下次再使用该Bean的时候, 直接从这个缓存中获取;如果单例bean是懒加载的,即lazy-init为true,则在第一次getBean获取该Bean的时候进行实例化,并放入缓存;scope是prototype的多例bean,每次使用获取Bean的时候都会进行实例化
<bean id="" class="" scope="作用域"/>
1. singleton: 单例 ,在Spring IoC容器中仅存在一个Bean实例 (默认的scope)
2. prototype: 多例 ,每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()
3. request: 用于web开发,将Bean放入request范围 , 在同一个request 获得同一个Bean
4. session: 用于web开发,将Bean 放入Session范围,在同一个Session 获得同一个Bean
spring容器默认加载bean为非延迟加载,在容器刷新阶段就会实例化bean对象,设置为延迟加载则当类首次被加载时才会初始化实例,所有bean的实例化都是通过getBean去实现
<!--当前xml中所有的bean-->
<beans default-lazy-init="default | false | true">
<!--指定的bean-->
<bean lazy-init="default | false | true">
使用注解方式
@Lazy
public class Bean {
}
总结所有bean的生命周期:单例且非延迟加载的bean跟随容器刷新完成实例初始化,之后访问实例从缓存中获取;单例延迟加载的bean在首次访问时通过getBean完成实例化,之后访问从缓存中获取;
Bean实例化的方式
无参数构造器实例化
<bean id="super" name="a1,a2,a3" class="cn.mywork.spring.Super" lazy-init="true"/>
静态工厂方法实例化
//factory-method找到工厂类的静态方法
<bean id="student" class="cn.mywork.spring.StaticFactory" factory-method="getStu"/>
//配置静态工厂类
public class StaticFactory {
//通过配置文件找到静态方法,返回对象为创建的bean
public static Student getStu(){
return new Student();
}
}
ApplicationContext context;
Student student = context.getBean("student", Student.class);
实例工厂
//先将工厂bean交给容器管理
<bean id="instanceFactory" name="fc" class="cn.mywork.wms.spring.InstanceFactory"/>
//factory-bean只能是初始化好的bean对象,通过bean工厂对象,获取实例方法初始化bean
<bean id="student" factory-bean="fc" factory-method="getStu"/>
实现FactoryBean接口,通过getObject方法返回目标实例
//实现getObject方法
public class InstanceFactory implements FactoryBean<Student>{
@Override
public Student getObject() throws Exception {
return new Student();
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
<bean id="student" class="cn.mywork.spring.InstanceFactory"/>
注解的方式
//注解对应的配置解析
<bean id="super" class="cn.mywork.wms.spring.Super" init-method="init" destroy-method="destory" scope="prototype">
<!--注入的属性-->
<property name="sub" ref="sub"/>
</bean>
<bean id="sub" class="cn.mywork.wms.spring.Sub"/>
//默认的为简化的类名,Xml里也同于bean标签的id值
@Component("super")
//作用域:非单例
@Scope("prototype")
public class Super {
private String name;
//注入Sub初始化的实例
@Autowired
private Sub sub;
//初始化的方法,init-method="init"
@PostConstruct
public void init(){
}
//销毁的方法,destroy-method="destory"
@PreDestroy
public void destory(){
}
}
自定义BeanFactory工厂
public class BeanFactoryDemo {
//key为id,value为全限定名
private static Map<String,String> beanMap = new HashMap<>();
//bean缓存,延迟加载bean时,genBean之后将bean放入缓存
private static Map<String,Object> cacheMap = new HashMap<>();
//解析xml配置文件
static {
try {
//getClassLoader().getResourceAsStream是加载resources资源路径下的配置文件
InputStream resource = BeanFactoryDemo.class.getClassLoader().getResourceAsStream("spring.xml");
initBeanMap(resource);
}catch (Exception e){
}
}
private static void initBeanMap(InputStream resource) throws Exception {
SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
saxParser.parse(resource,new DefaultHandler(){
//解析后的标签名
private String tagName;
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
this.tagName = qName;
//获取标签内容
if ("bean".equals(tagName)){
//获取id的值
String id = attributes.getValue("id");
//获取bean的全限定名
String beanClassName = attributes.getValue("class");
beanMap.put(id,beanClassName);
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
tagName = null;
}
});
}
//获取bean实例的方法,延迟加载方式
public static <T> T getBean(String id,Class<T> beanClass) throws Exception{
//只有map中存在的key值才会继续处理
if (beanMap.containsKey(id)){
//再判断缓存中是否有该bean
if (cacheMap.containsKey(id)){
return (T) cacheMap.get(id);
}
String beanClassName = beanMap.get(id);
//加载全限定名,通过反射机制创建bean
Object instance = Class.forName(beanClassName).newInstance();
//判断是否为beanClass类型的实例
if (beanClass.isInstance(instance)){
cacheMap.put(id,instance);
return (T) instance;
}
}
return null;
}
}
Student student = BeanFactoryDemo.getBean("student", Student.class);
getBean
refresh执行到finishBeanFactoryInitialization时才开始实例化非延迟加载的bean,主要看其中的preInstantiateSingletons方法
public void preInstantiateSingletons() throws BeansException {
//所有的需要实例化的beanName都在beanDefinitionNames,包括 Aspectj的, 通过注解标识的
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
for (String beanName : beanNames) {
//合并父类BeanDefinition
//MergedBeanDefinition合并bean定义,XML 配置来注册 bean,会被封装成GenericBeanDefinition;使用注解的方式来注册 bean,会被封装成 ScannedGenericBeanDefinition,最终统一转换成 RootBeanDefinition处理
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//非抽象,单例,非懒加载三个条件
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
//是 FactoryBean 类型的对象则加上&
//判断是factoryBean还是普通bean,实现FactoryBean接口的getObject()方法可以定义创建实例对象,比如很多中间件的就是通过这种方式实现
if (isFactoryBean(beanName)) {
bean = getBean(FACTORY_BEAN_PREFIX + beanName);
...
}
else {
// 进入到doGetBean执行实例化bean
bean = getBean(beanName);
}
}
}
}
容器初始化完成还是在初始化之后动态获取bean都会访问beanFacroty.getBean()方法,进入这个方法发现有很多分支去获取bean,如果不是首次获取bean则直接getSingleton()先从缓存中获取
protected <T> T doGetBean(String name, Class<T> requiredType,Object[] args, boolean typeCheckOnly) throws BeansException {
//去掉FactoryBean的前缀“&”,解析别名返回namespace的beanName
String beanName = this.transformedBeanName(name);
//获取缓存中的bean,不涉及创建新的bean实例和解决循环依赖
Object sharedInstance = this.getSingleton(beanName);
Object bean;
//缓存中如果能获取到
if (sharedInstance != null && args == null) {
//普通bean直接返回实例,factoryBean继续处理
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
} else {
//和singletonsCurrentlyInCreation类似存放正在创建的Prototype实例
//循环依赖校验:当前原型实例池中有正在创建的对象了,说明这个对象是个原型对象,并且当前线程中这个对象已经处于创建中了,会造成循环依赖
if (this.isPrototypeCurrentlyInCreation(beanName)) {