1.什么是bean的生命周期
Bean的生命周期是指在Java中管理和控制一个Java对象(即Bean)从创建到销毁的整个过程。
Java中的Bean生命周期可以分为以下几个阶段:
- 实例化(Instantiation):在此阶段,容器创建了一个Bean的实例。这可以通过构造函数、工厂方法或其他方式完成。
- 属性设置(Properties Setting):在实例化后,容器会设置Bean的属性值,可以通过依赖注入(DI)或其他方式完成。
- 初始化(Initialization):在属性设置完成后,容器会调用Bean的初始化方法,通常是调用Bean定义中指定的初始化方法。
- 使用(In Use):Bean已经被完全创建和初始化,可以使用了。这是Bean生命周期的长时期阶段。
- 销毁(Destruction):当Bean不再需要时,容器会调用Bean的销毁方法来执行一些清理工作,例如释放资源、关闭连接等。
Bean的生命周期由容器(例如Spring容器)负责管理,容器会在适当的时间点调用相应的方法。开发人员可以通过实现特定的接口或注解方式来定义Bean的初始化方法和销毁方法,以便在Bean生命周期的不同阶段执行自定义的逻辑。
Bean的初始化过程:
2.bean的单例与多例选择:
在Java中,Bean的单例模式和多例模式是两种常见的对象创建和管理方式。下面是它们的区别和适用场景:
- 单例模式(Singleton):
- 单例模式确保在整个应用程序中只创建一个Bean实例,并在需要时反复使用该实例。
- 适用于需要共享状态或资源的对象,以及需要频繁访问的对象实例。
- 在Spring中,默认情况下,Bean是单例的。
- 多例模式(Prototype):
- 多例模式允许每次请求时都创建一个新的Bean实例,每个实例都是独立的。
- 适用于每次请求需要一个独立的对象实例,或者对象状态需要在每次使用之间重置的情况。
- 在Spring中,可以通过在Bean定义中使用
@Scope("prototype")
注解或者XML配置来声明多例Bean。因此,当选择单例还是多例模式时,考虑以下因素:
- 对象状态:如果对象状态需要在每次使用之间重置或保持独立,则多例模式更合适。如果对象状态需要被全局共享或保持一致,则单例模式更适合。
- 资源消耗:如果Bean的创建和销毁过程较为昂贵,并且系统中只需要一个实例来共享资源,则使用单例模式可以节省资源。如果对象的创建和销毁成本较低,或者需要频繁创建和销毁实例,则多例模式可能更适合。
- 并发性:单例模式可以简化线程安全问题,因为只有一个实例需要处理并发访问。多例模式可能需要额外的措施来确保每个实例的线程安全性。
在实际开发中,根据具体需求和性能考虑,可以灵活选择适合的单例或多例模式来管理Bean。
准备好资源:
package com.zking.beanlife; import java.util.List; import com.YU.ioc.service.UserService; import com.YU.ioc.service.impl.UserServiceImpl1; import com.YU.ioc.service.impl.UserServiceImpl2; 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); } }
写好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("业务方法"); } }
配置Spring-context.xml
<!--spring的生命周期--> <bean class="com.YU.beanlife.ParamAction" id="paramAction"> <constructor-arg name="name" value="小红"></constructor-arg> <constructor-arg name="age" value="21"></constructor-arg> <constructor-arg name="hobby"> <list> <value>唱</value> <value>跳</value> <value>篮球</value> </list> </constructor-arg> </bean> <bean id="instanceFactory" class="com.YU.beanlife.InstanceFactory" scope="prototype" init-method="init" destroy-method="destroy"></bean>
demo测试:
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; public class Demo2 { // 体现单例与多例的区别 @Test public void test1() { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml"); // 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"); InstanceFactory instanceFactory = (InstanceFactory) applicationContext.getBean("instanceFactory"); } // 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"); } }
测试结果:
在什么场景下适合用单例和多例模式:
单例模式适用的场景:
- 全局共享对象:当应用程序中的多个组件需要共享相同的对象实例时,使用单例模式可以确保它们访问的是同一个实例,从而确保全局共享。
- 资源管理:当一个对象需要管理系统资源(例如数据库连接、线程池等)时,使用单例模式可以避免频繁创建和销毁资源,从而提高资源利用率。
- 配置信息:当一个对象需要读取和缓存应用程序的配置信息时,单例模式可以确保对象只加载一次配置信息,并在整个应用程序中共享。
多例模式适用的场景:
- 独立对象状态:当需要每次使用时都获得一个全新的对象实例,并且每个实例都有独立的状态时,多例模式是一个合适的选择。例如,创建多个游戏角色实例或网络连接实例等。
- 临时对象:当对象只用于短暂的临时操作且没有长期的共享需求时,使用多例模式可以避免资源浪费。例如,创建临时的工具类对象或临时缓存对象等。
- 并发性:当多个线程需要同时使用一个对象,并且需要保持线程间的隔离和独立状态时,多例模式可以提供每个线程独立的对象实例,避免线程安全问题。
总结而言,使用单例模式适合全局共享、资源管理和配置信息等场景。使用多例模式适合独立对象状态、临时对象和并发性等场景。具体应用中需要根据需求综合考虑对象共享和资源利用等因素来选择适当的模式。