理解Spring Bean的作用域和生命周期

1.什么是Spring Bean

  Spring Bean就会由Spring IOC容器初始化、装配及管理的对象,除此之外,它就和应用程序中其他对象没什么区别了。

2.Spring Bean作用域

2.1 Spring Bean的五种作用域

  在创建Spring Bean的时候可以灵活地选择这个对象的作用域,而不用在java类中进行定义。主要支持的五中作用域如下:

类别说明
singleton默认值,Bean以单例的形式存在。即这个Bean在Spring IOC容器中仅存在一个实例。
prototype这个Bean可以有多个实例,即每次从容器中调用Bean时,都会返回一个新的实例
request每次 http 请求都会创建一个 bean,该作用域仅在基于 web的Spring ApplicationContext情形下生效
session同一个Http Sessio共享一个Bean,不同的Session使用的是不同的实例,该作用域仅在基于 web 的Spring ApplicationContext 情形下有效
global-session在一个全局的 HTTP Session 中,一个 bean 定义对应一个实例。该作用域仅在基于 web 的 Spring ApplicationContext 情形下有效。
  • singleton
      唯一Bean实例。缺省的 Spring bean 的作用域是 Singleton。Sping Bean默认的作用域是singleton。当一个bean的作用域是singleton时,Spring IOC容器中就会只有一个共享的该bean的实例。所有对该bean的请求得到的也会是同一个对象。singleton分为**懒汉模式****饿汉模式**

饿汉模式: 默认,启动容器时(即实例化容器时),为所有spring配置文件或注解定义的bean都生成一个实例

懒汉模式: 在第一次被请求时才会生成实例,以后的请求都调用这个实例。spring singleton设置为懒汉模式:
  1.<beans default-lazy-init="true">

  • prototype
      每次请求都会创建一个新的Bean实例。当一个bean的作用域是prototype时,表示一个bean对应多个实例。prototype是原型类,在创建容器的时候并没有进行实例化,而是程序中需要获取bean的时候才会去实例化。每次对该 bean 请求(即将其注入到另一个 bean 中,或者以程序方法调用IOC容器的 getBean() 方法)时都会创建一个新的 bean 实例,获取到的对象都不是同一个对象。
对有状态的 bean(非线程安全) 应该使用 prototype 作用域,
而对无状态的 bean (线程安全)则应该使用 singleton 作用域

将bean 的作用域定义成 prototype 的几种方式:

1.@scope("prototype")
2.<bean id="xxx" class="com.xx.xxx" scope="prototype"/>
3.<bean id="xxx" class="com.xx.xxx" singleton="false"/>

2.2 Spring bean作用域为什么默认是单例

   一个bean创建的时候会先判断作用域是单例(singleton)还是原型(prototype),如果是单例则会先从缓存中获取,如果获取不到再新建,新建的就会存在于缓存中,如果是原型的时候就会新创建一个bean实例。
   所以一个bean的作用域为singleton时,在处理请求时,spring容器中只会实例化一个bean,并存在于缓存中,后续的请求都会从缓存中拿到这个bean实例,公用这个实例。prototype则是每次请求都会实例化一个新的bean。
   综上:Spring为什么把bean设计成单例的:

1.减少新创建实例的消耗,减少内存分配。
2.新生成的bean少了,jvm垃圾回收的对象也少了。
2.从缓存中拿取bean实例更快。

   当然,单例bean也有他的缺点,对于有状态的bean如果是单例的且在多线程环境下就会有线程安全问题。

问题:Spring的Controller是单例还是多例?怎么保证并发的安全
	答:单例
		怎么保证并发的安全?
		1.不要在controller中定义成员变量。
		2.万一必须要定义一个非静态成员变量时候,则通过注解@Scope(“prototype”),将其设置为多例模式。
		3.在Controller中使用ThreadLocal变量。

3.Spring Bean的生命周期

   先看一张图(图片来源自网络)
在这里插入图片描述

3.1 完整周期

先来看详细周期,后面为了方便理解和记忆会结合源码进行总结。

