Spring-day01
# 前置课程
1. javase
1). 面向对象: 封装,继承,多态(面向接口)
2). 反射
3). 动态代理
2. javaweb
1). servlet编程规范
2). 网络编程
3. 数据库
1). sql
2). mybatis框架
# 框架阶段
1. 时间 (8天)
1). spring : 3天 (IOC、AOP)
2). springmvc : 2天 (底层封装Servlet)
3). maven高级 : 1天
4). springboot 1天 (基于SSM做简化)
5). 综合案例: 1天
2. SSM
1). springmvc (控制层/web层)
2). spring (业务层)
3). mybatis (持久层)
框架课:以练习为主(多写代码)
框架:就是第三方组织开发的半成品软件(我们就是学习软件的使用)
在开发中:新增类/方法、删除类/方法,比修改类或方法便捷
- 尽量不修改源代码
01_Spring初体验
目标
- 能够使用Spring框架初步改造案例代码
路径
- 综合案例中代码优化方式
- 使用Spring框架改造案例
综合案例中代码优化方式
在前面开发的web综合案例用户权限系统
中,在web层调用业务层代码的优化使用了:"工厂类+反射+配置文件"的方式解决。
只需要告知工厂,要使用哪个类,工厂类就自动创建该类对象并返回
- 底层实现机制:工厂类 + 配置文件
- 工厂类中使用反射技术
好处:
- 解耦(类和类之间没有直接关系)
- 便于程序的维护
而这种工厂类+反射+配置文件
的开发方式,已经有一个现成的框架(Spring)提供了。
使用Spring框架改造案例
使用Spring改造案例的步骤:
-
导入spring坐标(5.1.9.release)
-
编写业务层接口与实现类
-
建立Spring配置文件
-
配置所需资源(Service)为Spring控制的资源
-
表现层通过Spring获取资源(Service实例)
第1步:导入Spring坐标
<dependencies>
<!-- spring依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
</dependencies>
第2步:编写业务层接口与实现类
//业务层接口
public interface UserService {
//添加用户
public abstract boolean addUser(User user);
//查询用户数据
public abstract List<User> findUsers();
}
//业务层实现类
public class UserServiceImpl implements UserService {
@Override
public boolean addUser(User user) {
//省略代码...
//模拟数据
boolean saveResult = true;
return saveResult;
}
@Override
public List<User> findUsers() {
//省略代码...
//模拟数据
List<User> userList = new ArrayList<>();
userList.add(new User("用户名","密码"));
userList.add(new User("itheima","123123"));
return userList;
}
}
第3步:建立Spring配置文件
- 在maven工程的resources目录下创建:applicationContext.xml
第4步:配置所需资源(Service)为Spring控制的资源
- 在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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 创建spring控制的资源
id : 是这个bean(类)的标识。 【见名知其意】
class : 指定实现类的全限定名。
-->
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl"/>
</beans>
第5步:表现层通过Spring获取资源(Service实例)
@WebServlet("/user/*")
public class UserServlet extends BaseServlet {
//业务层对象(父接口)
private UserService userService;
public UserServlet() {
//1.加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.获取资源: 通过配置文件中的id
userService = (UserService) ctx.getBean("userService");
}
/**
* 添加用户
*
* @param request
* @param response
* @throws IOException
*/
private void addUser(HttpServletRequest request, HttpServletResponse response) throws IOException {
//调用业务层功能: 添加用户
boolean result = userService.addUser(new User("测试用户", "测试密码"));
if (result) {
response.getWriter().print("用户添加成功!");
}
}
/**
* 查询用户数据
*
* @param request
* @param response
* @throws IOException
*/
private void queryUser(HttpServletRequest request, HttpServletResponse response) throws IOException {
//调用业务层功能: 查询用户信息
List<User> users = userService.findUsers();
//测试:打印查询用户
for (User user : users) {
System.out.println(user);
}
}
}
小结
使用spring框架开发代码的步骤:
-
导入spring坐标
-
建立spring配置文件
-
在spring配置文件中配置所需资源(把类托管给spring来管理和创建对象)
-
通过spring获取资源(获取对象)
02_Spring简介
目标
- 了解Spring技术的背景
路径
- 什么是Spring
- Spring的发展历史
什么是Spring
Spring是一个开源框架。简单来说,Spring是一个分层的JavaSE/EE 一站式(full-stack) 轻量级开源框架。
分层:每一个层都有提供的解决方案
- web层:struts2,spring-MVC
- service层:spring
- dao层:mybatis , spring-data
一站式(full-stack):简单来讲就是将各层能够无缝的集成在一起,提高开发的效率
轻量级:与EJB(enterprice javabean)对比,依赖资源少,消耗的资源少。
Spring的发展历史
Java语言分类 :
- JavaSE:java standard edition 标准
- JavaEE:java enterprice edition 企业
- JavaME:java micro edition 微型
Spring的发展历史:
- 1997年IBM提出了EJB的思想(EJB是的Enterprise Java Beans技术的简称, 又被称为企业Java Beans)
- 1998年,SUN制定开发标准规范EJB1.0
- 1999年,EJB1.1发布
- 2001年,EJB2.0发布
- 2003年,EJB2.1发布
- 2006年,EJB3.0发布
Rod Johnson(罗德·约翰逊) [Spring之父]
Expert One-to-One J2EE Design and Development(2002)
阐述了J2EE使用EJB开发设计的优点及解决方案
Expert One-to-One J2EE Development without EJB(2004)
阐述了J2EE开发不使用EJB的解决方式(Spring雏形)
2017年9月份发布了spring的最新版本--spring 5.0通用版
小结
Spring技术:
- spring是一个开源框架
- spring可以把JavaEE开发中使用到的各种框架技术(如:mybatis等)整合在一起
- 现在使用的spring最新版本为:spring 5.x
03_Spring体系结构
目标
- 能够说出Spring技术体系中的核心是什么
路径
- Spring体系结构
- Spring优势
- Spring核心
Spring体系结构
Spring优势
Spring 出现是为了解决JavaEE 实际问题:
-
方便解耦,简化开发 (IOC)
Spring就是一个大工厂(容器)。 通过Spring提供的容器,可以将对象的创建和对象间的依赖关系交由Spring进行管理,避免硬编码所造成的过度程序耦合。 用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。
-
AOP编程的支持
Spring提供面向切面(AOP)编程,可以方便的实现对程序进行权限拦截、运行监控等功能。
-
声明式事务的支持
将程序员从单调烦闷的事务管理代码中解脱出来。 只需要通过配置就可以完成对事务的管理,而无需手动编程。
-
方便程序的测试
Spring对Junit4支持,可以通过注解方便的测试Spring程序。
-
方便集成各种优秀框架
Spring可以降低各种框架的使用难度,提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz(定时任务)等)的直接支持。
-
降低JavaEE API的使用难度
Spring对JavaEE开发中使用的一些API(如:JDBC、JavaMail、远程调用等),进行了封装,使这些API的应用难度大大降低。
基于这些特性,通常称Spring为开发架构的粘合剂。
Spring核心
Spring为企业级开发提供了丰富的功能,这些功能的底层都依赖于它的两个核心特性:
- 控制反转(Inversion of Control,IOC): 将对象创建权利交给Spring工厂进行管理
- 面向切面编程(aspect-oriented programming,AOP): 基于动态代理的功能增强方式
小结
- Spring技术的核心是:控制反转(IoC)、面向切面(AOP)
04_IOC介绍-解耦的思想
目标
- 能够说出程序中代码解耦的思路
路径
- 优质程序代码的制作原则
- 耦合和解耦
- 解耦的思想
优质程序代码的制作原则
程序书写的目标:高内聚,低耦合
-
耦合(Coupling):
-
代码书写过程中所使用技术的结合紧密度,用于衡量软件中各个模块之间的互联程度
A.jar |-- Hello.java B程序中导入A.jar后,书写代码: Hello hello = new Hello(); //结合紧密度高(高耦合)
-
内聚(Cohesion):
-
代码书写过程中单个模块内部各组成部分间的联系,用于衡量软件中各个功能模块内部的功能联系
-
结论:
- 同一个模块内的各个元素之间要高度紧密(高内聚)
- 不同模块之间的相互依赖程序不要过于紧密(低耦合)
-
好处:
- 便于代码的长期维护和扩展
耦合和解耦
问题:早期我们的 JDBC 操作,注册驱动时,我们为什么不使用 DriverManager 的 register 方法,而是采用 Class.forName 的方式?
public static void main(String[] args) throws SQLException {
// 注册驱动(绑定死MySQL驱动类)
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
//获取数据库连接
String url="jdbc:mysql://127.0.0.1:3306/itheima";
Connection con = DriverManager.getConnection(url, "root", "itheima");
//后续代码省略......
}
原因就是:我们的类依赖了数据库的具体驱动类(MySQL),如果这时候更换了数据库(如:Oracle), 需要修改源码来重新数据库驱动。这显然不方便程序后期的维护。
存在的问题:耦合性高
解耦的思想
解决程序耦合问题的思路:
/**
* 程序的耦合
* 耦合:程序间的依赖关系
* 包括:
* 类之间的依赖
* 方法间的依赖
* 解耦: 降低程序间的依赖关系
* 实际开发中:
* 应该做到:编译期不依赖,运行时才依赖。
*
* 解耦的思路:
* 第一步:使用反射来创建对象,而避免使用 new 关键字。
* 第二步:通过读取配置文件来获取要创建的对象全限定类名
*/
在讲解 jdbc 时,我们是通过反射技术来注册驱动的,代码如下:
Class.forName("com.mysql.jdbc.Driver"); //此处只是一个字符串
public class DecoupleDemo {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
// 1. 加载数据库驱动
Class.forName("com.mysql.jdbc.Driver"); //API: forName(String s)
// 2. 建立数据库连接
String url = "jdbc:mysql://127.0.0.1:3306/itheima";
Connection con = DriverManager.getConnection(url, "root", "root");
// 3. 获取数据库操作对象
String sql = "select id,name from tb_user";
PreparedStatement pstmt = con.prepareStatement(sql);
// 4. 执行sql语句,并且获取结果
ResultSet rs = pstmt.executeQuery();
// 5. 处理结果
while (rs.next()) {
System.out.println(rs.getString("name"));
}
//6. 释放资源
rs.close();
pstmt.close();
con.close();
}
}
此时的好处是,我们的类中不再依赖具体的驱动类,此时就算删除mysql的驱动jar包,依然可以编译(运行就不要想了,没有驱动不可能运行成功的)。
同时,也产生了一个新的问题,mysql 驱动的全限定类名字符串是在 java 类中写死的,一旦要改还是要修改源码。
解决方案:使用配置文件 (jdbc程序中读取db.properties配置文件)
### db.properties ###
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/itheima
jdbc.name=root
jdbc.password=itheima
小结
-
耦合:程序间的依赖关系(类之间的依赖、方法间的依赖)
-
解耦:降低程序间的依赖关系
-
解耦的思路:
- 第一步:使用反射来创建对象,而避免使用 new 关键字
- 第二步:通过读取配置文件来获取要创建的对象全限定类名
-
在开发中应该做到:编译期不依赖,运行时才依赖
05_IOC介绍-IOC思想
目标
- 能够说出IOC思想
路径
- IOC的定义
- IOC思想的代码演变
IOC的定义
IOC:控制反转。( 英文全称: inversion of control )
- 控制:对象的控制权(如:创建、销毁)
- 反转:对象的控制权从开发者手里转移到工厂中
由主动初始化到被动由工厂创建的这个过程,叫做控制反转(即IOC):工厂+反射+配置文件
以前:在获取对象时,都是采用new的方式(控制权在开发者手中。主动获取)
现在:获取对象时,跟工厂要。有工厂为我们创建对象(控制权从开发者手里转移到工厂中。被动获取)
这种被动获取对象的思想就是控制反转,它是spring框架的核心之一。
它的作用只有一个:削减计算机程序的耦合。
- 解耦(不是解决当前问题,而是为了对未来兼容)
IOC思想的代码演变
从学习Java开始到现在,大家的编程思想一直在升级,现已升级到:使用工厂+反射+配置文件
创建对象
IOC思想代码演变:
//需求:创建service层对象
/* 1. 主动创建对象 */
UserServiceImpl userService = new UserServiceImpl();
// 存在的问题:耦合严重。 当service层类需要变动,左右两遍都要修改。
/* 2. 面向接口编程 (多态) */
UserSerivce userService = new UserServiceImpl();
// 好处:解耦。 当dao层实现类需要变动,等号左边代码不需要修改。
// 缺点:等号右边代码还要变动。
/* 3. 反射 + 配置文件 */
ResourceBundle bundle = ResourceBundle.getBundle("service");//读取配置文件
String userServiceClassName = bundle.getString("userService");//获取配置文件中信息
Class userServiceCalss = Class.forName(userServiceClassName);//反射获取类的Class对象
UserService userService = (UserService) userServiceCalss.newInstance();//实例化
// 好处: 进一步解耦。 当service层实现类需要变动,不需要修改代码(直接修改配置文件即可)
// 缺点: 代码多。 (对程序员来讲)
/* 4. 工厂模式 (工厂+反射+配置文件) */
UserService userService = (UserService) BeanFactory.getBean("userService");
// 好处: 封装了创建对象的方法,更好的管理对象。
小结
IOC思想:对象的控制权从开发者手里转移到工厂中
Spring框架的底层也是使用:工厂类、反射、配置文件
框架做的事:
- 工厂类
- 制定配置文件编写规范
框架的使用者做的事:
- 编写实现类
- 进行配置
- 用工厂获取对象
06_Spring中的工厂
目标
- 能够使用ApplicationContext加载配置文件
路径
- Spring工厂结构介绍
- 使用ApplicationContext工厂加载配置文件
Spring工厂结构介绍
ApplicationContext是一个接口,提供了访问spring容器的API
- BeanFactory接口是ApplicationContext的父接口
- BeanFactory是spring容器中的顶层接口,定义了bean相关的最基本操作
- ApplicationContext在BeanFactory基础上追加了若干新功能
ApplicationContext是一个接口实现类:
- ClassPathXmlApplicationContext是ApplicationContext接口的实现类
- 作用:加载类路径下xml配置文件
- 实现技术:xml解析
- AnnotationConfigApplicationContext是ApplicationContext接口的实现类
- 作用:加载注解配置
- 实现技术:反射
- FileSystemXmlApplicationContext (了解即可)
- 从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置
使用ApplicationContext工厂加载配置文件
配置文件:
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 创建spring控制的资源
id : 是这个bean(类)的标识。 【见名知其意】
class : 指定实现类的全限定名。
-->
<bean id="userService" class="com.itheima.example.service.impl.UserServiceImpl"/>
<!-- 新增的spring资源:学生业务类 -->
<bean id="StudentService" class="com.itheima.spring.appcontext.impl.StudentServiceImpl"/>
</beans>
测试类代码:
package com.itheima.spring.appcontext;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ApplicationContextDemo1 {
@Test
public void testApplicationContext(){
/**
* ApplicationContext : 父接口
* ClassPathXmlApplicationContext : ApplicationContext接口的实现类
* 作用:加载类路径下xml配置文件
* 实现技术: xml解析
*/
//加载指定的xml配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取Spring管理的资源。 通过配置文件中的<bean>标签中的id属性值
StudentService studentService = (StudentService) ctx.getBean("StudentService");
//调用方法
studentService.sayHello();
}
}
小结:
-
ApplicationContext提供了访问Spring容器的API
-
使用Spring工厂加载配置文件的方式:
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
07_Spring的IOC配置-bean标签
目标
- 能够在配置文件中使用bean标签配置Spring资源
路径
- bean标签的介绍
- 获取bean标签配置的Spring容器中的资源
- bean标签中id和name的区别
bean标签的介绍
在前面使用Spring编写代码时:通过ApplicationContext工厂,获取配置文件中所定义的资源
- 资源的定义是使用
<bean>
标签
bean标签:
-
作用:
- 定义spring中的资源,受此标签定义的资源将受到spring控制(用于配置让spring来创建的对象)
-
书写格式:
<beans> <!-- 定义spring中的资源 --> <bean></bean> </beans>
-
基本属性:
<bean id="beanId" name="beanName" class="ClassName"></bean>
- id:bean的名称, 可以通过id值获取bean定义的资源。(唯一)
- name:bean的名称,可以通过name值获取bean定义的资源。(唯一)【类似于别名】
- class:bean的类型 (全限定名)
获取bean标签配置的Spring容器中的资源
案例:获取bean标签定义的资源
-
第1步:配置文件
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- name和id的作用相似, 可以通过name获取bean --> <bean id="userService2" name="userService3,userService4" class="com.itheima.spring.bean.UserServiceImpl"/> </beans>
- 说明:name属性是定义别名的,可以指定多个名称。
-
第2步:测试类
public class SpringBeanDemo1 { @Test public void testBeanMethod1(){ //加载指定的xml配置文件 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); //获取Spring容器中的资源(通过id 或 name都可以获取到) //通过id获取 // UserService userService = (UserService) ctx.getBean("userService2"); //通过name获取 // UserService userService = (UserService) ctx.getBean("userService3"); UserService userService = (UserService) ctx.getBean("userService4"); //调用方法 userService.save(); } }
bean标签中id和name的区别
<bean id="userService2" class="com.itheima.spring.bean.UserServiceImpl"/>
<bean name="userService3" class="com.itheima.spring.bean.UserServiceImpl"/>
- bean中的id属性:bean的唯一标识符(只能设置一个)
- bean中的name属性:bean的别名(可以设置多个)
注意细节:
-
不管是标识符,还是别名,在容器中必需唯一(如果不唯一,显然不知道获取的到底是哪一个bean)
-
同时设置了id和name属性,那么id设置的即是唯一标识符,name设置的是别名
-
同时设置了id和name属性,并且id和name的值相同,spring容器会自动检测并消除冲突,这个bean就只会有标识符,没有别名
-
只设置了name属性(没有id属性),那么name属性就是作为bean的唯一标识符。并且name的值在spring容器中必须唯一
-
没有设置id,而name属性设置了多个值,那么name的第一个值会被用作标识符,其他的值被视为别名
- 如果设置了id,那么name的所有值都是别名
08_Spring的IOC配置-bean的作用域
目标
- 能够使用Spring切换单例或多例
路径
- bean的作用域介绍
- 设置bean作用域的代码示例
bean的作用域介绍
在程序中,想要使用spring所创建的对象是单例模式,需要对bean标签进行作用域设置。
在bean标签中使用scope
属性,可以设置bean的作用域范围:
<bean scope="singleton"></bean>
-
scope属性的取值:
- singleton:设定创建出的对象保存在spring容器中,是一个单例的对象
- prototype:设定创建出的对象保存在spring容器中,是一个非单例的对象
- request、session、application、 websocket :设定创建出的对象放置在web容器对应的位置 (了解)
设置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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
scope : 作用域范围
1. singleton : 单例 (默认值)
1). 这个类在容器只会有一个实例
2). 饿汉单例 : 工厂加载配置文件的时候,实例就创建了
效率高
2. prototype : 多例
1). 这个类在容器有多个实例
2). 懒汉多例 : 工厂加载配置文件的时候,没有实例, 获取的时候才创建
3. 运用:
1). 单例: 全工程只要一个实例 (例:连接池, 线程池, 工厂...)
2). 多例: 全工程需要多个实例 (例:连接, 线程 ... )
-->
<bean id="singleUserService" scope="prototype" class="com.itheima.spring.bean.UserServiceImpl"/>
</beans>
修改实现类:
public class UserServiceImpl implements UserService{
//添加:构造方法
public UserServiceImpl(){
System.out.println("UserServiceImpl构造器");
}
public void save(){
System.out.println("执行保存功能....");
}
}
测试类:
public class SpringSingleBeanDemo {
@Test
public void testSingleBeanMethod(){
//加载指定的xml配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取Spring容器中的资源
UserService userService1 = (UserService) ctx.getBean("singleUserService");
UserService userService2 = (UserService) ctx.getBean("singleUserService");
//测试:输出
System.out.println(userService1);
System.out.println(userService2);
}
}
//输出结果:
UserServiceImpl构造器
UserServiceImpl构造器
com.itheima.spring.bean.UserServiceImpl@3043fe0e
com.itheima.spring.bean.UserServiceImpl@78e67e0a
09_Spring的IOC配置-bean的生命周期
目标
- 了解单例bean的生命周期和多例bean的生命周期的区别
路径
- bean的生命周期介绍
- bean生命周期的代码示例
bean的生命周期介绍
在程序中,一个对象从创建到销毁的过程,就是该对象的生命周期。
通过spring来创建的bean对象,也同样具有生命周期:
- 单例对象:scope="singleton"
- 一个应用只有一个对象实例。它的作用范围就是整个应用。
- 生命周期:
- 对象出生:当应用加载,创建容器时,对象就被创建了。
- 对象活着:只要容器在,对象一直活着。
- 对象死亡:当应用卸载,销毁容器时,对象就被销毁了。
- 多例对象:scope="prototype"
- 每次访问对象时,都会重新创建对象实例。
- 生命周期:
- 对象出生:当使用对象时,创建新的对象实例(getBean)。
- 对象活着:只要对象在使用中,就一直活着。
- 对象死亡:当对象长时间不用时,会被java的垃圾回收器回收。
可以在bean标签中,使用init-method
,destroy-method
两个属性,分别定义bean对象在初始化或销毁时要完成的工作
<bean init-method="指定初始化方法" destroy-method="指定销毁方法"></bean>
- init-method属性值: bean对应的类中初始化方法的名字
- destroy-method属性值:bean对应的类中销毁方法的名字
注意事项:
-
当scope=“singleton”时,spring容器中有且仅有一个对象,指定的初始化方法在创建容器时仅执行一次
-
当scope=“prototype”时,spring容器要创建同一类型的多个对象,初始化方法在每个对象创建时均执行一次
-
当scope=“singleton”时,关闭容器会导致bean实例的销毁,调用指定的销毁方法一次
-
当scope=“prototype”时,对象的销毁由垃圾回收机制gc()控制,销毁方法将不会被执行
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
bean的生命周期方法
0. 概念
生命周期: 从创建到销毁的整个过程
bean的生命周期方法 : 在一个bean从创建到销毁的整个过程中执行的方法
1. init-method : 用来指定bean的init方法(初始化)
执行时机: 此方法bean创建的时候调用
适合 : 初始化数据
2. destroy-method : 用来指定bean的destroy方法(销毁)
此方法bean销毁的时候调用
适合 : 保存数据,释放资源
底层原理:
Class clazz = Class.forName("com.itheima.service.impl.UserServiceImpl");
Object obj = clazz.newInstance(); // 通过空参构造创建实例
//在类中,找到名为 myInit 的public空参方法
Method method = clazz.getMethod("myInit");
//调用方法
method.invoke(obj);
单例:
1. 初始化:工厂(ioc容器)创建时bean就会被加载, bean的init方法就会执行
2. 销毁:程序终止, 工厂(ioc容器)销毁,bean也会随之销毁,destroy方法就会执行
多例:
1. 初始化:每从ioc容器中获取一个bean,就会创建一个bean,init方法就会被调用一次
2. 销毁:bean对象不由ioc容器管理, ioc容器销毁, bean不会随之销毁的,destroy不执行
由GC管理(垃圾回收器)
-->
<bean id="lifecycleUserService" scope="singleton" class="com.itheima.spring.bean.UserServiceImpl"
init-method="myInit"
destroy-method="myDestroy"/>
</beans>
修改实现类:
public class UserServiceImpl implements UserService{
public UserServiceImpl(){
System.out.println("UserServiceImpl构造器");
}
@Override
public void save(){
System.out.println("执行保存功能....");
}
//添加:初始化方法
public void myInit(){
System.out.println("UserServiceImpl类中初始化方法");
}
//添加:销毁方法
public void myDestroy(){
System.out.println("UserServiceImpl类中销毁方法");
}
}
测试类:
public class SpringBeanLifecycleDemo {
@Test
public void testLifecycleBeanMethod(){
//加载指定的xml配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取Spring容器中的资源
UserService userService1 = (UserService) ctx.getBean("lifecycleUserService");
UserService userService2 = (UserService) ctx.getBean("lifecycleUserService");
/* 工厂销毁 (当程序运行结束时,工厂就会销毁)
1. 如果程序正常运行终止, 工厂是会销毁的,但是因为demo的运行太快, destroy有执行
但是时间太短,看不到destroy,所以现在手动调用close方法
2. close方法是属于 ClassPathXmlApplicationContext特有的(要强制类型转换)
*/
((ClassPathXmlApplicationContext)ctx).close();
}
}
//运行结果: 当bean设置 scope="singleton"
UserServiceImpl构造器
UserServiceImpl类中初始化方法
UserServiceImpl类中销毁方法
//运行结果: 当bean设置 scope="prototype"
UserServiceImpl构造器
UserServiceImpl类中初始化方法
UserServiceImpl构造器
UserServiceImpl类中初始化方法
10_Spring的IOC配置-bean对象创建方式
目标
- 能够通过配置的spring资源创建bean对象
路径
- 方式一:直接配置
- 方式二:静态工厂
- 方式三:实例工厂
方式一:直接配置
<!-- 将UserService实现类装配到容器中 -->
<bean id="userService" class="com.itheima.spring.bean.UserServiceImpl"/>
通过bean标签的配置,spring会利用反射来创建这个对象并装配到容器中,通过反射创建这个对象时是默认使用类的无参构造方法来实例化bean的
- 应用场景:在配置的时候,知道实现类的全限定名 (一般自己写bean)
- 底层原理:无参构造 (要求类中必须有无参构造方法)
- 缺点:开发者需要知道类名
方式二:静态工厂
除了通过调用bean的无参构造方法创建对象之外,spring还提供了两种工厂创建方式:
- 静态工厂:创建对象的方法是静态
- 实例工厂:创建对象的方法是非静态的 (仅了解)
使用静态工厂的形式创建bean :
<!-- 通过静态工厂方法创建对象并装配到容器中 -->
<bean id="beanId" class="FactoryClassName" factory-method="factoryMethodName"></bean>
- 注意事项:
- class属性值,必须配置成静态工厂的类名
- factory-method属性值,设置为工厂中的静态方法名
代码示例:
- UserService实现类
/*
UserService实现类:UserServiceImpl2
*/
public class UserServiceImpl2 implements UserService {
private int number;
//有参构造方法
public UserServiceImpl2(int number) {
this.number = number;
}
//无参构造方法
pubic UserServiceImpl2(){
}
@Override
public void save() {
System.out.println("执行保存功能....");
}
}
- 工厂类
/*
静态工厂: 方法是静态的
*/
public class StaticFactory {
//静态方法
public static UserService getBean(){
//UserService userService = new UserServiceImpl2(10);
UserService userService = new UserServiceImpl2();
return userService;
}
}
- 配置文件
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
如果一个类没有无参构造方法,就不能用<bean id="" class="">方式配置。可以使用:
1. 静态工厂
2. 实例工厂
# 静态工厂的原理
Class clazz = Class.forName("com.itheima.spring.bean.factory.StaticFactory");
Method getBean = clazz.getMethod("getBean");
UserService service = getBean.invoke(null);
map.put("userService2",service);
-->
<bean id="userService2"
class="com.itheima.spring.bean.factory.StaticFactory"
factory-method="getBean"/>
</beans>
- 测试类
public class StaticFactoryTest {
@Test
public void testStaticFactoryNewObject(){
//加载指定的xml配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取Spring容器中的资源
UserService userService = (UserService) ctx.getBean("userService2");
//调用方法
userService.save();
}
}
方式三:实例工厂 (了解)
使用实例工厂的形式创建bean :
<!-- 通过实例工厂方法创建对象并装配到容器中 -->
<bean id="beanId" factory-bean="factoryBeanId" factory-method="factoryMethodName"></bean>
注意事项:
-
factory-bean属性值,设置为实例工厂的beanId
-
使用实例工厂创建bean,首先要配置实例工厂的bean交由spring进行管理
<!-- 实例工厂对象 --> <bean id="beanId" class="com.itheima.spring.bean.factory.InstanceFactory"/>
-
-
factory-method属性值,设置为工厂中的非静态方法名
代码示例:
- 工厂类
/*
* 实例工厂: 方法是非静态
* */
public class InstanceFactory {
//非静态方法
public UserService getBean() {
UserService userService = new UserServiceImpl2();
return userService;
}
}
- 配置文件
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
# 实例工厂的原理
clazz = Class.forName("com.itheima.factory.InstanceFactory");
if = clazz.newInstance();
getBean = clazz.getMethod("getBean")
UserService service = getBean.invoke(if);
map.put("userService3",service);
-->
<!-- 实例工厂对象 -->
<bean id="if" class="com.itheima.spring.bean.factory.InstanceFactory"/>
<!-- UserService对象 -->
<bean id="userService3" factory-bean="if" factory-method="getBean"/>
</beans>
- 测试类
public class InstanceFactoryTest {
@Test
public void testInstanceFactoryNewObject(){
//加载指定的xml配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取Spring容器中的资源
UserService userService = (UserService) ctx.getBean("userService3");
//调用方法
userService.save();
}
}
小结
- 在开发中,通常就是使用:直接装配方式
- 要求:装配的类,必须有无参构造方法
- 当自定义类没有无参构造方法时,通常使用:静态工厂装配bean
11_Spring的IOC配置-依赖注入
目标
- 能够使用Spring的依赖注入给成员变量赋值
路径
- 依赖注入的介绍
- setter注入
- 构造器注入
- 集合类型数据注入
依赖注入的介绍
在我们之前书写的程序中,是通过控制反转(IOC),把对象的创建交给了Spring,由Spring容器创建bean对象。但是这种方式仅仅是降低了代码中的依赖关系,并不会完全消除依赖。例如:业务层要调用dao层的方法
//业务层
public class UserServiceImpl3 implements UserService {
//dao层对象
private UserDao userDao;//成员变量
//无参构造方法
public UserServiceImpl3(){
//1.加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.获取Spring容器中的资源
userDao = (UserDao) ctx.getBean("userDao");//仅仅只是让Spring创建bean对象,降低了依赖关系。 但还是需要自己书写代码接收Spring创建的bean对象。
}
//保存用户
public void save(User user) {
//调用dao层对象中的添加用户方法
userDao.save(user);
}
}
问题:能否不让程序员书写接收Spring创建bean对象的代码?
解决方案:依赖注入(DI => Dependency Injection)
- 所谓的依赖注入,可以先简单的理解为由spring框架以解耦的方式将dao对象传递到业务层中,简称依赖注入
结论:IOC与DI是同一件事,只是站在不同角度看待问题
setter注入
问题:常用的给类中成员变量赋值的方式有几种?
答案:2种。 1:setter方法、 2:构造方法
依赖注入 - setter注入方式:
<bean id="beanId" class="ClassName">
<!-- 给bean对象中的成员赋值(依赖注入) -->
<property name="propertyName" value="propertyValue" ref="beanId"/>
</bean>
- property标签:
- name:对应bean中的属性名,要求该属性必须提供可访问的setter方法
- value:设定非引用类型(8大基本类型和String)属性对应的值。【不能与ref同时使用】
- ref:设定引用类型属性对应bean的id。【不能与value同时使用】
- 注意:一个bean可以有多个property标签
代码演示:
- 业务类
//业务层
public class UserServiceImpl3 implements UserService {
private int num; //基本类型
private String name; //String类型
private UserDao userDao; //dao层对象
private Date birthday; //Date类型
//无参构造方法
public UserServiceImpl3(){
}
public void save(User user) {
System.out.println("成员变量 num:"+num);
System.out.println("成员变量 name:"+name);
System.out.println("成员变量 birthday:"+birthday);
//调用dao层对象中的添加用户方法
userDao.save(user);
}
//setter&getter方法
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
- 配置文件
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
set注入
1. 原理 : 空参构造 + set方法
clazz = Class.forName("com.itheima.service.impl.UserServiceImpl3");
service = class.newInstance(); //
setName = clazz.getMethod("setName")
setName.invoke(service,"zs");
// service.setName("zs");
2. 配置 : bean标签内子标签property
1). name : bean中的属性名
2). 值
value : 写基本类型、字符串、包装类
ref: 引用类型
-->
<!-- UserDao对象 -->
<bean id="userDao" class="com.itheima.spring.bean.UserDao"/>
<!-- 日期类型 -->
<bean id="birthday" class="java.util.Date"/>
<!-- UserService对象 -->
<bean id="userService4" class="com.itheima.spring.bean.UserServiceImpl3">
<!-- 注入属性值 -->
<property name="num" value="100"/>
<property name="name" value="黑马"/>
<property name="birthday" ref="birthday"/>
<property name="userDao" ref="userDao"/>
</bean>
</beans>
- 测试类
public class SetterTest {
@Test
public void testPropertySetter(){
//加载指定的xml配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取Spring容器中的资源
UserService userService = (UserService) ctx.getBean("userService4");
//调用方法
userService.save(new User());
}
}
//输出结果:
成员变量 num:100
成员变量 name:黑马
成员变量 birthday:Wed Apr 20 19:04:35 CST 2021
UserDao => 执行添加用户的功能...
构造器注入
依赖注入 - 构造器注入方式:
<bean id="beanId" class="ClassName">
<constructor-arg name="argsName" value="argsValue" ref="beanId"/>
</bean>
- constructor-arg标签:
- name:对应bean中的构造方法所携带的参数名
- value:设定非引用类型构造方法参数对应的值。【不能与ref同时使用】
- ref:设定引用类型构造方法参数对应bean的id。【不能与value同时使用】
代码演示:
-
前置要求:类中的必须有对应的构造方法(带参数的构造方法)
-
业务类
public class UserServiceImpl3 implements UserService {
private int num; //基本类型
private String name; //String类型
private UserDao userDao; //dao层对象
private Date birthday; //Date类型
//有参构造方法
public UserServiceImpl3(int num , String name, UserDao userDao, Date date){
this.num = num;
this.name = name;
this.userDao= userDao;
this.birthday = date;
}
//无参构造方法
public UserServiceImpl3(){
}
public void save(User user) {
System.out.println("成员变量 num:"+num);
System.out.println("成员变量 name:"+name);
System.out.println("成员变量 birthday:"+birthday);
//调用dao层对象中的添加用户方法
userDao.save(user);
}
}
- 配置文件
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
构造器注入 (了解)
1. 原理
clazz = Class.forName("com.itheima.service.impl.UserServiceImpl3");
contructor = clazz.getConstructor(String.class,int.class,UserDao.class,Date.class);
service = contructor.newInstance("zs",18,userDao,myDate);
map.put("userService44",service);
2. 配置:bean标签的子标签constructor-arg
name属性 : 构造方法中参数的名字
value属性: 非引用类型值
ref属性: 引用类型值
-->
<bean id="userDao" class="com.itheima.spring.bean.UserDao"/>
<bean id="birthday" class="java.util.Date"/>
<bean id="userService4" class="com.itheima.spring.bean.UserServiceImpl3">
<constructor-arg name="num" value="100"/>
<constructor-arg name="name" value="黑马"/>
<constructor-arg name="userDao" ref="userDao"/>
<!-- 构造方法中参数名:date -->
<constructor-arg name="date" ref="birthday"/>
</bean>
</beans>
- 测试类
public class ConstructorTest {
@Test
public void testPropertyConstructor(){
//加载指定的xml配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取Spring容器中的资源
UserService userService = (UserService) ctx.getBean("userService4");
//调用方法
userService.save(new User());
}
}
//输出结果:
成员变量 num:100
成员变量 name:黑马
成员变量 birthday:Wed Apr 20 19:28:42 CST 2021
UserDao => 执行添加用户的功能...
集合类型数据注入
依赖注入 - 集合类型数据注入:
- 集合:List、Set、Map、Properties
<!-- List类型数据注入 -->
<bean id="beanId" class="className">
<property name="成员变量名">
<list>
<value>元素</value>
</list>
</property>
</bean>
<!-- Set类型数据注入 -->
<bean id="beanId" class="className">
<property name="成员变量名">
<set>
<value>元素</value>
</set>
</property>
</bean>
<!-- 数组类型数据注入 -->
<bean id="beanId" class="className">
<property name="成员变量名">
<array>
<value>元素值</value>
</array>
</property>
</bean>
<!-- Map类型数据注入 -->
<bean id="beanId" class="className">
<property name="成员变量名">
<map>
<entry key="key元素" value="value元素"/>
</map>
</property>
</bean>
<!-- Properties类型数据注入 -->
<bean id="beanId" class="className">
<property name="成员变量名">
<props>
<prop key="key元素">value元素</prop>
</props>
</property>
</bean>
代码示例:
- 业务类
public class UserServiceImpl4 implements UserService {
private List list;//List集合
private Set set;//Set集合
private Map map;//Map集合
private Properties properties;//属性集
private int[] arrry;//数组
//无参构造方法
public UserServiceImpl4() {
}
@Override
public void save(User user) {
System.out.println("执行保存功能....");
System.out.println("List集合:"+list);
System.out.println("Set集合:"+set);
System.out.println("Map集合:"+map);
System.out.println("Properties集合:"+properties);
System.out.println("数组:"+ Arrays.toString(arrry));
}
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
public Set getSet() {
return set;
}
public void setSet(Set set) {
this.set = set;
}
public Map getMap() {
return map;
}
public void setMap(Map map) {
this.map = map;
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
public int[] getArrry() {
return arrry;
}
public void setArrry(int[] arrry) {
this.arrry = arrry;
}
}
- 配置文件
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
# 集合类型数据注入
1. properties标签的name属性指定的是UserServiceImpl4中对应的成员变量名
2. properties的子标签
1). list : 声明该属性是List类型
2). props : 声明该属性是Properties类型
3). array : 声明该属性是数组类型
4). set : 声明该属性是Set类型
5). map : 声明该属性是Map类型
原理:
clazz = Class.forName("com.itheima.service.impl.UserServiceImpl5")
service = clazz.newInstance();
setList = service.getMethod("setList",List.class);
List list = new ArrayList();
list.add("zs");
list.add("ls");
list.add("ww");
setList.invoke(service,list);// service.setList(list)
-->
<bean id="userService5" class="com.itheima.spring.bean.UserServiceImpl4">
<!-- 注入:List集合 -->
<property name="list">
<list>
<value>上海黑马</value>
<value>北京黑马</value>
</list>
</property>
<!-- 注入:Set集合 -->
<property name="set">
<set>
<value>上海</value>
<value>杭州</value>
</set>
</property>
<!-- 注入:Map集合 -->
<property name="map">
<map>
<entry key="sh" value="上海黑马程序员"/>
<entry key="bj" value="北京黑马程序员"/>
</map>
</property>
<!-- 注入:Properties属性集 -->
<property name="properties">
<props>
<prop key="name">张三</prop>
<prop key="age">20</prop>
</props>
</property>
<!-- 注入:数组 -->
<property name="arrry">
<array>
<value>100</value>
<value>1000</value>
</array>
</property>
</bean>
</beans>
- 测试类
public class ContainerTest {
@Test
public void testPropertyContainer(){
//加载指定的xml配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取Spring容器中的资源
UserService userService = (UserService) ctx.getBean("userService5");
//调用方法
userService.save(new User());
}
}
//输出结果:
执行保存功能....
List集合:[上海黑马, 北京黑马]
Set集合:[上海, 杭州]
Map集合:{sh=上海黑马程序员, bj=北京黑马程序员}
Properties集合:{age=20, name=张三}
数组:[100, 1000]
小结
依赖注入:给bean对象中的成员变量注入数据(由Spring IoC容器完成)
依赖注入的方式:
-
Set方法注入
- 通过property标签调用属性的setter方法将数据注入到目标类中
-
构造方法注入
- 提供一个类的有参构造,通过construct-arg标签调用该有参构造将数据注入到目标类中
-
集合类型的注入
- 通过对应的标签,可以给复杂类型的属性注入数据
12_Spring的IOC配置-EL表达式
目标
- 能够在Spring的依赖注入中使用EL表达式
路径
- Spring的EL表达式介绍
- Spring的El表达式示例
Spring的EL表达式介绍
el : expression language 表达式语言
- 含义: 就是数据引用
spring中el表达式:
-
{} //把指定的内容赋值给属性
- ${} //用于加载外部文件中指定的Key值
spring依赖注入中EL表达式的书写格式:
<bean id="beanId" class="className">
<property name="成员变量名" value="EL表达式"/>
</bean>
-
注意:所有成员变量的值不区分是否引用类型,统一使用value赋值
-
示例:
-
常量 : #{10} #{3.14} #
-
引用bean : #
-
引用bean属性 : #
-
运算符支持 : #
-
正则表达式支持 : #{user.name matches‘[a-z]{6,}’}
-
集合支持 : #
-
Spring的El表达式示例
代码示例:
- 业务类
//业务层
public class UserServiceImpl3 implements UserService {
private int num; //基本类型
private String name; //String类型
private UserDao userDao; //dao层对象
private Date birthday; //Date类型
//无参构造方法
public UserServiceImpl3(){
}
public void save(User user) {
System.out.println("成员变量 num:"+num);
System.out.println("成员变量 name:"+name);
System.out.println("成员变量 birthday:"+birthday);
//调用dao层对象中的添加用户方法
userDao.save(user);
}
//setter&getter方法
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
- 配置文件
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
Spring EL
1. ${表达式}
引入配置文件中的数据
2. #{表达式}
强调的是把内容赋值给属性
#{'字符串'}
#{数字}
#{beanId}
-->
<bean id="userDao" class="com.itheima.spring.bean.UserDao"/>
<bean id="birthday" class="java.util.Date"/>
<bean id="userService6" class="com.itheima.spring.bean.UserServiceImpl3">
<!-- 使用EL表达式注入属性值 -->
<property name="num" value="#{100}"/>
<property name="name" value="#{'黑马'}"/>
<property name="birthday" value="#{birthday}"/>
<property name="userDao" value="#{userDao}"/>
</bean>
</beans>
- 测试类
public class SpringElDemo {
@Test
public void testSpringEl(){
//加载指定的xml配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取Spring容器中的资源
UserService userService = (UserService) ctx.getBean("userService6");
//调用方法
userService.save(new User());
}
}
//输出结果:
成员变量 num:100
成员变量 name:黑马
成员变量 birthday:Wed Apr 20 21:25:41 CST 2021
UserDao => 执行添加用户的功能...
13_Spring的IOC配置-引入外部资源文件
目标
- 能够通过读取外部资源文件,实现给bean对象的属性赋值
路径
- Spring中加载外部资源文件
- 示例:给bean对象属性注入外部资源文件中的数据
Spring中加载外部资源文件
Spring提供了读取外部properties文件的机制,使用读取到的数据为bean的属性赋值
操作步骤
-
准备外部properties文件
-
在XML中开启context命名空间支持
xmlns:context="http://www.springframework.org/schema/context"
-
加载指定的properties文件
<context:property-placeholder location="classpath:filename.properties"/>
-
使用加载的数据
<property name="成员变量名" value="${propertiesName}"/>
注意事项:
- 如果需要加载所有的properties文件,可以使用
*.properties
表示加载所有的properties文件 - 读取数据使用${propertiesName}格式进行,其中propertiesName指properties文件中的属性名
示例:给bean对象属性注入外部资源文件中的数据
代码示例:
-
外部资源文件(data.properties)
name=heima num=10
-
业务类
//业务层
public class UserServiceImpl3 implements UserService {
private int num; //基本类型
private String name; //String类型
private UserDao userDao; //dao层对象
private Date birthday; //Date类型
//无参构造方法
public UserServiceImpl3(){
}
public void save(User user) {
System.out.println("成员变量 num:"+num);
System.out.println("成员变量 name:"+name);
System.out.println("成员变量 birthday:"+birthday);
//调用dao层对象中的添加用户方法
userDao.save(user);
}
//setter&getter方法
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
- 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!--
第1步:
schema约束新增: 开启context命名空间支持
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd"
-->
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 第2步:加载指定的properties文件 -->
<context:property-placeholder location="classpath:data.properties"/>
<bean id="userDao" class="com.itheima.spring.bean.UserDao"/>
<bean id="birthday" class="java.util.Date"/>
<bean id="userService7" class="com.itheima.spring.bean.UserServiceImpl3">
<!--
第3步: 使用外部资源文件中的数据
格式: ${外部文件中的key}
-->
<property name="num" value="${num}"/>
<property name="name" value="${name}"/>
<property name="birthday" value="#{birthday}"/>
<property name="userDao" value="#{userDao}"/>
</bean>
</beans>
- 测试类
public class SpringPropertiesTest {
@Test
public void testSpringOuterProperties(){
//加载指定的xml配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取Spring容器中的资源
UserService userService = (UserService) ctx.getBean("userService7");
//调用方法
userService.save(new User());
}
}
//输出结果:
成员变量 num:10
成员变量 name:heima
成员变量 birthday:Wed Apr 20 21:53:04 CST 2021
UserDao => 执行添加用户的功能...
小结
在Spring中,EL表达式有两种使用方式:
-
- 把{ }中指定的内容,赋值给一个属性
- $
- 从外部资源文件中,获取数据,赋值给bean对象中的属性
- { }中书写的是外部资源文件(.properties)中的key