- 🤪个人主页:i笨笨i
- 🐽版权:本文由【i笨笨i】原创,需要转载联系博主
- 🎉欢迎关注、点赞、收藏(一键三连)和订阅专栏哦!
一、Spring介绍
Spring 使创建 Java 企业应用程序变得更加容易。它提供了在企业环境中接受 Java 语言所需的一切,,并支持 Groovy 和 Kotlin 作为 JVM 上的替代语言,并可根据应用程序的需要灵活地创建多种体系结构。 从 Spring Framework 5.0 开始,Spring 需要 JDK 8(Java SE 8+),并且已经为 JDK 9 提供了现成的支持。
Spring支持各种应用场景, 在大型企业中, 应用程序通常需要运行很长时间,而且必须运行在 jdk 和应用服务器上,这种场景开发人员无法控制其升级周期。 其他可能作为一个单独的jar嵌入到服务器去运行,也有可能在云环境中。还有一些可能是不需要服务器的独立应用程序(如批处理或集成的工作任务)。
Spring 是开源的。它拥有一个庞大而且活跃的社区,提供不同范围的,真实用户的持续反馈。这也帮助Spring不断地改进,不断发展。
二、传统方式创建对象弊端
2.1、案例
public class BookService{
private BookDao bookDao = new BookDao();
public void setup() {
System.out.println("book service setup ...");
}
}
2.2、问题分析
按照以前做法,BookService对象要依赖BookDao对象,一个明显的问题是:耦合度高,一旦BookDao代码修改要重新编译。
- 解决方法
解耦合。将类实例化交给外部去做,自己只关注对象的使用,使用IoC思想。
三、IoC(控制反转)/DI(依赖)
3.1、IoC(Inversion of Control)控制反转
使用对象时,在程序中不要主动使用new产生对象,转换为由外部提供对象。
- Spring技术对IoC思想进行了实现
Spring提供了一个容器,称为IoC容器,用来当作IoC思想中的外部
IoC容器负责对象的创建、初始化等一系列工作,被创建或管理的对象在IoC容器中统称为Bean。
- IoC代码实现
初级实现方式:导入jar包+配置XML
中级实现方式:Maven+注解+XML
高级实现方式:SpringBoot+javaConfig
3.2、DI(Dependency Injection)依赖注入
在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入。
- 使用IoC容器和DI,想要达到的效果
使用对象时,不仅可以从IoC容器中直接获取,并且取到的bean已经绑定了所有的依赖关系。
3.3、生活化案例
人们在以前的生活中,想要喝西瓜汁;首先准备好西瓜、榨汁机、冰镇水。值得注意的是:这些原材料都是自己亲自准备的。
外卖开始兴起后,当我们想喝西瓜汁时,首先想通过外卖平台上的饮品店购买一杯西瓜汁,购买后给商家自己的地址,联系方式,姓名等,过一会就有人送来一杯西瓜汁了。
此时,自己并没有主动做西瓜汁,西瓜汁是由饮品店做的,但是最后你也成功喝到了西瓜汁,甚至西瓜汁里还可以添加其他东西,你只需要付出一点代价。
3.4、总结
IoC和DI是从不同的角度描述的同一件事情,IoC是从容器角度描述,而DI是从应用程序的角度来描述。IoC是依赖倒置原则的设计思想,而DI是具体的实现方式。
四、入门案例
以BookDao类为例,初试Spring的IoC容器管理对象。项目由Maven管理。
4.1、编写类
BookDao路径:src.main.java.com.item.dao.BookDao;
BookService路径src.main.java.com.item.service.BookService;
public class BookDao {
public void method() {
System.out.println("Book Dao method");
}
}
public class BookService {
private BookDao bookDao ;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void method() {
System.out.println("BookService method");
bookDao.method();
}
}
4.2、传统方式测试
@Test
public void Test() {
BookService bookService = new BookService();
bookService.setBookDao(new BookDao());
bookDao.method();
}
利用junit框架去测试代码是以前经常用的,BookDao类的实例化是new出来的。
4.3、导入Spring依赖包
<dependencies>
<!-- Spring 的jar包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<!-- junit 测试框架-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
4.4、创建Spring的配置文件
说明:Spring的主配置文件名一般叫做beans.xml或applicationContext.xml。下面配置文件在resources目录下新建applicationContext.xml文件。
<?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">
<!-- 把BookDao对象的创建工作交给Spring-->
<bean id="bookDao" class="com.item.dao.BookDao"></bean>
<bean id="bookService" class="com.item.service.BookService">
<property name="bookDao" ref="bookDao"></property>
</bean>
</beans>
解读:创建BookDao类的bean交由IoC管理,由于BookService类中bookDao变量需要具体指向,所以使用标签进行依赖注入(注入),name属性:值为BookService类中需要注入的变量名,ref属性:参照哪一个bean(值为bean的id);标签 id属性:bean的称号;class属性:参照哪一个实体类进行实例化(值为改类的路径)
4.5、Spring测试
@Test
public void Test() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.method();
}
4.6、案例总结
4.6.1、分析
- IoC容器管理什么?
例如案例中BookDao的对象。
- 如何将被管理的对象告知IoC容器?
通过配置
- 案例中BookService类中的bookDao如何进入的?
在BookService提供了setBookDao方法。在配置好对应bean情况下,容器会调用setBookDao将对象注入。
- 如何描述的BookService和BookDao之间的关系?
通过配置告诉容器BookService和BookDao之间有依赖关系。
4.6.2、ApplicationContext的三个常用实现类
- ClassPathXmlApplicationContext
该类可以加载类路径下的配置文件,要求配置文件必须在类路径下。如果不在则加载失败。
- FileSystemXmlApplicationContext
它可以加载磁盘任意路径下的配置文件。
- AnnotationConfigApplicationContext
根据javaconfig来配置实例化Spring容器(用于读取注解创建容器的)。
4.6.3、BeanFactory容器
- BeanFactory
BeanFactory是Spring最初的容器,提供了最简单的容器功能,只提供了实例化对象和拿对象的功能。
BeanFactory在启动的时候不会实例化Bean,只有从容器中拿bean时才会实例化。延迟加载。
@Test
public void Test() {
Resource resource = new ClassPathResource("applicationContext.xml");
BeanFactory bf = new XmlBeanFactory(resource);
BookService bookService=(BookService)bf.getBean("bookService");
bookService.method();
}
五、Bean基于XML方式
5.1bean的概述
5.1.1、何为Bean?
简单来说IoC创建出来的对象称作bean。
5.1.2、bean的别名配置
功能:定义bean的别名,可定义多个名字。使用逗号(,)、分号(😉、空格( )间隔。
<bean name="dao bookDao">
5.1.3、bean实例化
5.1.3.1、使用构造器实例化
- 定义Bean
public class BookDao {
//statement....
}
- 配置bean
<bean id="bookDao" class="com.item.dao.BookDao"></bean>
- 注意事项
构造器方式是通过默认构造方法的方式创建bean,如果类中没有无参构造方法,则运行代码会报异常(BeanCreationException)。
5.1.3.2、使用静态工厂实例化
- 定义bean
public class OrderDao{
//statement....
}
// OrderDaoFactory静态工作,作用就是创建OrderDao对象
public class OrderDaoFactory {
public static OrderDao getOrderDao() {
return new OrderDao();
}
}
- 配置
<bean id="orderDao" factory-method="getOrderDao"
class="com.item.factory.OrderDaoFactory">
</bean>
说明:class属性的值为静态工厂类路径,factory-method属性表示调用哪个方法进行创建。
5.1.3.3、使用实例工厂进行实例化
- 定义bean
class UserDao {
//statement....
}
public class UserDaoFactory {
public UserDao getUserDao() {
return new UserDao();
}
}
- 配置
<bean id="userDaoFactory" class="com.item.factory.UserDaoFactory"></bean>
<bean id="userDao" factory-method="getUserDao"
factory-bean="userDaoFactory">
</bean>
说明:getUserDao方法不是静态方法,所以需要先创建userDaoFactory的bean再调用方法创建UserDao的bean。
factory-bean属性表示使用哪个bean。
5.2、依赖
5.2.1、依赖注入
5.2.1.1、Setter方法注入
- 定义bean
public class User {
private Integer id;
private BookDao bookDao;//入门案例里的类
public void setId(Integer id) {
this.id = id;
}
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
- bean配置
<bean id="bookDao" ref="com.item.dao.BookDao"></bean>
<bean id="user" class="com.item.dao.User">
<property name="id" value="1"></property>
<property name="bookDao" ref="bookDao"></property>
</bean>
说明:标签的name属性:值为set方法对应的名字,例如:setId则name=“id”,setXxx则name=“xxx”;
ref属性:参照哪一个bean进行实例化(值为bean的id)。
- 测试
@Test
public void Test() {
//1. 读取配置文件内信息,创建容器对象
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//2. 从容器中调用getBean方法根据id获取对象
User user = (User) ctx.getBean("user");
System.out.println(user);//User类提供toString方法
}
5.2.1.2、构造器依赖注入
- 定义Bean
public class User {
private Integer id;
private BookDao bookDao ;
public User(Integer id,BookDao bookDao) {
this.id = id;
this.bookDao = bookDao;
}
}
- name方式配置
<bean id="bookDao" ref="com.item.dao.BookDao"></bean>
<bean id="user" class="com.item.dao.User">
<constructor-arg name="id" value="1"></constructor-arg>
<constructor-arg name="bookDao" ref="bookDao"></constructor-arg>
</bean>
说明:标签的name属性:值为构造函数参数的变量名;
注意:user的bean内有两个constructor-arg标签则在创建对象时寻找对应的构造器,若没有则到报错。
- type方式配置
<bean id="bookDao" class="com.item.beans.BookDao"></bean>
<bean id="user4" class="com.item.beans.User">
<constructor-arg type="java.lang.Integer" value="1"></constructor-arg>
<constructor-arg type="com.item.beans.BookDao"
ref="bookDao">
</constructor-arg>
</bean>
- index方式配置
<bean id="user5" class="com.item.beans.User">
<constructor-arg index="0" value="1"></constructor-arg>
<constructor-arg index="1" ref="bookDao"></constructor-arg>
</bean>
说明:标签的index属性从0开始
5.2.2、依赖和配置的细节
5.2.2.1、直接值【基本数据类型,String】
- 定义Bean
public class Simple {
private int id;
private String name;
private boolean flag;
private double grade;
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public void setGrade(double grade) {
this.grade = grade;
}
}
- 配置
<bean id="simple" class="com.item.beans.Simple">
<property name="id" value="1"></property>
<property name="name" value="小哈"></property>
<property name="flag" value="true"></property>
<property name="grade" value="3.12"></property>
</bean>
说明:标签进行设置值,但是容器注入这些数据时会转为对应类型。
5.2.2.2、对其他bean的引用【注入】
- 定义Bean
public class Cat {
private Date date;
public void setDate(Date date) {
this.date = date;
}
}
- 配置bean
<bean id="date" class="java.util.Date"></bean>
<bean id="cat" class="com.item.beans.Cat">
<property name="date" ref="date"></property>
</bean>
5.2.2.3、内部bean
配置如下,Cat类为对其他bean的引用中所定义的类。内部bean不能为外部bean所使用。
<bean id="cat" class="com.item.beans.Cat">
<property name="date">
<bean class="java.util.Date"></bean>
</property>
</bean>
5.2.2.4、集合注入
- 定义Bean
public class example {
private Integer[] array;
private List<String> list;
private Set<String> set;
private HashMap<String,String> map;
private Properties properties;
public void setArray(Integer[] array) {
this.array = array;
}
public void setList(List<String> list) {
this.list = list;
}
public void setSet(Set<String> set) {
this.set = set;
}
public void setMap(HashMap<String, String> map) {
this.map = map;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
}
说明:example类路径com.item.beans.example。由于使用property标签,则需要提供set方法。
- 注入数组类型配置
<bean id="example" class="com.item.beans.example">
<property name="array">
<array>
<value>100</value>
<value>200</value>
<!--注入引用类型,bean的值为bean的id-->
<!--<ref bean="beanId"></ref> -->
</array>
</property>
</bean>
- List类型配置
<bean id="example" class="com.item.beans.example">
<property name="list">
<list>
<value>haha</value>
<!--<ref bean="beanID"></ref>-->
</list>
</property>
</bean>
- 注入Set类型配置
<bean id="example" class="com.item.beans.example">
<property name="set">
<set>
<value>haha</value>
<!--<ref bean="beanID"></ref>-->
</set>
</property>
</bean>
- 注入Map类型配置
<bean id="example4" class="com.item.beans.example">
<property name="map">
<map>
<entry key="country" value="china"></entry>
<!--
<entry key-ref="beanId" value-ref="beanId"></entry>
-->
</map>
</property>
</bean>
说明:标签的key-ref或value-ref属性值都为bean的id,在这之前Map集合存储类型也须和key-ref、value-ref对象类型相同。
- 注入Properties类型配置
<bean id="example5" class="com.item.beans.example">
<property name="properties">
<props>
<prop key="country">china</prop>
</props>
</property>
</bean>
5.2.2.5、注入null和空字符串
<!-- 设置null -->
<property name="name">
<null></null>
</property>
<!--设置空字符串-->
<property name="gender" value=""></property>
说明:设置null,则在内嵌入子标签。设置空字符串如上所示。
5.2.2.6、使用p命名空间简化基于setter属性注入
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="wife" class="com.item.beans.Wife" p:age="18" p:name="迪丽热巴">
</bean>
</beans>
说明:在标签头内添加 xmlns:p=“http://www.springframework.org/schema/p”,即可在标签中使用;p:属性名="属性值"或p:name-ref=“bean的id”。如果不想这么麻烦,在IDEA中直接在标签中加入**p:**按住Alt+Enter点击Create namespace declaration即可自动添加完成。
注意:**如果有集合类型需要额外配置。**Wife类定义在对其他bean的引用处。
5.2.2.7、使用c命名空间简化XML
简化构造函数注入。Wife是一个已定义类,其中一个构造方法中有两个参数,参数1为int类型、参数2为String类型。
<?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:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="wife" class="com.item.beans.Wife" c:_0="1" c:_1="哈哈">
</bean>
</beans>
说明:c:_0此处的0表示构造器的参数的下标位置(从0开始)。c:age则为c:属性名。
注意:**如果有集合类型需要额外配置。**Wife类定义在对其他bean的引用处。
5.2.2.8、加载properties文件配置
- 步骤
- 开辟新的命名空间(context)
<?xml version="1.0" encoding="UTF-8"?>
<beans default-lazy-init="true"
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">
</beans>
说明:
- 添加
xmlns:context
xmlns:context="http://www.springframework.org/schema/context"
2. 添加`xsi:schemaLocation`
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
在xsi:schemaLocation内添加上述两个语句,将第7和8行复制一份然后将里面的beans替换成context即可。
- 使用context命名空间,加载指定properties文件
<context:property-placeholder location="db1.properties">
</context:property-placeholder>
location:文件路径
- 使用${}读取加载的属性值
<property name="username" value="${mysql.username}"></property>
说明:properties文件是k=v形,${}内填写k即可.
其余属性,如下所示:
- 不加载系统属性(system-properties-mode)
因为有时候${K}的K会与系统中属性名一直,且系统属性优先级高于K。则system-properties-mode设置为NEVER。
<context:property-placeholder location="db1.properties"
system-properties-mode="NEVER">
</context:property-placeholder>
- 加载多个properties文件
<context:property-placeholder location="db1.properties,msg.properties">
</context:property-placeholder>
- 加载所有properties文件
<context:property-placeholder location="*.properties">
</context:property-placeholder>
- 加载properties文件标准格式
<context:property-placeholder location="classpath:*.properties">
</context:property-placeholder>
- 从类路径或jar包中加载properties文件
<context:property-placeholder location="classpath*:*.properties">
</context:property-placeholder>
5.2.2.9、Spring创建第三方bean对象
在Spring中,很多对象都是单例的,在日常开发中,我们经常需要使用某些外部的单实例对象,例如数据库连接池,下面了解如何在Spring中创建第三方bean实例。
- 首先配置坐标(pom.xml)
<!-- druid连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
<!-- mysql坐标 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
- 配置bean
<!-- 配置第三方bean -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/db1"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
说明:配置对应的驱动、url、username、password等属性。
- 测试
@Test
public void T16(){
DruidDataSource dataSource =
ioc.getBean("dataSource", DruidDataSource.class);
System.out.println(dataSource);//会输出配置信息
}
5.2.3、使用depends-on属性
在XML配置方式中容器是从XML文件开始处依次加载bean,如果你想在一个bean加载前去加载另一个bean的需要使用depends-on属性。
<bean id="person" class="com.item.beans.Person" depends-on="wife"></bean>
<bean id="wife" class="com.item.beans.Wife"></bean>
说明:正常情况下,person的加载早于wife的加载,但由于person使用了depends-on属性,使person加载前必须加载wife。depends-on=“bean的id”
5.2.4、懒加载
容器中的一些bean不会经常使用,所以初始化时就不必加载这些bean,等到使用的时候再加载。
使用属性lazy-init=“true/false”。true为懒加载,false非懒加载。
<bean id="wife" class="com.item.beans.Wife" lazy-init="true"></bean>
如果你想让本XML内的所有bean都懒加载则需再标签内加上default-lazy-init=“true”。
5.2.5、自动注入
IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动注入。
- 自动注入方式(autowire属性)
- 按类型(byType属性值)
- 按名称(byName属性值)
- 按构造方法(constructor属性值)
- 不启用自动注入(default属性值)
5.2.5.1、自动注入的方式
- 按类型注入
<bean id="wife" class="com.item.beans.Wife"></bean>
<bean id="person" class="com.item.beans.Person" autowire="byType"></bean>
说明:byType 根据类型去自动匹配,且注入的类型必须在IoC容器中有bean,如果出现多个类型相同的bean则报错。
注意:要提供相应的set方法。
- 按名字注入
<bean id="wife" class="com.item.beans.Wife"></bean>
<bean id="person" class="com.item.beans.Person" autowire="byType"></bean>
说明:根据set方法的名字自动匹配。
- 按构造方法注入
<bean id="wife5" class="com.item.beans.Wife" autowire="constructor">
<property name="age" value="1"></property>
<property name="name" value="啊哈"></property>
</bean>
说明:根据构造器去匹配,调用对应参数列表的构造器。优先根据参数名字去匹配,假如参数名字没有匹配到,会根据参数类型进行匹配,假如对应类型的bean有多个会注入失败但不会报错,将会调用默认构造函数(有的情况下)。
5.2.5.2、多个类型注入配置
通过以下属性设置,在多个类型相同的bean,让IoC容器注入选择时明确参照的bean。
- primary属性
作用:设置primary属性为true则为主bean,注入时优先参照此bean注入(未指定bean的情况下)。
- 属性值:true/false
<bean id="wife" class="com.item.beans.Wife" primary="true"></bean>
- autowire-candidate属性
用来标记当前bean是否会被作为注入的候选bean。适用于多个相同类型的bean。
- 属性值
- true(默认)表示其他bean可以把当前bean作为属性注入。
- false,表示其他bean选在注入属性 bean时将忽略当前bean。
<bean id="wife" class="com.item.beans.Wife" autowire-candidate="false"></bean>
5.3、Bean的作用域
功能:定义bean的作用范围。属性:scope
5.3.1、作用域类型
- singleton:单例的(默认值),只会创建一次。
- prototype:多例的,一个Bean定义可以创建任意多个实例对象.
- request:作用于web应用的请求范围,Spring创建这个类之后,将这个类存到request范围内。
- session:应用于web项目的会话范围,Spring创建这个类之后,将这个类存到session范围内。
- application:将单个bean定义范围限定为
ServletContext
的生命周期。一个应用创建一个bean。 - websocket:将单个bean定义范围限定为
WebSocket
的生命周期。
后三个作用域类型都是Web部分的。
5.3.2、案例
<bean class="...." scope="prototype"></bean>
5.3.3、bean作用范围说明
- 适合交给容器管理的bean
- 表现层对象
- 业务层对象
- 数据层对象
- 工具对象
- 不适合交给容器管理的bean
- 封装实体的域对象(有状态的)
5.4、bean的生命周期
5.41、介绍
从Spring 2.5开始,您有三种选择用于控制bean生命周期行为
InitializingBean
和DisposableBean
回调接口- 自定义
init()
和destroy()
方法 @PostConstruct
和@PreDestroy
注解
5.4.2、使用自定义方法实现
public class BookDao {
//statement....
public void init() {
//statement....
System.out.println("初始化");
}
public void destroy() {
//statement....
System.out.println("销毁");
}
}
- 配置
<bean id="bookDao" class="com.item.dao.BookDao"
init-mmethod="init" destroy-method="destroy">
</bean>
init-mmethod属性指出BookDao类中调用哪个方法进行初始化。destroy-method属性指出BookDao类中调用哪个方法进行销毁。
- 测试(main方法内)
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext("beans.xml");
BookDao bookDao = ctx.getBean("bookDao");
ctx.close();//只有容器关闭了才能调用销毁方法。
5.4.3、使用接口的方式实现
- 实现步骤
- 初始化回调,继承InitializingBean接口,重写afterPropertiesSet方法
- 继承DisposableBean接口,重写destroy方法
public class BookDao implements InitializingBean,DisposableBean {
//statement....
@Override
public void afterPropertiesSet() throws Exception {
//statement....
System.out.println("初始化");
}
@Override
public void destroy() throws Exception {
//statement....
System.out.println("销毁");
}
}
- 配置
<bean id="bookDao" class="com.item.dao.BookDao"></bean>
- 测试
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext("beans.xml");
BookDao bookDao = ctx.getBean("bookDao");
ctx.close();//只有容器关闭了才能调用销毁方法。
5.5.5、总结
在使用自定义方式和接口方式同时实现情况下,初始化或销毁是先调用接口方式再调用自定义方式实现。