1.Spring启动,通过配置文件或注解找到被Spring管理的bean,并加载,然后实例化,相当于常说的new。
————————————————————————————————————————
2.Spring 根据 bean 的定义填充所有的属性。也就是IOC注入。
————————————————————————————————————————
3.BeanNameAware 实现:如果这个 Bean 实现了 BeanNameAware 接口,会调用它的 setBeanName(String)方法,把spring配置文件中bean的id传过来。

4.BeanFactoryAware 实现:如果bean实现了BeanFactoryAware接口,就会调用setBeanFactory(BeanFactory)方法,注入当前的BeanFactory的引用

5.ApplicationContextAware接口实现:如果这个bean实现了该接口,会调用
setApplicationContext(ApplicationContext)方法,传入 Spring 上下文(注入ApplicationContext容器本身,有和4一样的作用,但比效果 4 好,因为 ApplicationContext 是 BeanFactory 的子接口,有更多的实现方法)。

6.BeanPostProcessor接口实现:前置处理,在bean初始化之前,如果已经实现了该接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,这个一般被用作 Bean 内容的更改。

7.InitializingBean接口实现:如果实现了该接口,spring会调用afterPropertiesSet()方法,如果有自定义的init-method方法(Spring允许我们创建自己的 init 方法和 destroy 方法),则执行。

8.BeanPostProcessor 接口实现:后置处理,在初始化之后的后置操作如果这个 Bean 实现了 BeanPostProcessor 接口,将会调用postProcessAfterInitialization(Object obj, String s)方法。
————————————————————————————————————————
9.现在,Bean已经准备好了,可以使用啦,但在使用之前还会注册Destruction(销毁)相关回调接口。

10:最后销毁时如果bean实现了DisposableBean接口,Spring将执行destory()方法,和7一样,如果有自定义的destory-method 方法,该方法也会被执行。

3.2 概括生命周期的流程

  看了上面的10个步骤是不是感觉很难记,而且不理解…(其实上面的一些接口平时应该也很少用到)

为了方便学习和记忆可以将上述过程分为4个阶段:
  • ①实例化 Instantiation(第1步)
  • ②属性赋值 Populate(第2步)
  • ③初始化 Initialization(第3~8步)
  • ④销毁 Destruction(第9~10步)

  这里第9步时使用,实际上还不算是正式的销毁,因为这时还没开始使用或正在使用中。

结合源码加深理解和记忆
  ① 在方法org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean里可以看到Spring一次执行了这四个阶段(代码中加注释的地方)

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, Object[] args) throws BeanCreationException {

		//*********1.实例化**********
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
        }

        if (instanceWrapper == null) {
            instanceWrapper = this.createBeanInstance(beanName, mbd, args);
        }
        Object exposedObject = bean;

        try {
			//********** 2.属性赋值 **********
            this.populateBean(beanName, mbd, instanceWrapper);
            //**********3.初始化******************
            if (exposedObject != null) {
                exposedObject = this.initializeBean(beanName, exposedObject, mbd);
            }
        } catch (Throwable var18) {
            if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
                throw (BeanCreationException)var18;
            }

            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
        }
        try {
        	//*********** 4.注册回调接口--销毁**************
            this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
            return exposedObject;
        } catch (BeanDefinitionValidationException var16) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16);
        }
    }

为了直观,中间有的代码省略了没有贴过来。

② 查看第三步中的初始化方法(注释内容:对应上面的步骤序号)

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {

		// Aware相关接口及操作(对应第3~5)
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
                public Object run() {
                    AbstractAutowireCapableBeanFactory.this.invokeAwareMethods(beanName, bean);
                    return null;
                }
            }, this.getAccessControlContext());
        } else {
            this.invokeAwareMethods(beanName, bean);
        }
		
		// BeanPostProcessor接口 前置处理(对应第六步)
        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
        }
		// 检查如果实现了InitializingBean,调用它的afterPropertiesSet()方法,   
		//如果有自定义的init-method方法,则使用(第7步)
        try {
            this.invokeInitMethods(beanName, wrappedBean, mbd);
        } catch (Throwable var6) {
            throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
        }
		// BeanPostProcessor接口 后置处理 (第八步)
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }
        return wrappedBean;
    }

