spring 详解四 IOC(spring Bean生命周期)

spring生命周期概述

spring Bean的生命周期是从Bean实例化之后,即通过反射创建对象之后,到Bean成为一个完整对象,最终存储在单例池中,然后在销毁的过程被称为spring Bean的生命周期,这部分不会介绍销毁过程,只要在从无到有的创建过程

Bean的实例化阶段:spring框架会从BeanDefinitionMap中取出BeanDefinition定义信息判断当前Bean的范围是否是singleton,是否是延迟加载,是否是工厂方法实例化等,最终通过反射创建出Bean对象

Bean的初始化阶段:Bean创建之后仅仅只是个半成品,还需要对Bean进行DI,也就是popluate属性填充,执行一些Aware接口方法,执行BeanPostProcessor#before方法,执行InitializingBean接口初始化方法,执行自定义初始化方法,BeanPostProcessor#after方法执行,该阶段是spring的重要阶段,Aop功能的实现,注解功能,循环依赖功能均在此阶段

Bean的完成阶段:经过初始化阶段,Bean就成为了一个完整的sping Bean,被存储到单例池singletonObjects中去了,到此为止,即完成了springBean的整个生命周期

 spirng生命周期图

spring属性填充和三级缓存解决循环依赖 

属性填充位置

BeanDefinition中有对当前Bean实体的注入信息通过属性propertyValues进行存储注入

 属性注入规则

普通属性注入时,String,int或者存储基本类型的集合时,直接通过set方法的反射注入

注入单项对象引用属性时,先从容器中getBean获取后在通过set方法反射设置进去,如果容器中没有,则先创建对象Bean实例,在注入操作

注入双向对象引用属性时,即涉及到了循环引用问题(解决方案是三级缓存)

spring循环依赖问题 

当两个对象互相引用对方对象的时候,就出现了循环引用问题,下面造一个循环引用的问题

package com.tech.test.testbean;

import com.tech.test.service.UserService;


public class DI {

    private UserService userService;

    public void setUserService(UserService userService) {
        this.userService = userService;
    }
}
package com.tech.test.service.impl;

import com.tech.test.service.UserService;
import com.tech.test.testbean.DI;

public class UserServiceImpl implements UserService {


    private DI di;

    public void setDi(DI di) {
        this.di = di;
    }

    @Override
    public void getUser() {
        System.out.println("get User Success");
    }


}
  <bean id="userService"  name="aaa,bbb"  class="com.tech.test.service.impl.UserServiceImpl" >
        <property name="di" ref="di"></property>
    </bean>


    <bean id="di"  class="com.tech.test.testbean.DI" autowire="byName">
        <property name="userService" ref="userService"></property>
    </bean>

 在上边定义的循环引用问题是 userService对象引用了di对象,di对象又引用了userService对象,出现了循环引用问题,也就是死循环

 解决循环依赖问题(三级缓存)

 spring解决循环依赖问题引入了三级缓存

1、实例化对象,没有进行属性注入等初始化操作,会放入三级缓存,这时候的对象是一个半成品,没有被引用

2、当半成品对象被其他对象引用的时候,这个时候将对象放入二级缓存,删除三级缓存,

3、当引用对象的实例化和初始化都完成了进入一级缓存 ,删除二级缓存

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {

	/** Cache of singleton objects: bean name to bean instance. */
    // 存储单例Bean成品的容器,一级缓存
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/** Cache of early singleton objects: bean name to bean instance. */
   // 早期的Bean单例池,缓存半成品对象,且对象已经被引用啦,二级缓存
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

	/** Cache of singleton factories: bean name to ObjectFactory. */
   // 单例Bean的工厂池,缓存半成品对象,对象未被引用,使用时在通过工厂创建Bean 三级缓存
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);



}

上述实例填充步骤:

1、userService实例化对象,分配内存地址,但尚未初始化,将userService存储到三级缓存

2、userService属性注入,需要DI对象,从缓存中取,没有DI对象

3、DI实例化对象,分配内存地址,但尚未初始化,将DI存入三级缓存

4、DI属性注入,需要userService,从三级缓存中取userService,userService从三级缓存中移除,放入二级缓存

5、DI执行初始化,最终成为一个完整的bean,存到一级缓存,移除二级缓存

6、userService 注入DI

7、userService执行初始化等流程,最终形成一个bean,放入一级缓存,移除二三级缓存

 spring中的Aware接口

 Aware接口是一种框架辅助属性注入的一种思想,简单直白的说,就是框架通过Aware接口给我们注入框架底层使用的对象,其他框架也有类似的Aware接口,框架具有高度封装性,底层API不能轻易的获取到,框架通过Aware接口给使用者注入该对象

在属性注入之后执行Aware方法

 常见的Aware接口

Aware接口回调方法作用
ServletContextAwaresetServletContext(ServletContext context)spring框架回调方法注入servletContext对象,web环境生效
BeanFactoryAwaresetBeanFactory(BeanFactory factory)spring框架回调方法注入beanFactory对象
BeanNameAwaresetBeanName(String beanName)spring框架回调方法注入当前Bean在容器中的beanName

ApplicationContextAware

setApplicationContext(ApplicationContext applicationContext)spring回调方法注入applicationContext对象
package com.tech.test.service.impl;

import com.tech.test.service.UserService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class UserServiceImpl implements UserService, ApplicationContextAware, BeanNameAware {


    @Override
    public void getUser() {
        System.out.println("get User Success");
    }


    @Override
    public void setBeanName(String name) {
        System.out.println(name);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println(applicationContext);
    }
}

 可以看到 ,spring框架帮我们注入了bean的名称和applicationcontext对象

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值