1.项目准备
回顾
新建接口com.tools.Axe,并新建该Axe接口的实现类com.tools.impl.StoneAxe:
1 2 3 4 5
| package com.tools;
public interface Axe { void chop(); }
|
1 2 3 4 5 6 7 8
| package com.tools.impl; import com.tools.Axe;
public class StoneAxe implements Axe { public void chop() { System.out.println("用石斧砍柴。"); } }
|
在main/java目录中,新建类com.service.Person:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package com.service; import com.tools.Axe;
public class Person { private Axe axe;
public void setAxe(Axe axe) { this.axe = axe; }
public void useAxe(){ if (axe == null){ System.out.println("斧头不存在!"); return; } axe.chop(); } }
|
新建测试类com.service.PersonTest:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package com.service; import com.tools.Axe; import com.tools.impl.StoneAxe; import org.junit.Test;
public class PersonTest { @Test public void useAxeTest(){ Person person = new Person(); Axe axe = new StoneAxe(); person.setAxe(axe); person.useAxe(); } }
|
测试结果为:
创建第二个实现类,添加一个铁斧类com.tools.impl.SteelAxe:
1 2 3 4 5 6 7
| package impl; import tools.Axe; public class SteelAxe implements Axe { public void chop() { System.out.println("用铁斧砍柴。"); } }
|
引言
*能否有一个斧头工厂,提供各种型号的斧头(而非斧头图纸)供樵夫选用,从而降低樵夫使用斧头的成本?*
2.基于XML的装配
Maven依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.3.16</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.16</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>5.3.16</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>5.3.16</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> </dependencies>
|
bean.xml配置文件
main/resources目录中新一个config目录,并在该目录中,创建Spring框架的配置文件applicationContext.xml文件
1 2 3 4 5 6 7 8 9 10 11
| <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="axe" class="com.example.javaee_test05.tools.impl.StoneAxe"/> <bean name="person" class="com.example.javaee_test05.service.Person"/> </beans>
|
bean对象测试
创建一个新的测试类对象AxeTest
1 2 3 4 5 6 7
| public void AxeTest(){ ApplicationContext context= new ClassPathXmlApplicationContext("config/applicationContext.xml"); Person person = (Person) context.getBean("person"); Axe axe =(Axe)context.getBean("axe"); person.setAxe(axe); person.useAxe(); }
|
3.基于注解的装配
修改配置文件
在上述的基础上,将beam.xml中的bean对象修改为包扫描类
1 2 3 4 5 6 7 8 9 10 11 12
| <?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-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd "> <context:component-scan base-package="com.example.javaee_test05.tools.impl" /> <context:component-scan base-package="com.example.javaee_test05.service" /> </beans>
|
添加注解
在类对象中为其添加注解,在类前加上Component注解,其中括号中为调用的名称
1 2 3 4 5 6 7 8 9 10
| @Component("person") public interface Person { void usePen(); } 、、、 @Component("arithmetic")
、、、 @Component("axe")
|
| 元素名 |
描述 |
| @Component |
标注在类上,用于描述一个需要由 Spring装配的 Bean。@Component 注解有一个默认属性value,通过该属性可以指定装配到IoC 容器中的 Bean 实例名,如 @Component (value=”实例名”)或@Component (“实例名”) |
| @Repository |
功能与@Component相同,通常标注数据访问层的类 |
| @Service |
功能与@Component 相同,通常标注业务层的类 |
| @Controller |
功能与@Component相同,通常标注控制层的类 |
| @Autowired |
可标注 Bean 的属性,也可标注 setter 或构造方法的形参,用于按类型注入属性值。该注解也可以在@Qualifer注解的协助下,按 Bean实例名称注人,实例名由注解 @Qualier 确定,如@Qualier (“实例名”) |
| @Resource |
其功能与@Autowired注解类似,包括name和type两个属性:name属性用于指定要注人的Bean实例名即按名称注人;type属性用于指定要注人的 Bean 类型,即按类型注人。若两个属性都未指定,则优先按属性名匹配IoC容器中的 Bean实例名;若不能匹配,再按属性类型匹配 |
其中经常使用的为**@Component和@Autowired**两种,其中的@Component可以代替其中的@Repository、@Service、@Controller等可以互相使用。
其中使用@Autowired注解时,例如出现多个自动装配对象,需要使用@Qualier(“”)来指定其中的需要装配的对象,例如:
1 2 3
| @Autowired @Qualier(value="StoneAxe") private Axe axe;
|
这里根据StoneAxe类构建出一个Axe类的实现类StoneAxe,使用Qualier的前提是有多个实现Axe的对象方法则需要指定其中的value值。
测试用例
1 2 3 4 5 6 7 8
| @Test public void useAxeTest(){ ApplicationContext context= new ClassPathXmlApplicationContext("config/applicationContext.xml"); Person person = context.getBean(Person.class); Axe axe =(Axe)context.getBean(Axe.class); person.setAxe(axe); person.useAxe(); }
|
输出结果
总结
1
| <context:component-scan base-package="com.example.javaee_test05.tools.impl" />
|
1 2
| <bean id="axe" class="com.example.javaee_test05.tools.impl.StoneAxe"/> <bean name="person"
|
这两种方式配置出的原理是一样的,上面的方法对包中的所有带有@Component注解的类名自动扫描并且为其赋值唯一标识,下面的方法直接对类进行id赋值唯一标识扫描,其中包扫描的方法简化了存在多个Bean对象的冗余度。
4.基于配置类的装配
装配方式
基于配置类的装配是配置类及注解相结合的装配方式,该方式可以完全脱离对 XML配置文件的依赖,是Spring Boot建议使用的装配方式。基于配置类的装配需要涉及两个重要的注解:
@Configuration和@Bean
@Configuration 用于标注一个类是一个配置类,Spring能够自动扫描并装配配置类,@Configuration 和@Component 注解的作用类似。
@Bean 注解用于标注配置类中的某个方法是创建 Bean实例的方法, @Bean 注解标注的方法与XML配置文件中 元素的功能类似。
创建config/AppConfg.java文件
1 2 3 4 5 6 7 8 9 10
| @Confiquration @ComponentScan(basePackages = { "com.example.javaee_test05.service", "com.example.javaee_test05.controller" }) public class AppConfig { @Bean(name="bookService”) public BookService bookService(@Autowired Book book)[ BookServiceImpl bookServiceImpl = new BookServiceImpl(); bookServiceImpl.setBook(book); return bookServiceImpl; } }
|
第1行的 @Configuration 注解用于标注 AppConfig类是一个配置类,Spring IoC 容器以其作为装配Bean的依据。
第2行的@ComponentScan 注解用于指定自动扫描的包路径,可以指定多个扫描的包路径,功能Spring配置文件中的<context;component-scan/>元素类似。
第4行的@Bean 注解用于标注 bookService 方法,其含义是将 bookService 方法返回的对象将bookService实例名被装配到loC容器中。Bean在容器中的实例名由@Bean注解的属性name指定,缺省时取bookService0方法的名称作为 Bean的实例名。
第5行的@Auowired注解用于标注形参,其含义是该形参 book 在装配 bookService实例时被注入。
基于XML配置文件、注解及配置类的装配,是开发人员可选择的 Bean 装配方式,这些装配策略虽然各具特色,但也相互依存。例如,单纯的注解难以装配第三方 Bean,需要 XML或配置类的支持也需要通过 <context;component-scan/>元素或 @ComponentSean 注解配置扫描策略。因此,扫描装配常只适合项目中定义的类,对于JDK或Spring框架中定义的类,无法自动扫描装配,仍需要通过XML配置文件或Java配置类方式将其装配到SpringloC容器中。
Bean的使用方法
将 Bean 装配到IoC容器后,接下来就是获取 Bean 实例。
ApplicationContext 接口定义了 getBean0。较常用的方法主要有两个:以下展示为bookService1和bookService这两种
1 2 3
| ApplicationContext applicationContext = new Annotat ionConfigApplicationContext (AppConfig.class) ; BookService bookServicel = (BookService)applicationContext.getBean("bookServiceImpl"); BookService bookService = applicationContext.getBean(BookServiceImpl.class);
|
第1行以AppConig 配置类启动 IoC容器,这里用到了ApplicationContext 接口的实现类 Annotation ConfigApplicationContexto
第2行按引用名bookServicelmpl从IoC容器中获取 Bean实例,该方法的原型为“Object getBean( Strings);”,因此,在赋值前需要强制类型转换。
第3行按类型从IoC容器中获取 Bean实例,该方法是一个范型方法,其原型为“T getBean(ClassaClass);”,因此,不需要强制类型转换便可赋值。
值得注意的是,当IoC 容器中装配了多个同类型的 Bean 实例时,按类型获取 Bean 的方法将不再适用。
5.依赖注入
引言
在Spring项目中,Bean之间通常不是独立的,或多或少会存在着一些联系,如 BookService类需要PublisherService类提供出版方面的服务。因此,装配到Spring loC 容器中的 BookService实例要具有版方面的能力,就要将 PublisherService实例注人 BookService 实例中。为了解决这类问题,Spring框l在装配 Bean时提供了依赖注人功能,并支持XML配置文件注人和注解注人两种方法。
Spring 支持两种基于XML 的依赖注入方式,即设值注入 ( Seler lnjeetion)和构造注人 (Construclowjection),。设值注入是在 Bean 实例化后、由容器调用Bean 实的万法注入属性值,因此要求Bean 必须具备两个条件
无参构造方法和用于设值注入的set法。
setter 方法
selter 注人是通过配置 元素的 子元素实现的
在Service包中创建 ClassService 和 StudentService 类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class ClassService { private String classNo; private String className; private String major; }
public class StudentService{ private String sno; private String sname; private ClassService classService; private List<Float> scoreList; private Set<String> interest; private Map<string, String> other;
}
|
为确保 seter 注人成功,需要给 ClassService 和 StdentService 的所有属性成员添加 setter 方法和无参构造方法
方法一:XML注入
在 main/resources/config文件夹中创建 XML 配置文件 beansxml。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| <bean name="classService" class="com.example.javaee_test05.service.ClassService"> <property name="classNo" value="2215711"/> <property name="className"value="22级软件工程1班"/> <property name="major" value="软件工程"/> </bean> <bean name="studentService" class="com.example.javaee_test05.service.studentService"> <property name="sno" value="221571101"/> <property name="sname" value="张晓媛"/> <property name="classService" ref="classService"/> <property name="scoreList"> <list> <value>89.5</value> <value>78.0</value> <value>84.0</value> </list> </property> <propertyname="interest"> <set> <value>篮球 </value> <value>爬山</value> <value>跳绳 </value> </set> </property> <property name="other"> <map> <entry key="mobile" value="13588886666"/> <entry key="QQ"value="5874587"/> <entry key="address"value="广东省广州市"/> </map> </property> </bean> <beans>
|
配置了 ClassService 的实例,用 元素注人了3个属性 元素中,name 属性用于指定被注入的属性名,vaue 属性用于指定简单的数据类,即包括Java 语言基本数据类型、String 以及基本数据类型的包装器 (wrapper)类型,如 nteger、Float、Double等。
这里用到了 元素的 ref属性,该属性用于指定一个对象的引用;
利用 元素注人了 3 个列表元素值,每个列表元素值由一个 子元素表示;
利用 子元素注人了3 个集合元素值,每个集合元素值也是由一个子元素表示的:
利用
测试
在test/java目录中创建测试方法 XmlInjectionTest
1 2 3 4 5 6 7 8 9
| public class XmlInjectionTest{ @Test public void xmlInjectionTest(){ ApplicationContext ac= new ClassPathXmlApplicationContext("config/beans.xml"); StudentService studentService = ac.getBean(studentService.class); System.out.println(studentService); } }
|
运行测试方法
1
| StudentService{sno='221571101',sname='张晓媛',classService=ClassService{classNo='2215711',className='22级软件工程1班',smajor='软件工程'},scoreList=[89.5,78.0,85.0],interest=[蓝球,爬山,跳绳],other={mobile=13588886666,QQ=5874587,address=广东省广州市}}
|
方法二:构造方法注入
与XML注入的不同点在于配置文件中的信息书写方式不同,与 setter 方法注入的配置文件相比,只需将 bean/> 元素中的所有 property/>子元素替换成 子元素,便可实现构造方法注入的配置。此外,元素比元素多了一个index 属性,该属性可替代 name 属性表示构造方法的形参,index 的取值为大于等于0的整数,0表示第 1个形参,1 表示第 2个形参,以此类推。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| <bean name="classService" class="com.example.javaee_test05.service.ClassService"> <constructor-arg name="classNo" value="2215711"/> <constructor-arg name="className"value="22级软件工程1班"/> <constructor-arg name="major" value="软件工程"/> </bean> <bean name="studentService" class="com.example.javaee_test05.service.studentService"> <constructor-arg name="sno" value="221571101"/> <constructor-arg name="sname" value="张晓媛"/> <constructor-arg name="classService" ref="classService"/> <constructor-arg name="scoreList"> <list> <value>89.5</value> <value>78.0</value> <value>84.0</value> </list> </constructor-arg> <constructor-argname="interest"> <set> <value>篮球 </value> <value>爬山</value> <value>跳绳 </value> </set> </constructor-arg> <constructor-arg name="other"> <map> <entry key="mobile" value="13588886666"/> <entry key="QQ"value="5874587"/> <entry key="address"value="广东省广州市"/> </map> </constructor-arg> </bean> <beans>
|
方法三:注解的依赖注入
在 main/resources 建立属性文件 data.properties
1 2 3 4 5
| student.sno-221571101 student.sname=张晓媛 student.scores=89.5,78.0,84.0 student.interest=篮球,爬山,跳绳 student.other={“mobile":"13588886666","oo":"s874587","address":"广东省广州市"}
|
以键-值对的格式定义了一些数据,这些数据用于依赖注人。其中,第 1、2是字符串类型数据(注意,不需要双引号),其他基本类型数据也可按此格式定义;第 3、4行定义以号分的集合数据,可注入给数组(Amay)、列表(Lit)或合(St)等类的属性;第 行Map 类型的数据,每个数据以“键:值”的格式定义,位于大括号中,以逗号分割。
或者另一种直接注入的方式:
创建service 包ClassService和StudentService类
1 2 3 4 5 6 7 8 9 10
| @Component public class ClassService { @Value("2215711") private String classNo; @Value(”22 级软件工程1班”) private String className; @Value(“软件工程”) private String major; }
|
第 3行 @Component 注 解 装 配 ClassService 类到IC容器中,Bean 实例名为 cassServiceClassService 的3个属性均使用@Value 注解标注,@Value 可以给属性注人字符串或基本类型的数据@Value 注解的作用是将括号中的字符串赋值给被标注的属性,等价于直接给属性赋值。
或者在上述文件中取值(StudentService.java):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Component @PropertySource(value="classpath:data.properties",encoding = "utf-8") public class StudentService { @Value("${student.sno}") private String sno; @Value("${student.sname}") private String sname; @Autowired private ClassService classService; @Value("#{'$student.scores}'.split (',')}") private List<Float> scoreList; @Value("#{'$student.interest)'.split(',')}") private Set<String> interest; @Value("#{'${student.other}}") private Map<String,String> other; }
|
第4行的 @PropertySource 注解用于加属性文件,注解的 value 属性指定被加的属性文件路径,encoding属性指定文件的编码方式,以避免中文乱码问题。第6行和第8行分别从属性文件 dataproperties 中注人了 student.sno和 student.sname, 注意注入格式为$[.·.。第10行采用@Autowired注解按类型注人了IoC 容器中的 Bean 实例 classService,这里也可以使用 @Resource 注解,如按 Bean实例名注人 @Resource(name=”classService”)或按类型注入 @Resource(type=ClassServiceclass)。第12行和第14行注人集合数据 student.scores 和 student.interest,注意这里使用了 split()方法对注人的字符串进行分割,这种注人方法也适合数组类型。第 16行注人了 Map 数据。
使用 @Value 注解注人属性文件中定义的数据,应用较为广泛,请读者注意注入语法格式。在属性前使用@Autowired 和@Resource 注解,相当于 setter 注人,但 Spring不要求在类中定义 seter 方法,这与XML方式的 setter 注人是不同的。实际上,也可按构造方法注入属性,如代码“public StdentService(@Autowired ClassService classService) (this.classService=classService;)”可替代第 10行的 @Autowired注解。显然当需要注人的属性很多时,使用构造方法注人相对麻烦,而 setter 方法注人则比较方便。构造方法注入的作用与 setter 方法的作用基本相似,只是在注人时机略有差异,构造方法注人是在对象被构造时完成的而setter方法注人则在对象被构造后,再调用 setter 方法注人,时间上稍晚于构造方法注人。注意,@Autowired 和 @Resource 注解只对单个属性起作用,即每个需要注入的属性都需要用@Autowired 或 @Resource 注解标注。
测试
创建配置扫描类 config.AppConfig
1 2 3 4
| @Confiquration @ComponentScan(basePackages = "com.example.javaee_test05.service") public class AppConfig { }
|
在 main/test 中新建测试包
1 2 3 4 5 6 7 8
| public class ConfigAnnotationTest { @Test public void configAnnotationTest(){ ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class); StudentService studentService = ac.getBean(StudentService.class); System.out.println(studentService.tostring()); } }
|
6.Bean的作用域
常见的作用域
Bean 的作用域决定了 Bean实例在项目中的可见性,只有当前可见的 Bean,才能从 Spring IoC容器中获得并使用。
| 作用域名称 |
说明 |
| singleton |
单例作用域,是IoC容器的默认作用域。由ngleton作用域定义的 Bean,在IoC容器中只有一个实例,在 IoC 容器启动时被实例化,该实例可被多次引用(或获取 ,每次引用(或获取)的实例相同。` |
| prototype |
原型作用域,由 prototype作用域定义的 Bean,在引用(或取)时被创建,因此,每次引用(或获取)的实例是不同的。 |
| request |
用于 Web 环境,由 request 作用域定义的 Bean,在同一 HTTP 请求中,多次引用的实例是相同的在不同 HTTP 请求中,引用的实例是不同的 |
| session |
用于 Web 环境,由 session 作用域定义的 Bean,在同一 HTTP 会话中,多次引用的实例是相同的;在不同 HTTP 会话中,引用的实例是不同的 |
上述4种作用域中,singleton 和 prototype 是最常用的,
方法一:基于 XML 配置文件的作用城配置
创建ClassService.java、TeacherService.java、StudentService.java三个类文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package com.javaee.ex04.service; public class ClassService{ private String classNo; private String className; private String major; }
package com.javaee.ex04.service; public class TeacherService { private ClassService classService; }
package com.javaee.ex04.service; public class StudentService { private String sno; private String sname; private ClassService classService; }
|
在Beans.xml文件中添加以下配置属性
1 2 3 4 5 6 7
| <bean name="classService" class="com.javaee.ex04.service.ClassService" scope="prototype"/> <bean name="teacherService" class="com.javaee.ex04.serviceTeacherService" scope="prototype"> <property name="classService" ref="classService"/> </bean> <bean name="studentService" class="com.javaee.ex04.service.StudentService" scope="singleton"> <property name="classService" ref="classService"/> </bean>
|
在XML 配置文件中,Spring 采用元素的 scope 属性设置 Bean 的作用域,
测试
在test/java中创建测试类XmlScopeTest
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package com. javaee. ex04;
public class XmlScopeTest { @Test public void xmlScopeTest(){ ApplicationContext ac = new ClassPathXmlApplicationContext("config/beans. xml"); ClassService classService1 = ac. getBean(ClassService. class); ClassService classService2 = ac. getBean(ClassService. class); TeacherService teacherService1 = ac. getBean(TeacherService. class); TeacherService teacherService2 = ac. getBean(TeacherService. class); StudentService studentService1 = ac. getBean(StudentService. class); StudentService studentService2 = ac. getBean(StudentService. class); System. out. println("classService1:" + classService1); System. out. println("classService2:" + classService2); System. out. println("teacherService1:" + teacherService1); System. out. println("teacherService2:" + teacherService2); System. out. println("studentService1:" + studentService1); System. out. println("studentService2:" + studentService2); System. out. println("teacherService1. classService: " + teacherService1.getClassService()); System. out. println("teacherService2. classService: " + teacherService2.getClassService()); System. out. println("studentService1. classService:" + studentService1.getClassService()); System. out. println("studentService2. classService:" + studentService2.getClassService()); } }
|
测试结果
1 2 3 4 5 6 7 8 9 10
| classService1:com.javaee.ex05.service.ClassService@221a3fa4 classService2:com.javaee.ex05.service.ClassService@451001e5 teacherService1:com.javaee.ex05.service.TeacherService@2b40ff9c teacherService2:com.javaee.ex05.service.TeacherService@3e08ff24 studentService1:com.javaee.ex05.service.StudentService@4d1c005e studentService2:com.javaee.ex05.service.StudentService@4d1c005e teacherService1.classService: com.javaee.ex05.service.ClassService@8462f31 teacherService2.classService: com.javaee.ex05.service.ClassService@24569dba studentService1.classService:com.javaee.ex05.service.ClassService@5ddeb7cb studentService2.classService:com.javaee.ex05.service.ClassService@5ddeb7cb
|
方法二:基于注解的作用域配置
在方法一中ClassService、TeacherService 和 StudentService 类创建之前添加作用域的注解配置
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Service @Scope (ConflgurableBeanFactory.SCOPE PROTOTYPE) public class ClassService { private String classNo; private String className; private String major; } @Service @Scope (ConflgurableBeanFactory.SCOPE PROTOTYPE)
@Service @Scope (ConflgurableBeanFactory.SCOPE SINGLETON)
|
使用 @Scope 注解将 ClassService 和 TeacherService类的实例作用域设为prototype,将StudentService类的实例作用域设为singleton。设置时使用了接口 ConfigurableBeanFactory的常量属性。由于 singleton 是默认作用域,因此,第27 行的 @Scope 注解是可以省略的。
新建配置类 comjavaee.ex04.config.AppConfig
1 2 3 4 5
| package com.javaee.ex04.config; @ComponentScan(basePackages = "com.javaee.ex04.service") @Configuration public class AppConfig{ }
|
生命周期总结
loC 容器中所有的 Bean 都会经历从创建到消亡的过程,这一过程便是 Bean 的生命周期。了解Bean 的生命周期,不仅能够更加深入理解 Bean 在容器中的活动状态,而且还可以在 Bean 生命周期的某个阶段执行特定的操作,如文件访问类的 Bean 实例在销毁前应执行关闭(Close)操作。对于 singleton作用域的 Bean 实例,IoC 容器将负责 Bean 的实例化、注人、初始化、引用及销毁等阶段的管理。对于 prototype 作用域的 Bean 实例,loC 容器仅负责实例化、注入及初始化阶段的管理将Bean 实例交给使用者后,将不再跟踪 Bean 实例的生命周期,Bean 何时销毁,由使用者决定。