② 销毁(和第7步类似)

//org.springframework.beans.factory.support.DisposableBeanAdapter#destroy
public void destroy() {
        if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
            Iterator var1 = this.beanPostProcessors.iterator();

            while(var1.hasNext()) {
                DestructionAwareBeanPostProcessor processor = (DestructionAwareBeanPostProcessor)var1.next();
                processor.postProcessBeforeDestruction(this.bean, this.beanName);
            }
        }

        if (this.invokeDisposableBean) {
            if (logger.isDebugEnabled()) {
                logger.debug("Invoking destroy() on bean with name '" + this.beanName + "'");
            }

            try {
            //如果bean实现了DisposableBean接口,Spring将执行destory()方法
                if (System.getSecurityManager() != null) {
                    AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                        public Object run() throws Exception {
                            ((DisposableBean)DisposableBeanAdapter.this.bean).destroy();
                            return null;
                        }
                    }, this.acc);
                } else {
                    ((DisposableBean)this.bean).destroy();
                }
            } catch (Throwable var3) {
                String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
                if (logger.isDebugEnabled()) {
                    logger.warn(msg, var3);
                } else {
                    logger.warn(msg + ": " + var3);
                }
            }
        }
        
		//如果有自定义的destory-method 方法,该方法也会被执行
        if (this.destroyMethod != null) {
            this.invokeCustomDestroyMethod(this.destroyMethod);
        } else if (this.destroyMethodName != null) {
            Method methodToCall = this.determineDestroyMethod();
            if (methodToCall != null) {
                this.invokeCustomDestroyMethod(methodToCall);
            }
        }

    }

3.3 SpringBean 的扩展

上面不是说了很多接口嘛,有InitializingBean,*Aware,BeanPostProcessor,DisposableBean等等,这些接口可实现可不实现,方便我们对Bean做一些扩展操作。
1.InitializingBean接口和init-method,DisposableBean和destroy-method
  通过实现InitializingBean接口的afterPropertiesSet()方法和DisposableBean的destroy()方法 或自定义的init-method和destroy-method方法,可以让我们在Bean初始化属性赋值之后和销毁之前做一些操作,比如查看bean的属性值… …

几个例子:
这里使用demoService 作为正在被Spring管理的Bean

①通过实现接口方法(与Spring耦合)

public class demoService implements InitializingBean,DisposableBean {
	//实现两个接口并覆写他们的方法,让Spring执行
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("属性设置完成后执行InitializingBean接口的afterPropertiesSet()完成一些操作");
    }
     @Override
    public void destroy() throws Exception {
        System.out.println("销毁之前执行DisposableBean 的destroy()完成一些操作");
    }
}

②使用注解(好用)

public class demoService {
    @PostConstruct
    public void initMethod(){
        System.out.println("通过@PostConstruct执行一些操作");
    }
    @PreDestroy
    public void destroyMethod(){
        System.out.println("通过@PostConstruct执行一些操作");
    }
}

③使用配置文件

public class demoService {
    public void initMethod() throws Exception {
        System.out.println("执行init-method做一些操作");
    }
        public void destroyMethod() throws Exception {
        System.out.println("执行destroy-method做一些操作");
    }
}
<bean name="demoService " class="com.service.demoService " init-method="initMethod" destroy-method="destroyMethod"></bean>

3.4 总结

Spring Bean的生命周期:

  • 四大阶段:实例化>属性赋值>初始化>销毁

  其中初始化阶段的内容比较多,这部分内容主要就是检查是否实现*Aware接口,调用set方法,通过依赖注入的方式,让Bean获取容器自身的一些对象,例如BeanFactoryAware 接口——setBeanFactory(BeanFactory)方法——BeanFactory;检查是否实现BeanPostProcessor接口,在初始化前后进行处理;检查是否实现InitializingBean接口和init-method方法在初始化时进行自定义操作。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值