Bean的作用域,生命周期和注解
eotteon__ireum 人气:0Bean的作用域
singleton作用域
当将bean的scope设置为singleton
时,Spring IoC容器仅生成和管理一个Bean实例(单例)。使用id或name获取Bean实例时,IoC容器将返回共享的Bean实例。
由于singleton是scope(范围)的默认方式,因此有两种方式将bean的scope设置为singleton。配置文件示例代码如下:
<bean id="constructorInstance" class="instance.BeanClass"/> 或 <bean id="constructorInstance" class="instance.BeanClass" scope="singleton"/>
测试singleton作用域,代码如下:
//初始化Spring容器ApplicationContext,加载配置文件 ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml"); //测试构造方法实例化Bean BeanClass b1 = (BeanClass)appCon.getBean("constructorInstance"); System.out.println(b1); BeanClass b2 = (BeanClass)appCon.getBean("constructorInstance"); System.out.println(b2);
prototype作用域
当bean的scope设置为prototype(原型)时,Spring IoC容器将为每次请求创建一个新的实例。如果将3.3.1中bean的配置修改如下:
<bean id="constructorInstance" class="instance.BeanClass" scope="prototype"/>
Bean的生命周期
Bean的生命周期整个过程如下:
1.根据Bean的配置情况,实例化一个Bean。
2.根据Spring上下文对实例化的Bean进行依赖注入,即对Bean的属性进行初始化。
3.如果Bean实现了BeanNameAware接口,将调用它实现的setBeanName(String beanId)方法,此处参数传递的是Spring配置文件中Bean的ID。
4.如果Bean实现了BeanFactoryAware接口,将调用它实现的setBeanFactory()方法,此处参数传递的是当前Spring工厂实例的引用。
5.如果Bean实现了ApplicationContextAware接口,将调用它实现的setApplicationContext(ApplicationContext)方法,此处参数传递的是Spring上下文实例的引用。
6.如果Bean关联了BeanPostProcessor接口,将调用预初始化方法postProcessBeforeInitialization(Object obj, String s)对Bean进行操作。
7.如果Bean实现了InitializingBean接口,将调用afterPropertiesSet()方法。
8.如果Bean在Spring配置文件中配置了init-method属性,将自动调用其配置的初始化方法。
9.如果Bean关联了BeanPostProcessor接口,将调用postProcessAfterInitialization(Object obj, String s)方法,由于是在Bean初始化结束时调用After方法,也可用于内存或缓存技术。
以上工作(1至9)完成以后就可以使用该Bean,由于该Bean的作用域是singleton,所以调用的是同一个Bean实例。
10.当Bean不再需要时,将经过销毁阶段,如果Bean实现了DisposableBean接口,将调用其实现的destroy方法将Spring中的Bean销毁。
11.如果在配置文件中通过destroy-method属性指定了Bean的销毁方法,将调用其配置的销毁方法进行销毁。
1.创建Bean的实现类
package life; public class BeanLife { public void initMyself() { System.out.println(this.getClass().getName() + "执行自定义的初始化方法"); } public void destroyMyself() { System.out.println(this.getClass().getName() +"执行自定义的销毁方法"); } }
2.配置Bean
在Spring配置文件中,使用实现类BeanLife配置一个id为beanLife的Bean。具体代码如下:
<!-- 配置bean,使用init-method属性指定初始化方法,使用 destroy-method属性指定销毁方法--> <bean id="beanLife" class="life.BeanLife" init-method="initMyself" destroy-method="destroyMyself"/>
3.测试生命周期
在ch3应用的test包中,创建测试类TestLife,具体代码如下:
//初始化Spring容器,加载配置文件 //为了方便演示销毁方法的执行,这里使用ClassPathXmlApplicationContext //实现类声明容器 ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); System.out.println("获得对象前"); BeanLife blife = (BeanLife)ctx.getBean("beanLife"); System.out.println("获得对象后" + blife); ctx.close();//关闭容器,销毁Bean对象
Bean的装配方式
Bean的装配可以理解为将Bean依赖注入到Spring容器中,Bean的装配方式即Bean依赖注入的方式。Spring容器支持基于XML配置的装配、基于注解的装配以及自动装配等多种装配方式。本节将主要讲解基于XML配置的装配和基于注解的装配。
基于XML配置的装配
package assemble; import java.util.List; import java.util.Map; import java.util.Set; public class ComplexUser { private String uname; private List<String> hobbyList; private Map<String,String> residenceMap;//Map存储键值对 private Set<String> aliasSet; private String[] array; //使用构造方法注入,需要提供带参数的构造方法 public ComplexUser(String uname, List<String> hobbyList, Map<String, String> residenceMap, Set<String> aliasSet, String[] array) { super(); this.uname = uname; this.hobbyList = hobbyList; this.residenceMap = residenceMap; this.aliasSet = aliasSet; this.array = array; } //使用setter方法注入,提供默认无参数的构造方法,并为注入的属性提供setter方法 public ComplexUser() { super(); } public void setUname(String uname) { this.uname = uname; } public void setHobbyList(List<String> hobbyList) { this.hobbyList = hobbyList; } public void setResidenceMap(Map<String, String> residenceMap) { this.residenceMap = residenceMap; } public void setAliasSet(Set<String> aliasSet) { this.aliasSet = aliasSet; } public void setArray(String[] array) { this.array = array; } @Override public String toString() { return "uname="+uname+";hobbyList="+hobbyList+";residenceMap="+residenceMap+";alisaSet="+aliasSet+";array="+array; } }
<!-- 使用构造方法注入方式装配ComplexUser实例user1 --> <bean id="user1" class="assemble.ComplexUser" > <constructor-arg index="0" value="chenheng1" /> <constructor-arg index="1"> <list> <value>唱歌</value> <value>跳舞</value> <value>篮球</value> </list> </constructor-arg> <constructor-arg index="2"> <map> <entry key="dalian" value="大连" /> <entry key="beijing" value="北京" /> <entry key="shanghai" value="上海" /> </map> </constructor-arg> <constructor-arg index="3"> <set> <value>陈恒100</value> <value>陈恒101</value> <value>陈恒102</value> </set> </constructor-arg> <constructor-arg index="4"> <array> <value>aaaaa</value> <value>bbbbb</value> </array> </constructor-arg> </bean> <!-- 使用setter方法注入方式装配ComplexUser实例user2 --> <bean id="user2" class="assemble.ComplexUser" > <property name="uname" value="chenheng2"></property> <property name="hobbyList"> <list> <value>看书</value> <value>学习Spring</value> </list> </property> <property name="residenceMap"> <map> <entry key="shenzhen" value="深圳"></entry> <entry key="guangzhou" value="广州"></entry> <entry key="tianjin" value="天津"></entry> </map> </property> <property name="aliasSet"> <set> <value>陈恒103</value> <value>陈恒104</value> <value>陈恒105</value> </set> </property> <property name="array"> <array> <value>ccccc</value> <value>ddddd</value> </array> </property> </bean>
package test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import assemble.ComplexUser; public class TestAssemble { public static void main(String[] args) { ClassPathXmlApplicationContext appCon=new ClassPathXmlApplicationContext("applicationContext.xml"); ComplexUser u1=(ComplexUser) appCon.getBean("user1"); //构造方法装配测试 System.out.println(u1); //setter方法装配测试 ComplexUser u2=(ComplexUser) appCon.getBean("user2"); System.out.println(u2); appCon.close(); } }
基于注解的装配
1.@Component
该注解是一个泛化的概念,仅仅表示一个组件对象(Bean),可以作用在任何层次上。
(1)创建Bean的实现类
package annotation; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component() /**相当于@Component("annotationUser")或@Component(value = "annotationUser"),annotationUser为Bean的id,默认为首字母小写的类名**/ public class AnnotationUser { @Value("chenheng")//只注入了简单的值,复杂值的注入目前使用该方式还解决不了 private String uname; public String getUname() { return uname; } public void setUname(String uname) { this.uname = uname; } @Override public String toString() { return "uname="+uname; } }
(2)配置注解
现在有了Bean的实现类,但还不能进行测试,因为Spring容器并不知道去哪里扫描Bean对象。需要在配置文件中配置注解,注解配置方式如下:
<?xml version="1.0" encoding="UTF-8"?> <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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 使用context命名空间,通过Spring扫描指定包下所有Bean的实现类,进行注解解析 --> <context:component-scan base-package="annotation" /> </beans>
(3)测试Bean实例
package test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import annotation.AnnotationUser; public class TestAnnoation { public static void main(String[] args) { ApplicationContext appcon=new ClassPathXmlApplicationContext("annotationContext.xml"); AnnotationUser au=(AnnotationUser) appcon.getBean("annotationUser"); System.out.println(au.getUname()); } }
2.@Repository
该注解用于将数据访问层(DAO)的类标识为Bean,即注解数据访问层Bean,其功能与@Component()相同。
3.@Service
该注解用于标注一个业务逻辑组件类(Service层),其功能与@Component()相同。
4.@Controller
该注解用于标注一个控制器组件类(Spring MVC的Controller),其功能与@Component()相同。
5.@Autowired
该注解可以对类成员变量、方法及构造方法进行标注,完成自动装配的工作。 通过 @Autowired的使用来消除setter 和getter方法。默认按照Bean的类型进行装配。
6.@Resource
该注解与@Autowired功能一样。区别在于,该注解默认是按照名称来装配注入的,只有当找不到与名称匹配的Bean才会按照类型来装配注入;而@Autowired默认按照Bean的类型进行装配,如果想按照名称来装配注入,则需要结合@Qualifier注解一起使用。
@Resource注解有两个属性:name和type。name属性指定Bean实例名称,即按照名称来装配注入;type属性指定Bean类型,即按照Bean的类型进行装配。
7.@Qualifier
该注解与@Autowired注解配合使用。当@Autowired注解需要按照名称来装配注入,则需要结合该注解一起使用,Bean的实例名称由@Qualifier注解的参数指定。
上面几个注解中,虽然@Repository、@Service和 @Controller等注解的功能与@Component()相同,但为了使标注类的用途更加清晰(层次化),在实际开发中推荐使用@Repository标注数据访问层(DAO层)、使用@Service标注业务逻辑层(Service层)以及使用@Controller标注控制器层(控制层)。
package annotation.dao; import org.springframework.stereotype.Repository; @Repository("testDao") /**相当于@Repository,但如果在service层使用@Resource(name="testDao")的话,testDdao不能省略**/ public class TestDaoImpl implements TestDao { @Override public void save() { // TODO Auto-generated method stub System.out.println("testDao save"); } }
package annotation.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import annotation.dao.TestDao; import jakarta.annotation.Resource; @Service("testService") public class TestServiceImpl implements TestService { @Autowired /**相当于@Autowired.@Autowired默认按照Bean类型装配**/ private TestDao testDao; @Override public void save() { // TODO Auto-generated method stub testDao.save(); System.out.println("testService save"); } }
package annotation.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import annotation.service.TestService; @Controller("testController") public class TestControllerImpl { @Autowired private TestService testService; public void save() { // TODO Auto-generated method stub testService.save(); System.out.println("testController save"); } }
<?xml version="1.0" encoding="UTF-8"?> <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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 使用context命名空间,通过Spring扫描指定包下所有Bean的实现类,进行注解解析 --> <context:component-scan base-package="annotation" /> </beans>
package test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import annotation.controller.TestControllerImpl; public class TestMoreAnnotation { public static void main(String[] args) { ApplicationContext appcon=new ClassPathXmlApplicationContext("annotationContext.xml"); TestControllerImpl testc=(TestControllerImpl) appcon.getBean("testController"); testc.save(); } }
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注的更多内容!
加载全部内容