何为Spring生命周期
Bean的生命周期
对于一个Bean的生命周期,其实非常简单,无非就是从创建对象到销毁的过程,但是Spring作为一个可扩展的框架,其在Bean的创建和销毁过程中加入了非常多的扩展点,这也是为什么Spring能够蓬勃发展至今的一个原因。Bean的生命周期大体可以总结为以下几个阶段:
- Bean的定义
- Bean的注册
- Bean的创建
- Bean的注入
- Bean的初始化
- Bean的销毁
生命周期图
生命周期的流程
1. Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化
2. Bean实例化后将Bean的引入和值注入到Bean的属性中
3. 如果Bean实现了BeanNameAware接口的话,Spring将Bean的id传递给setBeanName()方法
BeanNameAware的作用:让Bean获取自己在BeanFactory配置中的名字。4. 如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
BeanFactoryAware的作用:让Bean获取配置他们的BeanFactory的引用。5. 如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入
为什么使用ApplicationContextAware接口:在spring项目中,类之间的关系是spring容器来管理的,但是一个项目中有些类不受spring容器管理缺需要使用受spring管理的bean,这时候不能通过正常的方式注入bean,这时候spring给我们提供了ApplicationContextAware接口,我们可以编写一个工具类来实现ApplicationContextAware,通过工具类来获取我们需要的bean然后供不在spring容器中的类调用。6. 如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法
postProcessBeforeInitialization()方法:初始化方法之前调用7. 如果Bean实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用
afterPropertiesSet()方法:初始化方法。如果使用了init-method声明了初始化方法,则执行顺序为:先执行afterPropertiesSet()方法,再执行init-method声明的方法。8. 如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法
postProcessAfterInitialization()方法:初始化方法之后调用9. 此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁
10. 如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用
destory()方法:销毁前调用。如果使用了destory-method声明了销毁方法,则执行顺序为:先执行destory()方法,再执行destory-method声明的方法。
Spring Bean的单列与多列的作用域
单例模式(Singleton):
单例是指在整个应用程序上下文中只创建一个实例,并且所有的请求都会返回同一个实例
默认情况下,Spring容器中的Bean都是单例的
单例模式适用于那些不需要维护状态的Bean,或者对资源消耗较大的Bean进行共享
缺点:使用单例会有变量污染,单例是根据spring上下文初始化;容器生对象生,容器死对象死多例模式(Prototype):
多例是指每次请求时都会创建一个新的实例,每个实例都是独立的
每次从容器中获取该Bean时,都会创建一个新的实例
多例模式适用于那些需要维护状态的Bean,或者对资源消耗较小的Bean进行独立创建
缺点:使用多例及其消耗内存,多例使用时候才会创建,销毁跟着jvm走。
单例Bean的配置方式
注解方式
// 使用注解配置单例Bean @Component @Scope("singleton") public class MySingletonBean { // ... } // 使用注解配置多例Bean @Component @Scope("prototype") public class MyPrototypeBean { // ... }
XML方式
<!-- 使用XML配置单例Bean --> <bean id="paramAction" class="com.zking.beanlife.ParamAction" scope="singleton"> <!-- ... --> </bean> <!-- 使用XML配置多例Bean --> <bean id="paramAction" class="com.zking.beanlife.ParamAction" scope="prototype"> <!-- ... --> </bean>
单列案列
先建一个类,创建它的三种方法
package com.zking.beanlife; public class InstanceFactory { public void init() { System.out.println("初始化方法"); } public void destroy() { System.out.println("销毁方法"); } public void service() { System.out.println("业务方法"); } }
后端Servlet
package com.zking.beanlife; import java.util.List; public class ParamAction { private int age; private String name; private List<String> hobby; private int num = 1; // private UserBiz userBiz = new UserBizImpl1(); public ParamAction() { super(); } public ParamAction(int age, String name, List<String> hobby) { super(); this.age = age; this.name = name; this.hobby = hobby; } public void execute() { // userBiz.upload(); // userBiz = new UserBizImpl2(); System.out.println("this.num=" + this.num++); System.out.println(this.name); System.out.println(this.age); System.out.println(this.hobby); } }
测试类
package com.zking.beanlife; import org.junit.Test; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; /* * spring bean的生命週期 * spring bean的單例多例 */ public class Demo2 { // 体现单例与多例的区别 @Test public void test1() { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml"); // InstanceFactory instanceFactory = (InstanceFactory) applicationContext.getBean("instanceFactory"); // ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml"); ParamAction p1 = (ParamAction) applicationContext.getBean("paramAction"); ParamAction p2 = (ParamAction) applicationContext.getBean("paramAction"); // System.out.println(p1==p2); p1.execute(); p2.execute(); // 单例时,容器销毁instanceFactory对象也销毁;多例时,容器销毁对象不一定销毁; applicationContext.close(); } // 体现单例与多例的初始化的时间点 instanceFactory @Test public void test2() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml"); } // BeanFactory会初始化bean对象,但会根据不同的实现子类采取不同的初始化方式 // 默认情况下bean的初始化,单例模式立马会执行,但是此时XmlBeanFactory作为子类,单例模式下容器创建,bean依赖没有初始化,只有要获取使用bean对象才进行初始化 @Test public void test3() { // ClassPathXmlApplicationContext applicationContext = new // ClassPathXmlApplicationContext("/spring-context.xml"); Resource resource = new ClassPathResource("/spring-context.xml"); BeanFactory beanFactory = new XmlBeanFactory(resource); // InstanceFactory i1 = (InstanceFactory) beanFactory.getBean("instanceFactory"); } }
Spring Config文件配置