spring容器的bean什么时候被实例化
BeanFactory作为Spring Bean的工厂类,则所有的bean都是在第一次使用该Bean的时候实例化
ApplicationContext作为Spring Bean的工厂类,则又分为以下几种情况:
如果bean的scope是singleton的,并且lazy-init为false(默认是false,所以可以不用设置),则 ApplicationContext启动的时候就实例化该Bean,并且将实例化的Bean放在一个map结构的缓存中,下次再使 用该 Bean的时候,直接从这个缓存中取
如果bean的scope是singleton的,并且lazy-init为true,则该Bean的实例化是在第一次使用该Bean的时候进行实例化。
如果bean的scope是prototype的,则该Bean的实例化是在第一次使用该Bean的时候进行实例化。
Bean类的配置项
Spring IOC容器管理Bean时,需要了解Bean的类名、名称、依赖项、属性、生命周期及作用域等信息。为此,Spring IOC提供了一系列配置项,用于Bean在IOC容器中的定义。
① class
该配置项是强制项,用于指定创建Bean实例的Bean类的路径。
② name
该配置项是强制项,用于指定Bean唯一的标识符,在基于 XML 的配置项中,可以使用 id和或 name 属性来指定 Bean唯一 标识符。
③ scope
该配置项是可选项,用于设定创建Bean对象的作用域。
④ constructor-arg
该配置项是可选项,用于指定通过构造函数注入依赖数据到Bean。
⑤ properties
该配置项是可选项,用于指定通过set方法注入依赖数据到Bean。
⑥ autowiring mode
该配置项是可选项,用于指定通过自动依赖方法注入依赖数据到Bean。
⑦ lazy-initialization mode
该配置项是可选项,用于指定IOC容器延迟创建Bean,在用户请求时创建Bean,而不要在启动时就创建Bean。
Spring Bean的作用域(scope配置)
在Spring配置文件定义Bean时,通过声明scope配置项,可以灵活定义Bean的作用范围。
① singleton
IOC容器仅创建一个Bean实例,IOC容器每次返回的是同一个Bean实例。
② prototype
IOC容器可以创建多个Bean实例,每次返回的都是一个新的实例。
③ request
每次HTTP请求都会创建一个新的Bean,适用于WebApplicationContext环境。
④ session
该属性仅用于HTTP Session,同一个Session共享一个Bean实例。
⑤ global-session
该属性仅用于HTTP Session,所有的Session共享一个Bean实例。
Spring加载流程
初始化环境—>加载配置文件—>实例化Bean—>调用Bean显示信息
核心步骤
(1)首先是先从AbstractBeanFactory中去调用doGetBean(name, requiredType, final Object[] args, boolean typeCheckOnly)typeCheckOnly,判断进行创建bean还是仅仅用来做类型检查
(2)然后接着是去调用getSingleton()方法,用于单例Bean之间的循环依赖的解决,
singletonObjects指单例对象的cache (一级缓存)
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
singletonFactories指单例对象工厂的cache(三级缓存)
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
earlySingletonObjects指提前曝光的单例对象的cache(二级缓存)
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
(3)对从缓存中拿到的bean其实是最原始的bean,还未长大,所以这里还需要调用getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd)方法去进行实例化。
(4)然后会解决单例情况下尝试去解决循环依赖,如果isPrototypeCurrentlyInCreation(beanName)返回为true的话,会继续下一步,否则throw new BeanCurrentlyInCreationException(beanName);
(5)因为第三步中缓存中如果没有数据的话,就直接去parentBeanFactory中去获取bean,然后判断containsBeanDefinition(beanName)中去检查已加载的XML文件中是否包含有这样的bean存在,不存在的话递归去getBean()获取,如果没有继续下一步
(6)这一步是吧存储在XML配置文件中的GernericBeanDifinition转换为RootBeanDifinition对象。这里主要进行一个转换,如果父类的bean不为空的话,会一并合并父类的属性
(7)这一步核心就是需要跟这个Bean有关的所有依赖的bean都要被加载进来,通过刚刚的那个RootBeanDifinition对象去拿到所有的beanName,然后通过registerDependentBean(dependsOnBean, beanName)注册bean的依赖
(8)然后这一步就是会根据我们在定义bean的作用域的时候定义的作用域是什么,然后进行判断在进行不同的策略进行创建(比如isSingleton、isPrototype)
(9)这个是最后一步的类型装换,会去检查根据需要的类型是否符合bean的实际类型去做一个类型转换。Spring中提供了许多的类型转换器
Spring Bean的生命周期
如上图所示,Bean 的生命周期还是比较复杂的,下面来对上图每一个步骤做文字描述:
1.Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化
2.Bean实例化后对将Bean的引入和值注入到Bean的属性中
3.如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法
4.如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
5.如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。
6.如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。
7.如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用
8.如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。
9.Bean已经准备就绪,如果scope设置singleon,缓存在springioc容器。如果为prototype生命周期交给应用程序。
10.如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法
11.如果bean使用了destory-method 声明销毁方法,该方法也会被调用。
Bean 的生命周期验证
public class Book implements BeanNameAware,BeanFactoryAware,
ApplicationContextAware,InitializingBean,DisposableBean {
private String bookName;
public Book(){
System.out.println("Book Initializing ");
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("Book.setBeanFactory invoke");
}
public void setBeanName(String name) {
System.out.println("Book.setBeanName invoke");
}
public void destroy() throws Exception {
System.out.println("Book.destory invoke");
}
public void afterPropertiesSet() throws Exception {
System.out.println("Book.afterPropertiesSet invoke");
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("Book.setApplicationContext invoke");
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
System.out.println("setBookName: Book name has set.");
}
public void myPostConstruct(){
System.out.println("Book.myPostConstruct invoke");
}
// 自定义初始化方法
@PostConstruct
public void springPostConstruct(){
System.out.println("@PostConstruct");
}
public void myPreDestory(){
System.out.println("Book.myPreDestory invoke");
System.out.println("---------------destroy-----------------");
}
// 自定义销毁方法
@PreDestroy
public void springPreDestory(){
System.out.println("@PreDestory");
}
@Override
protected void finalize() throws Throwable {
System.out.println("------inside finalize-----");
}
}
自定义实现BeanPostProcessor 的MyBeanPostProcessor:
public class MyBeanPostProcessor implements BeanPostProcessor {
// 容器加载的时候会加载一些其他的bean,会调用初始化前和初始化后方法
// 这次只关注book(bean)的生命周期
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof Book){
System.out.println("MyBeanPostProcessor.postProcessBeforeInitialization");
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof Book){
System.out.println("MyBeanPostProcessor.postProcessAfterInitialization");
}
return bean;
}
}
在resources 目录下新建Bean-Lifecycle.xml
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 扫描bean -->
<context:component-scan base-package="com.bean.lifecycle"/>
<!-- 实现了用户自定义初始化和销毁方法 -->
<bean id="book" class="com.bean.lifecycle.Book" init-method="myPostConstruct" destroy-method="myPreDestory">
<!-- 注入bean 属性名称 -->
<property name="bookName" value="thingking in java" />
</bean>
<!--引入自定义的BeanPostProcessor-->
<bean class="com.bean.lifecycle.MyBeanPostProcessor"/></beans>
做一个启动类的测试,新建SpringBeanLifecycleApplication
public class SpringBeanLifecycleApplication {
public static void main(String[] args) throws InterruptedException {
// 为面试而准备的Bean生命周期加载过程
ApplicationContext context = new ClassPathXmlApplicationContext("Bean-Lifecycle.xml");
Book book = (Book)context.getBean("book");
System.out.println("Book name = " + book.getBookName());
((ClassPathXmlApplicationContext) context).destroy();
}
}
输出结果
Book Initializing
setBookName: Book name has set.
Book.setBeanName invoke
Book.setBeanFactory invoke
Book.setApplicationContext invoke
MyBeanPostProcessor.postProcessBeforeInitialization
@PostConstruct
Book.afterPropertiesSet invoke
Book.myPostConstruct invoke
MyBeanPostProcessor.postProcessAfterInitialization
Book name = thingking in java
@PreDestory
Book.destory invoke
Book.myPreDestory invoke
---------------destroy-----------------
Spring Bean有三种配置方式:
传统的XML配置方式
基于注解的配置
基于类的Java Config
<bean id="beanFactroy" class="com.stonegeek.service.impl.BeanFactroyImpl" />
如果一个类使用了@Service,那么此类将自动注册成一个bean,不需要再在applicationContext.xml文件定义bean了,类似的还包括@Component、@Repository、@Controller。然后需要在applicationContext.xml文件中加一行,作用是自动扫描base-package包下的注解:
<context:component-scan base-package="com.stonegeek" />
@Service
通过java类定义spring配置元数据,且直接消除xml配置文件
Spring3.0基于java的配置直接支持下面的注解:
@Configuration @Bean@DependsOn@Primary @Lazy@Import
@ImportResource @Value
public class BeanFactoryImpl implements BeanFactory {
@Override
public void Beantest() {
}
}
@Configuration
public class BeanConfig {
@Bean
public BeanFactory beanFactory(){
return new BeanFactoryImpl();
}
}
测试
public class TestBean2 {
@Test
public void test(){
ApplicationContext ctx= new ClassPathXmlApplicationContext("applicationContext.xml");
BeanFactory beanFactory=(BeanFactory) ctx.getBean("beanFactory");
beanFactory.Beantest(); //This is a 基于java注解的bean!
}
}
借鉴:https://www.cnblogs.com/javazhiyin/p/10905294.html
https://cloud.tencent.com/developer/article/1516796