文章目录
- 1. 初识 spring
- 1.1 系统架构
- 1.2 学习路线
- 1.3 核心概念
- 2. IoC 与 DI 入门案例(xml版)
- 2.1 IoC(控制反转)
- 2.2 DI(依赖注入)
- 3. bean 配置
- 3.1 bean 基础配置
- 3.2 bean 别名配置
- 3.3 bean 作用范围配置
- 4. bean 实例化
- 4.1 用构造方法实例化 bean
- 4.2 用静态工厂实例化 bean(了解)
- 4.3 用实例工厂实例化 bean(了解)
- 4.4 FactoryBean
- 5. 控制 bean 的生命周期
- 5.1 bean 的生命周期
- 5.2 提供方法控制 bean 的生命周期
- 5.3 使用接口控制 bean 的生命周期(了解)
- 6. 依赖注入(DI)
- 6.1 依赖注入引入
- 6.2 setter 注入
- 6.2.1 引用类型的 setter 注入
- 6.2.2 简单类型的 setter 注入
- 6.3 构造器注入
- 6.3.1 引用类型的构造器注入
- 6.3.2 简单类型的构造器注入
- 6.3.3 传参方式
- 6.3.4 注入方式的选择
- 6.4 依赖自动装配
- 6.5 集合注入
- 7. 数据源对象管理
- 7.1 spring 管理第三方数据源对象
- 7.2 加载 properties文件
- 8. 容器
1. 初识 spring
1.1 系统架构
1.2 学习路线
1.3 核心概念
在业务层实现中,若 new BookDaoImpl() 改为 new BookDaoImpl2(),可能导致整个项目都要重新编译、重新测试。这样耦合度也偏高。
【解决方案】使用对象时,在程序中不要主动使用 new 产生对象,转换为由外部提供对象。
IoC 控制反转:对象的创建控制权由程序转移到外部,这种思想称为控制反转(IoC—Inversion of Control)。
Spring 技术对 IoC 思想进行了实现:
- Spring 提供了 IoC 容器,用来充当 IoC 思想中的”外部“。
- IoC 容器负责对象的创建、初始化等工作,被创建或管理的对象在 IoC 容器中统称为 Bean。
- IoC 容器又称 Spring 核心容器 / Spring 容器。
DI 依赖注入
在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入(Dependency Injection)。(bean 就是对象)
目标:充分解耦
使用IoC容器管理bean(IoC)
在IoC容器内将有依赖关系的bean进行关系绑定(DI)
最终效果
使用对象时不仅可以直接从 IoC 容器中获取,并且获取到的 bean 已经绑定了所有的依赖关系。
2. IoC 与 DI 入门案例(xml版)
2.1 IoC(控制反转)
新建 maven 项目后:
(1) 在 pom.xml 中配置如下:
<dependencies>
<dependency>
<groupId>org.springframework</groupId><!--所属群组-->
<artifactId>spring-context</artifactId><!--spring的坐标-->
<version>5.2.10.RELEASE</version><!--一个稳定的版本号-->
</dependency>
</dependencies>
(2) 定义接口、类
public interface BookService {
public void save();
}
public class BookServiceImpl implements BookService {
private BookDao bookDao = new BookDaoImpl();
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
(3) 配置 bean:在resource下新建applicationContext.xml
(4) 初始化 IoC 容器,通过容器获取 bean 中的对象,并调用对象方法
public class App {
public static void main(String[] args) {
//获取IoC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取bean中BookService的对象
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
}
}
//输出:book service save ...
// book dao save ...
2.2 DI(依赖注入)
上节的方式虽然在一定程度上解耦了,但 BookServiceImpl 类还有一个 new 对象语句,故解耦不彻底。下面就来解决这个问题。
(1) 删除使用 new 形式创建对象的代码
(2) 提供依赖对象对应的 setter 方法
(3) 配置 service 与 dao 之间的关系
3. bean 配置
3.1 bean 基础配置
3.2 bean 别名配置
【注意事项】获取 bean 时,无论通过 id 或 name 获取,若无法获取到,将抛出异常NoSuchBeanDefinitionException。如:
NoSuchBeanDefinitionException: No bean named ‘bookServiceImpl’ available
3.3 bean 作用范围配置
由下面的例子可知,spring 默认创建的 bean 是单例的。
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService1 = (BookService) ctx.getBean("service2");
System.out.println(bookService1);
BookService bookService2 = (BookService) ctx.getBean("service2");
System.out.println(bookService2);
输出结果:
service.impl.BookServiceImpl@6adede5
service.impl.BookServiceImpl@6adede5
通过修改配置文件可以使 spring 创建非单例的 bean,具体通过修改 bean 的 scope 属性来实现。
经过如下修改,spring 就能创建非单例的 bean。
输出结果:
service.impl.BookServiceImpl@6adede5
service.impl.BookServiceImpl@2d928643
4. bean 实例化
4.1 用构造方法实例化 bean
bean 一般通过构造方法创建,构造方法常常是 public 的,该构造方法用 private 修饰也可,原因在于反射机制,后面细讲。
构造方法由 IoC 容器自动调用。
创建 bean 时,只能调用无参构造方法,若硬要写有参构造方法会抛异常。
4.2 用静态工厂实例化 bean(了解)
(1) 准备接口和类
public interface OrderDao {
public void save();
}
public class OrderDaoImpl implements OrderDao {
@Override
public void save() {
System.out.println("order dao run...");
}
}
(2) 产生对象的工厂
public class OrderDaoFactory {
public static OrderDaoImpl getOrderDao(){
return new OrderDaoImpl();
}
}
(3) 配置 bean
<!--必须指定工厂方法,否则就创建了OrderDaoFactory的对象-->
<bean id="orderDao" class="factory.OrderDaoFactory" factory-method="getOrderDao"/>
(4) 获取 IoC 容器、bean,调用方法
public class App2 {
public static void main(String[] args) {
//获取IoC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
OrderDao orderDao = (OrderDao) ctx.getBean("orderDao");
orderDao.save();
}
}
输出:order dao run...
4.3 用实例工厂实例化 bean(了解)
(1) 需要的接口、类
public interface UserDao {
public void save();
}
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("user dao is running...");
}
}
(2) 产生对象的工厂
public class UserDaoFactory {
public UserDao getUserDao(){
return new UserDaoImpl();
}
}
(3) 配置 bean
<!--产生工厂对象-->
<bean id="userDaoFactory" class="factory.UserDaoFactory"/>
<!--利用工厂对象调用工厂方法,获得要生产的对象-->
<bean id="userDao" factory-bean="userDaoFactory" factory-method="getUserDao"/>
(4) 获取 IoC 容器、bean,调用方法
public class App2 {
public static void main(String[] args) {
//原始方法
//UserDaoFactory userDaoFactory = new UserDaoFactory();
//UserDao userDao = userDaoFactory.getUserDao();
//userDao.save();
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) ctx.getBean("userDao");
userDao.save();
}
}
4.4 FactoryBean
(1) 需要的接口、类
public interface UserDao {
public void save();
}
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("user dao is running...");
}
}
(2) 产生对象的 FactoryBean
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
@Override
//得到bean实例
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
@Override
//得到bean类型
public Class<?> getObjectType() {
return UserDao.class;
}
}
(3) 配置 bean
<bean id="userDao" class="factory.UserDaoFactoryBean"/>
(4) 获取 IoC 容器、bean,调用方法
public class App2 {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) ctx.getBean("userDao");
userDao.save();
}
}
关于 FactoryBean 接口中三个方法的作用:
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
//前两个方法是 FactoryBean 接口中的抽象方法,必须要实现
@Override
//得到bean实例
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
@Override
//得到bean类型
public Class<?> getObjectType() {
return UserDao.class;
}
@Override
//控制bean是单例或非单例
//不重写该方法时,默认单例,打印获取的bean可看出
public boolean isSingleton() {
return true;//单例
}
}
5. 控制 bean 的生命周期
5.1 bean 的生命周期
bean 的生命周期:
- 初始化容器
(1) 创建对象(new 内存分配)
(2) 执行构造方法
(3) 执行属性注入(set 操作)
(4) 执行bean初始化方法 - 使用 bean
执行业务操作 - 关闭 / 销毁容器
执行 bean 销毁方法
容器关闭前会触发 bean 的销毁,关闭容器方式有:
- 手工关闭容器
ConfigurableApplicationContext 接口 close() 操作 - 注册关闭钩子,在虚拟机退出前先关闭容器再退出虚拟机
ConfigurableApplicationContext 接口 registerShutdownHook() 操作
5.2 提供方法控制 bean 的生命周期
接口:
public interface BookDao {
public void save();
}
提供生命周期控制方法:
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
//bean生命周期开始时执行的方法
public void init(){
System.out.println("init...");
}
//bean生命周期结束时执行的方法
public void destory(){
System.out.println("destory...");
}
}
配置生命周期控制方法:
<bean id="bookDao" class="dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
控制 bean 的生命周期:
public class app {
public static void main(String[] args) {
//IoC容器加载
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//bean初始化,拿到bean
BookDao bookDao = (BookDao)ctx.getBean("bookDao");
bookDao.save();
//程序执行完,虚拟机马上退出,没有机会销毁bean,也就执行不了destroy方法
//若要销毁bean,有两个方法
//(1)在虚拟机退出之前,关闭容器(暴力方法)
//ClassPathXmlApplicationContext类有close方法
//ctx.close();
//(2)注册关闭钩子,关闭虚拟机之前先关闭容器(温和方法)
//在哪里加这句都可以,因为总是在程序结束之前
ctx.registerShutdownHook();
}
}
输出结果:
init...
book dao save ...
destory...
5.3 使用接口控制 bean 的生命周期(了解)
用service来演示:
public interface BookService {
public void save();
}
实现 InitializingBean、DisposableBean 接口
public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
private BookDao bookDao;
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
public void setBookDao(BookDao bookDao) {
//System.out.println("setBookDao...");
this.bookDao = bookDao;
}
@Override
public void destroy() throws Exception {
System.out.println("service destroy");
}
@Override
//afterPropertiesSet:在设置属性(set方法)之后执行
public void afterPropertiesSet() throws Exception {
System.out.println("service init");
}
}
<bean id="bookDao" class="dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
<bean id="bookService" class="service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
</bean>
加上上面的代码后,运行 app.java,输出如下:
init...
setBookDao...
service init
book dao save ...
service destroy
destory...
虽然 app.java 运行的是 bookDao 的方法,但是也输出了 bookService 的相关信息,这是因为 bean 加载了。
6. 依赖注入(DI)
6.1 依赖注入引入
向一个类中传递数据的方式有 2 种:
- 普通方法(set 方法)
- 构造方法
依赖注入描述了在容器中建立 bean 与 bean 之间依赖关系的过程,如果 bean 运行需要的是数字或字符串呢?所以下面要研究两种依赖注入方式:setter 注入和构造器注入对于下面两种情况的处理方式:
- 简单类型(基本数据类型与string)
- 引用类型
6.2 setter 注入
6.2.1 引用类型的 setter 注入
定义引用类型属性并提供可访问的 set 方法
public class BookServiceImpl implements BookService {
private BookDao bookDao;
private UserDao userDao;
public void save() {
System.out.println("book service save ...");
bookDao.save();
userDao.save();
}
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
配置文件中使用 property 标签和 ref 属性注入引用类型对象
<bean id="bookDao" class="dao.impl.BookDaoImpl"/>
<bean id="userDao" class="dao.impl.UserDaoImpl"/>
<bean id="bookService" class="service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
<property name="userDao" ref="userDao"/>
</bean>
测试:
public class app {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = (BookService)ctx.getBean("bookService");
bookService.save();
}
}
输出结果:
book service save ...
book dao save ...
user dao save...
6.2.2 简单类型的 setter 注入
定义简单类型属性并提供可访问的 set 方法
public class BookDaoImpl implements BookDao {
private int connectNum;
private String database;
public void setConnectNum(int connectNum) {
this.connectNum = connectNum;
}
public void setDatabase(String database) {
this.database = database;
}
public void save() {
System.out.println("book dao save ..."+connectNum+" "+database);
}
}
在配置中使用 property 标签 value 属性注入简单类型的数据
<bean id="bookDao" class="dao.impl.BookDaoImpl">
<!--spring内部会把value的类型转换好-->
<property name="connectNum" value="100"/>
<property name="database" value="mysql"/>
</bean>
测试:
public class app {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao)ctx.getBean("bookDao");
bookDao.save();
}
}
输出结果:
book dao save ...100 mysql
6.3 构造器注入
6.3.1 引用类型的构造器注入
public class BookServiceImpl implements BookService {
private BookDao bookDao;
private UserDao userDao;
public BookServiceImpl(BookDao bookDao, UserDao userDao) {
this.bookDao = bookDao;
this.userDao = userDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
userDao.save();
}
}
<bean id="bookDao" class="dao.impl.BookDaoImpl"/>
<bean id="userDao" class="dao.impl.UserDaoImpl"/>
<bean id="bookService" class="service.impl.BookServiceImpl">
<!--顺序无妨-->
<constructor-arg name="bookDao" ref="bookDao"/>
<constructor-arg name="userDao" ref="userDao"/>
</bean>
public class app {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = (BookService)ctx.getBean("bookService");
bookService.save();
}
}
输出结果:
book service save ...
book dao save ...
user dao save...
6.3.2 简单类型的构造器注入
public class BookDaoImpl implements BookDao {
private int connectNum;
private String database;
public BookDaoImpl(int connectNum, String database) {
this.connectNum = connectNum;
this.database = database;
}
public void save() {
System.out.println("book dao save ..."+connectNum+" "+database);
}
}
<bean id="bookDao" class="dao.impl.BookDaoImpl">
<!--顺序无妨-->
<constructor-arg name="connectNum" value="100"/>
<constructor-arg name="database" value="mysql"/>
</bean>
public class app {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao)ctx.getBean("bookDao");
bookDao.save();
}
}
输出结果:
book dao save ...100 mysql
6.3.3 传参方式
方式 1:
当构造方法的形参不是 connectNum、database 时(如:num、data),方式 1 失效。
方式 2: 指定参数类型
当有重复类型的参数时,方式 2 失效。
方式 3: 指定参数顺序
当参数很多,且需要去掉 / 增加一些参数时,就要大规模变动 index,比较繁琐。
6.3.4 注入方式的选择
- 强制依赖使用构造器进行,使用 setter 注入有概率不进行注入导致null 对象出现(bean 运行所必须的东西使用构造器进行依赖注入)
- 可选依赖使用 setter 注入进行,灵活性强
- Spring 框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
- 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用 setter 注入完成可选依赖的注入
- 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
- 自己开发的模块推荐使用 setter 注入
6.4 依赖自动装配
IoC 容器根据 bean 所依赖的资源在容器中自动查找并注入到 bean 中的过程称为自动装配。
自动装配方式:
(1) 按类型装配(常用):autowire="byType"
【注意事项】
① 按类型装配时,可以连 id 都不要:
② 找不到要装配的类型或者该类型的 bean 不止一个时,报错。
该类型的 bean 不止一个时,可以按名称装配。
(2) 按名称装配:autowire="byName"
(3) 按构造方法(很少用)
(4) 不启用自动装配
自动装配的细节:
- 自动装配用于引用类型依赖注入,不能对简单类型进行操作
- 使用按类型装配时(byType)必须保障容器中相同类型的 bean 唯一,推荐使用
- 使用按名称装配时(byName)必须保障容器中具有指定名称的 bean,因变量名与配置耦合,不推荐使用
- 自动装配优先级低于 setter 注入与构造器注入,同时出现时自动装配配置失效
6.5 集合注入
public class BookDaoImpl implements BookDao {
private int[] array;
private List<String> list;
private Set<String> set;
private Map<String,String> map;
private Properties properties;
public void setArray(int[] 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(Map<String, String> map) {
this.map = map;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public void save() {
System.out.println("book dao save ...");
System.out.println("遍历数组:"+ Arrays.toString(array));
System.out.println("遍历List:"+list);
System.out.println("遍历Set:"+ set);
System.out.println("遍历Map:"+map);
System.out.println("遍历Properties:"+properties);
}
}
<bean id="bookDao" class="dao.impl.BookDaoImpl">
<property name="array"><!--与set方法形参名保持一致-->
<array><!--标签名,array写成list也可-->
<value>100</value>
<value>200</value>
<value>300</value>
<!--如果元素是引用类型,这样写:-->
<!--<ref bean="beanId"/>-->
</array>
</property>
<property name="list"><!--与set方法形参名保持一致-->
<list><!--标签名,list写成array也可-->
<value>itcast</value>
<value>itheima</value>
<value>boxuegu</value>
</list>
</property>
<property name="set"><!--与set方法形参名保持一致-->
<set><!--标签名-->
<value>itcast</value>
<value>itheima</value>
<value>boxuegu</value>
<value>boxuegu</value>
</set>
</property>
<property name="map"><!--与set方法形参名保持一致-->
<map><!--标签名-->
<entry key="country" value="china"/>
<entry key="province" value="henan"/>
<entry key="city" value="kaifeng"/>
</map>
</property>
<property name="properties"><!--与set方法形参名保持一致-->
<props><!--标签名-->
<prop key="country">china</prop>
<prop key="province">henan</prop>
<prop key="city">kaifeng</prop>
</props>
</property>
</bean>
public class app {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao)ctx.getBean("bookDao");
bookDao.save();
}
}
输出结果:
book dao save ...
遍历数组:[100, 200, 300]
遍历List:[itcast, itheima, boxuegu]
遍历Set:[itcast, itheima, boxuegu]
遍历Map:{country=china, province=henan, city=kaifeng}
遍历Properties:{province=henan, city=kaifeng, country=china}
7. 数据源对象管理
7.1 spring 管理第三方数据源对象
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId><!--druid数据源-->
<version>1.1.16</version>
</dependency>
<bean class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/spring_db"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
public class app {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource dataSource = (DataSource) ctx.getBean("dataSource");
System.out.println(dataSource);
}
}
输出结果:
{
CreateTime:"2023-01-27 19:56:05",
ActiveCount:0,
PoolingCount:0,
CreateCount:0,
DestroyCount:0,
CloseCount:0,
ConnectCount:0,
Connections:[
]
}
7.2 加载 properties文件
在上节中,第三方 bean 的 property 标签中的 value 是写死的,除了这种方式,还可以从 properties 文件中加载 value。
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db
jdbc.username=root
jdbc.password=root
BookDaoImpl.java(用来验证)
public class BookDaoImpl implements BookDao {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public void save() {
System.out.println("book dao save ..."+name);
}
}
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"
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
"><!--1. 开启context命名空间-->
<!--2. 使用context空间加载properties文件-->
<context:property-placeholder location="jdbc.properties"/>
<!--3. 使用属性占位符${}读取properties文件中的属性-->
<bean class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--上面加载properties文件的结果难以验证,
所以下面做了一个类似的bean来验证-->
<bean id="bookDao" class="dao.impl.BookDaoImpl">
<property name="name" value="${jdbc.driver}"/>
</bean>
</beans>
public class app {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
}
}
输出结果:
book dao save ...com.mysql.jdbc.Driver
开启 context 命名空间时,applicationContext.xml 中需要更改的地方:
一些特殊情况:
(1)下面的第二个 bean 中,value 被赋的值不是 user666,而是系统的环境变量中的 username(系统的环境变量优先级高)。如果想要不被干扰,可以在加载 properities 文件时加入 system-properties-mode="NEVER"
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db
jdbc.username=root
jdbc.password=root
username=user666
<!--使用context空间加载properties文件-->
<context:property-placeholder location="jdbc.properties"/>
<!--<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>-->
<bean class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--上面加载properties文件的结果难以验证,
所以下面做了一个类似的bean来验证-->
<bean id="bookDao" class="dao.impl.BookDaoImpl">
<property name="name" value="${username}"/>
</bean>
(2)加载多个 properties 文件:
jdbc.properties:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db
jdbc.username=root
jdbc.password=root
jdbc2.properties:
username=user666
<!--使用context空间加载properties文件-->
<context:property-placeholder location="jdbc.properties, jdbc2.properties" system-properties-mode="NEVER"/>
<bean class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--上面加载properties文件的结果难以验证,
所以下面做了一个类似的bean来验证-->
<bean id="bookDao" class="dao.impl.BookDaoImpl">
<property name="name" value="${username}"/>
</bean>
(3)加载类路径下(自己工程下)的所有 properties 文件
<context:property-placeholder location="*.properties"/>
或标准格式:
<context:property-placeholder location="classpath:*.properties"/>
(3)加载类路径下(自己工程下)或 jar 包中的所有 properties 文件
<context:property-placeholder location="classpath*:*.properties"/>
8. 容器
(1) 加载配置文件(创建容器)
//方式1:加载类路径下的配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//方式2:从文件系统下加载配置文件
ApplicationContext ctx = new FileSystemXmlApplicationContext("E:\\IdeaProjects\\spring10_container\\src\\main\\resources\\applicationContext.xml");
加载多个配置文件时(上面两种方式都能实现),配置文件之间用逗号隔开,如:"bean1.xml", "bean2.xml"
(2) 获取 bean
//方式1:强制转换
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
//方式2:指定类型
BookDao bookDao = ctx.getBean("bookDao", BookDao.class);
//方式3:根据类型获取bean(不能有重复类型的bean)
BookDao bookDao = ctx.getBean(BookDao.class);
(3)容器层次结构
(4)spring 早期用 BeanFactory 创建容器(略)