Spring-day01 IoC
# 框架阶段
1. 时间 (8天)
1). spring : 3天
2). springmvc : 2天
3). maven高级 : 1天
5). springboot 1天
6). 综合案例: 1天
2. SSM
1). springmvc (web层)
2). spring (service,dao层)
3). mybatis (dao层)
1)Spring简介
1.1)什么是框架 (framework)
源自于建筑学,隶属土木工程,后发展到软件工程领域
软件工程框架:经过验证的,具有一定功能的,半成品软件
经过验证
具有一定功能
半成品
1.2)框架的作用
1.3)Spring是什么
Spring是一个开源框架,Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。
轻量级:与EJB对比,依赖资源少,消耗的资源少。
分层: 一站式,每一个层都提供的解决方案
- web层:struts2,Spring-MVC
- service层:spring
- dao层:hibernate,mybatis , jdbcTemplate —> spring-data
1.4)Spring的发展历史
java :
- SE: standard edition 标准
- ME: micro edition 微型
- EE: enterprice 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)<br />
阐述了J2EE开发不使用EJB的解决方式(Spring雏形)
2017年9月份发布了spring的最新版本—spring 5.0通用版
备注:EJB说白了就是把编写的软件中那些需要执行制定的任务的类,不放到客户端软件上了,而是给他打成包放到一个服务器上;
1.5)Spring的体系结构
1.6)Spring优势
Spring 出现是为了解决JavaEE 实际问题:
方便解耦,简化开发 (IOC)
Spring就是一个大工厂(容器),可以将所有对象创建和依赖关系维护,交给Spring管理
Spring工厂是用于生成beanAOP编程的支持
Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能声明式事务的支持
只需要通过配置就可以完成对事务的管理,而无需手动编程方便程序的测试
Spring对Junit4支持,可以通过注解方便的测试Spring程序方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持降低JavaEE API的使用难度
Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低
基于这些特性,我们也会俗称Spring为开发架构的粘合剂。
1.7)Spring核心
Spring为企业级开发提供了丰富的功能,这些功能的底层都依赖于它的两个核心特性:
- 控制反转(Inversion of Control,IOC)
- 面向切面编程(aspect-oriented programming,AOP)
Spring类似于航母,可以集成其他的框架
2)IoC简介
2.1)优质程序代码的制作原则
耦合(Coupling):代码书写过程中所使用技术的结合紧密度,用于衡量软件中各个模块之间的互联程度
- 耦合可以发生在方法与方法之间,类与类之间、模块与模块之间等;
- eg:A方法的实现调用并依赖了B方法,我们就说A与B方法存在耦合;
- 内聚(Cohesion):代码书写过程中单个模块内部各组成部分间的联系,用于衡量软件中各个功能模块内部的功能联系
程序书写的目标:高内聚,低耦合
- 就是同一个模块内的各个元素之间要高度紧密,但是各个模块之间的相互依存度却不要那么紧密
- 好处: 便于代码的长期维护和扩展
# 场景: 人打开门
1. 人
2. 门 : 打开
内聚 : 打开这个行为,脱离了'门'没有意义, 所以'打开'设计给'门'
耦合 : 如果把'打开'设计给'人' , 那么'猫' '狗'也可能需要添加'打开',代码冗余,而且脱离不了门, 耦合
2.2)工厂模式的代码演变
package com.itheima.ioc.dao;
public interface UserDao {
void addUser();
void deleteUser();
void updateUser();
void queryUser();
}
package com.itheima.ioc.dao.impl;
import com.itheima.ioc.dao.UserDao;
public class UserDaoImpl implements UserDao {
@Override
public void addUser() {
System.out.println("添加用户");
}
@Override
public void deleteUser() {
System.out.println("删除用户");
}
@Override
public void updateUser() {
System.out.println("修改用户");
}
@Override
public void queryUser() {
System.out.println("查询用户");
}
}
package com.itheima.ioc.service;
public interface UserService {
void add() throws Exception;
}
package com.itheima.ioc.service.impl;
import com.itheima.ioc.dao.UserDao;
import com.itheima.ioc.dao.impl.UserDaoImpl;
import com.itheima.ioc.dao.impl.UserDaoImpl2;
import com.itheima.ioc.service.UserService;
import com.itheima.ioc.util.BeanFactory;
import com.itheima.ioc.util.UnfinishedBeanFactory;
import org.junit.Test;
import java.util.ResourceBundle;
public class UserServiceImpl implements UserService {
@Test
@Override
public void add() throws Exception {
//1. 主动创建对象
//存在的问题:1.代码耦合:UserServiceImpl#add()实现依赖于UserDaoImpl,我们就说
//UserServiceImpl与UserDaoImpl存在耦合
//问题2:如果UserDao接口的方法做了另外一套实现,那么也需要改动代码
// UserDaoImpl userDao = new UserDaoImpl();
// UserDaoImpl2 userDao2=new UserDaoImpl2();
// 2. 面向接口编程 : 解耦(一定程度的解耦)
//思考:UserDao userDao = new UserDaoImpl()只有当前方法使用么?
//答案:显然不是,会构建很多构建userDao的方法
//核心思路:把共性代码提取到一个工具类中,而这段代码仅仅只有生成对象,所以这个工具类可
//称为工厂类
// UserDao userDao = new UserDaoImpl();
// UserDao userDao = new UserDaoImpl2();
//3.构建userDao对象的方法封装到统一工厂中:解耦服务对象与dao对象
// UserDao userDao= (UserDao) UnfinishedBeanFactory.getBean("userDao");
// 4. 反射 + 配置文件 : 进一步解耦
// ResourceBundle bundle = ResourceBundle.getBundle("data");
// String userDaoClassName = bundle.getString("userDao");
// Class<?> clazz = Class.forName(userDaoClassName);
// UserDao userDao = (UserDao) clazz.newInstance();
//5. 工厂模式 : 统一管理bean的创建
//工厂类+反射+配置文件实现最大程度的解耦
//思路:
//1.工厂类不要反复构建对象,尽量让构建好的对象增强复用性,好处:节约内存,且响应速度提升
//如何提高工厂生产的对象的复用性?对象池----》IOC容器
//2.将工厂生产的对象通过静态资源配置后,好处:1.解耦了工厂与资源的耦合 2.避免因资源的调整而反复编译工厂的问题,提高了可维护性
UserDao userDao = (UserDao) BeanFactory.getBean("userDao");
userDao.addUser();
}
}
package com.itheima.ioc.util;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
public class BeanFactory {
//1、事先存储容器
private static Map<String, Object> map = new HashMap<>();
//2、加载配置文件
static {
/*
好处:经动态资源静态配置化,避免了因为资源的调整而带来的反复编译的维护成本
弊端:静态配置文件与资源也会存在耦合,但是耦合已经降到最低了
结论:高内聚 低耦合,而不说高内聚 零耦合?
耦合不能彻底消除,只能降低!
*/
ResourceBundle bundle = ResourceBundle.getBundle("data");
try {
Enumeration<?> enumeration = bundle.getKeys();
while (enumeration.hasMoreElements()) {
String key = (String) enumeration.nextElement();
String value = (String) bundle.getString(key);
//3、实例化bean
Object beanObject = Class.forName(value).newInstance();
//4、放入容器
map.put(key,beanObject);
}
} catch (Exception e) {
e.printStackTrace();
}
}
//5、公共获得bean
public static Object getBean(String calssName){
return map.get(calssName);
}
}
2.3)Spring发展历程
2.4)IoC
# IOC概念
0. IoC 全称为 Inversion of Control,翻译为 “控制反转”。
1. 控制什么?
控制对象的创建和销毁
2. 反转什么?
对象的控制权(创建和销毁)从主动管理转为交给Spring的容器管理
3. Spring的容器(IOC Container)
Spring控制的资源全部放置在Spring容器中,该容器也称为IoC容器
4. IOC的思想
1). 面向接口编程 (多态)
接口类型 变量 = 接口实现类对象
2). 反射 + 配置文件
3). 工厂模式: 内置容器,管理对象的创建和销毁
5. IOC的作用: 解耦
3)入门案例
spring文档
3.1)案例环境说明
模拟三层架构中表现层调用业务层功能
表现层:UserTest模拟UserServlet(使用@Test方法模拟)
业务层:UserService (spring 在业务层解耦IOC和增强AOP)
3.2)IoC入门案例制作步骤
1.导入spring坐标(5.1.9.release)
2.编写业务层与表现层(模拟)接口与实现类
3.建立spring配置文件
4.配置所需资源(Service)为spring控制的资源
5.表现层(UserTest)通过spring获取资源(Service实例)
代码结构如下
3.2.1)IoC入门案例制作步骤-1
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
</dependencies>
3.2.2)IoC入门案例制作步骤-2
public interface UserService {
//业务方法
void save();
}
3.2.3)IoC入门案例制作步骤-3
public class UserServiceImpl implements UserService {
public void save() {
System.out.println("user service running...");
}
}
3.2.4)IoC入门案例制作步骤-4
配置文件
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">
<!-- 1.创建spring控制的资源
1). id 是这个bean的标识, 可以自定义,但是最好见名知意
2). class 指定实现类的全限定名
-->
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl"/>
</beans>
3.2.5)IoC入门案例制作步骤-5
测试类
public class UserTest {
@Test
public void test01(){
//2.加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//3.获取资源: 通过配置文件中的id
UserService userService = (UserService) ctx.getBean("userService");
userService.save();
}
}
3.3) 入门案例原理
3.31)ApplicationContext
1.ApplicationContext是一个接口,提供了访问spring容器的API
2.ClassPathXmlApplicationContext是一个类,实现了上述功能
3.ApplicationContext的顶层接口是BeanFactory
4.BeanFactory定义了bean相关的最基本操作
5.ApplicationContext在BeanFactory基础上追加了若干新功能
3.32 原理描述
package com.itheima.test;
import com.itheima.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/*
* # IOC重要角色
* 1. 工厂
* 1). BeanFactory 父接口
* 2). ApplicationContext 子接口
* 3). ClassPathXmlApplicationContext 实现类 (加载类路径下xml配置文件的工厂)
* 4). AnnotationConfigApplicationContext 实现类 (加载注解配置的工厂)
* 特点:
* I. 会加载配置文件
* a. properties文件 -> 解析 Properties(Map)/ ResourceBundle
* b. xml文件 -> 解析 sax/dom (dom4j)
* c. 注解 -> 解析 反射
* 语法不同, 解析方案不同
* II. 访问容器的入口
* Map<String,Object>
*
* 2. 配置
* 1). xml配置
* 2). 注解
*
* 3. bean
* 在xml/注解中配置
* 从容器中获取
*
* # 记录
* 1. 快捷键
* 1). ctrl + alt + u : 选中一个类, 查看这个类继承体系
*
* */
public class UserTest {
@Test
public void test01(){
//2.加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// ApplicationContext ctx = new AnnotationConfigApplicationContext();
//3.获取资源: 通过配置文件中的id
UserService userService = (UserService) ctx.getBean("userService");
userService.save();
}
}
4)IoC配置(XML格式)
4.1)bean
名称:bean
类型:标签
归属:beans标签
作用:定义spring中的资源,受此标签定义的资源将受到spring控制
格式:
<beans>
<bean />
</beans>
- 基本属性:
<bean id="beanId" name="beanName1,beanName2" class="ClassName"></bean>
id:bean的名称,通过id值获取bean
class:bean的类型 (全限定名)
name:bean的名称,可以通过name值获取bean,用于多人配合时给bean起别名
代码演示
- 配置文件修改
<!-- name和id的作用相似, 我们也可以通过name获取bean -->
<bean id="userService" name="userService1,userService2" class="com.itheima.service.impl.UserServiceImpl"/>
- 配置文件修改
测试类修改
public class UserTest {
@Test
public void test01(){
//2.加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//3.获取资源: 通过id和name都能获取到bean
// userService,userService1,userService2都可以
// userService3 因为没有指定,所以会报以下异常:
// NoSuchBeanDefinitionException: No bean named 'userService3' available
UserService userService = (UserService) ctx.getBean("userService3");
userService.save();
}
}
4.2)bean属性scope
名称:scope
类型:属性
归属:bean标签
作用:定义bean的作用范围
格式:
<bean scope="singleton"></bean>
取值:
- singleton:设定创建出的对象保存在spring容器中,是一个单例的对象,默认的属性
- prototype:spring容器只负责构建对象,内部不保存维护,是一个非单例的对象
- request、session、application、 websocket :设定创建出的对象放置在web容器对应的位置 (了解)
代码演示
配置文件修改
<!--
scope : 作用范围
1. singleton : 单例 (默认值)
1). 这个类在容器只会有一个实例
2). 饿汉单例 : 工厂加载配置文件的时候,实例就创建了
效率高
2. prototype : 多例
1). 这个类在容器有多个实例
2). 懒汉多例 : 工厂加载配置文件的时候,没有实例, 获取的时候才创建
3. 运用:
1). 单例: 全工程只要一个实例 (连接池,线程池,工厂...)
2). 多例: 全工程需要多个实例 (连接,线程 ... )
-->
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl"
scope="prototype"
/>
- 测试类修改
public class UserServiceImpl implements UserService {
public UserServiceImpl(){
System.out.println("constructor run...");
}
@Override
public void save() {
System.out.println("UserServiceImpl run...");
}
}
@Test
public void test02(){
ApplicationContext ctx
= new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService1 = (UserService) ctx.getBean("userService");
UserService userService2 = (UserService) ctx.getBean("userService");
// System.out.println(userService1);
// System.out.println(userService2);
}
4.3)bean生命周期
Spring中bean对象的创建到销毁的整个过程就是bean的生命周期;
名称:init-method,destroy-method
类型:属性
归属:bean标签
作用:定义bean对象在初始化或销毁时完成的工作
格式:
<bean init-method="init" destroy-method="destroy"></bean>
取值:bean对应的类中对应的具体方法名
注意事项:
当scope=“singleton”时,spring容器中有且仅有一个对象,init方法在创建容器时仅执行一次
当scope=“prototype”时,spring容器要创建同一类型的多个对象,init方法在每个对象创建时均执行一次
当scope=“singleton”时,关闭容器会导致bean实例的销毁,调用destroy方法一次
当scope=“prototype”时,对象的销毁由垃圾回收机制gc()控制,destroy方法将不会被执行
代码演示
实现类修改
public class UserServiceImpl implements UserService {
public UserServiceImpl(){
System.out.println("UserServiceImpl constructor..");
}
@Override
public void save() {
System.out.println("userService save--");
}
public void a(){
System.out.println("init");
}
public void destroy(){
System.out.println("destroy");
}
}
配置文件
<!--
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(); // 通过空参构造创建实例
//在类中,找到名为a的public空参方法
Method method = clazz.getMethod("a");
//调用方法
method.invoke(obj);
饿汉单例:
1. 初始化: 工厂创建,bean就会被加载, bean的init方法就会执行
2. 销毁 : 程序终止, 工厂(ioc容器)销毁,bean也会随之销毁,destroy方法就会执行
懒汉多例 :
1. 初始化 : 每从ioc容器中获取一个bean,就会创建一个bean,init方法就会被调用一次
2. 销毁 : bean对象不由ioc容器管理, ioc容器销毁, bean不会随之销毁的,destroy不执行
由GC管理(垃圾回收器)
-->
<bean id="userService"
scope="prototype"
class="com.itheima.service.impl.UserServiceImpl"
init-method="a"
destroy-method="destroy"
/>
- 测试类修改
@Test
public void method03(){
//1. 创建工厂对象
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//2. 从ioc容器中获取bean
UserService userService = (UserService) context.getBean("userService");
UserService userService2 = (UserService) context.getBean("userService");
/*
工厂销毁(当程序运行结束时, 工厂就会销毁)
1. 如果程序正常运行终止, 工厂是会销毁的,但是因为demo的运行太快, destroy有执行
但是时间太短, 看不到destroy,所以现在手动调用close方法(这个代码没必要写)
2. close方法是属于 ClassPathXmlApplicationContext特有的,ApplicationContext没有
*/
ClassPathXmlApplicationContext ctx = (ClassPathXmlApplicationContext) context;
ctx.close();
}
4.4)bean对象创建方式
# bean对象的创建方式
1. 直接配置
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl"/>
场景: 在配置的时候,知道实现类的全限定名 (一般自己写bean)
底层原理: 空参构造(有参构造涉及到DI依赖注入,后边会讲)
缺陷是: 开发者需要知道类名
2. 工厂方式
1). 静态工厂 : 创建对象的方法是静态
2). 实例工厂 : 创建对象的方法是非静态的
场景: 开发者不知道类名,但是可以通过代码创建实例
I. 匿名内部类
II. 动态代理 : 代理类是运行时动态创建的,开发者不知道类名
除了以上所示的通过调用bean的构造方法创建对象之外,spring还提供了两种工厂创建方式
一般用来配置其他框架的bean
(1)静态工厂
名称:factory-bean
类型:属性
归属:bean标签
作用:定义bean对象创建方式,使用静态工厂的形式创建bean,兼容早期遗留系统的升级工作
格式:
<bean class="FactoryClassName" factory-method="factoryMethodName"></bean>
取值:工厂bean中用于获取对象的静态方法名
注意事项:
class属性必须配置成静态工厂的类名测试代码:
- 新增一个静态工厂类 ```java package com.itheima.service.impl;
import com.itheima.service.UserService;
public class UserServiceImpl2 implements UserService {
int a;
public UserServiceImpl2(int a){
this.a = a;
}
public void save() {
System.out.println("user service2 running...");
}
}
```java
package com.itheima.factory;
import com.itheima.service.UserService;
import com.itheima.service.impl.UserServiceImpl2;
/*
静态工厂: 方法是静态的
*/
public class StaticFactory {
public static UserService getBean(){
UserServiceImpl2 service = new UserServiceImpl2(1);
return service;
}
}
配置文件修改
<!--
如果一个类没有空参构造,就不能用 bean:id,class方法配置
1. 静态工厂
2. 实例工厂
# 静态工厂的原理
clazz = Class.forName("com.itheima.factory.StaticFactory");
getBean = clazz.getMethod("getBean");
UserService service = getBean.invoke(null);
map.put("userService2",service);
-->
<bean id="userService2" class="com.itheima.factory.StaticFactory"
factory-method="getBean"/>
测试类修改
@Test
public void test04(){
ApplicationContext ctx
= new ClassPathXmlApplicationContext("applicationContext.xml");
UserService service = (UserService) ctx.getBean("userService2");
service.save();
}
打印结果:
user service2 running…
(2)实例工厂
名称:factory-bean,factory-method
类型:属性
归属:bean标签
作用:定义bean对象创建方式,使用实例工厂的形式创建bean,兼容早期遗留系统的升级工作
格式:
<bean factory-bean="factoryBeanId" factory-method="factoryMethodName"></bean>
取值:工厂bean中用于获取对象的实例方法名
注意事项:
- 使用实例工厂创建bean首先需要将实例工厂配置bean,交由spring进行管理
- factory-bean是实例工厂的beanId
测试代码
- 创建实例工厂 ```java package com.itheima.factory;
import com.itheima.service.UserService; import com.itheima.service.impl.UserServiceImpl2; /*
- 实例工厂: 方法是非静态
*/ public class InstanceFactory {
public UserService getBean(){
UserServiceImpl2 service = new UserServiceImpl2(1);
return service;
} } ```
- 配置文件修改
<!--
# 实例工厂的原理
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.factory.InstanceFactory"/>
<bean id="userService3" factory-bean="if" factory-method="getBean"/>
测试类修改
@Test
public void test04(){
ApplicationContext ctx
= new ClassPathXmlApplicationContext("applicationContext.xml");
UserService service = (UserService) ctx.getBean("userService3");
service.save();
}
运行结果
user service2 running…
4.5)DI 依赖注入
IoC(Inversion Of Control)控制翻转,Spring反向控制应用程序所需要使用的外部资源
DI(Dependency Injection)依赖注入,应用程序运行依赖的资源由Spring为其提供,资源进入应用程序的方式称为注入
举例:
UserService <-------> UserDao
- 站在对象构建的角度看:UserService的角度看,需要UserDao资源,而UserDao的构建需要通过springIOC容器反向构建—-》IOC
- 站在资源使用的角度看:UserService需要的资源,需要被动等待SpringIOC容器给提供(等待容器给资源的需求方法注入资源,才可以用)—-》DI(大白话说,就是为bean对象注入属性资源);
示例:张三(男)和李四(女)结婚
- 张三的亲友: 张三娶了李四
- 李四的亲友: 李四嫁给了张三
IoC与DI是同一件事站在不同角度看待问题;
4.6)set注入(主流)
名称:property
类型:标签
归属:bean标签
作用:使用set方法的形式为bean提供资源
格式:
<bean>
<property />
</bean>
- 基本属性:
<property name="propertyName" value="propertyValue" ref="beanId"/>
name:对应bean中的属性名,要求该属性必须提供可访问的set方法(严格规范为此名称是set方法对应名称)
value:设定非引用类型(8大基本类型和String)属性对应的值,不能与ref同时使用
ref:设定引用类型属性对应bean的id ,不能与value同时使用(refrence)
注意:一个bean可以有多个property标签
代码演示
- 添加和修改代码 ```java package com.itheima.service.impl;
import com.itheima.dao.UserDao; import com.itheima.service.UserService;
import java.util.Date;
public class UserServiceImpl3 implements UserService {
private String name;
private int age;
private UserDao dao;
private Date date;
public void save() {
System.out.println(name + "," + age + "," + date);
dao.add();
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public UserDao getDao() {
return dao;
}
public void setDao(UserDao dao) {
this.dao = dao;
}
}
```java
public interface UserDao {
void add();
}
package com.itheima.dao.impl;
import com.itheima.dao.UserDao;
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("UserDaoImpl add...");
}
}
修改配置文件
<!--
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: 引用类型
-->
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="myDate" class="java.util.Date"/>
<bean id="userService33" class="com.itheima.service.impl.UserServiceImpl3">
<property name="name" value="zs"/>
<property name="age" value="18"/>
<property name="dao" ref="userDao"/>
<property name="date" ref="myDate"/>
</bean>
- 修改测试类
@Test
public void test05(){
ApplicationContext ctx
= new ClassPathXmlApplicationContext("applicationContext.xml");
UserService service = (UserService) ctx.getBean("userService33");
//zs,18,Tue Aug 10 15:32:32 CST 2021
//UserDaoImpl add...
service.save();
}
zs,18,Tue Aug 10 15:32:32 CST 2021
UserDaoImpl add…
4.7)构造器注入(了解)
名称:constructor-arg
类型:标签
归属:bean标签
作用:使用构造方法的形式为bean提供资源,兼容早期遗留系统的升级工作
格式:
<bean>
<!--有多少个参数,就有多少个标签-->
<constructor-arg />
</bean>
- 基本属性:
<constructor-arg name="argsName" value="argsValue" ref="refBeanName" />
<!--value和ref属性只能二选一-->
name:对应bean中的构造方法所携带的参数名
value:设定非引用类型构造方法参数对应的值,不能与ref同时使用
其他属性:
<constructor-arg index="arg-index" type="arg-type"/>
type :设定构造方法参数的类型,用于按类型匹配参数或进行类型校验,配合value或者ref属性一块使用
index :设定构造方法参数位置,用于按位置匹配参数,参数index值从0开始计数,,配合value或者ref属性一块使用
注意:一个bean可以有多个constructor-arg标签
代码演示- 修改代码 ```java package com.itheima.service.impl;
import com.itheima.dao.UserDao; import com.itheima.service.UserService;
import java.util.Date;
public class UserServiceImpl4 implements UserService {
private String name;
private int age;
private UserDao dao;
private Date date;
public UserServiceImpl4(String name, int age, UserDao dao, Date date) {
this.name = name;
this.age = age;
this.dao = dao;
this.date = date;
}
public void save() {
System.out.println(name + "," + age + "," + date);
dao.add();
}
}
2.
修改配置文件
```xml
<!--
构造器注入 (了解)
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 id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="myDate" class="java.util.Date"/>
<bean id="userService44" class="com.itheima.service.impl.UserServiceImpl4">
<constructor-arg name="name" value="zs"/>
<constructor-arg name="age" value="18"/>
<constructor-arg name="dao" ref="userDao"/>
<constructor-arg name="date" ref="myDate"/>
</bean>
- 修改测试类
@Test
public void test05(){
ApplicationContext ctx
= new ClassPathXmlApplicationContext("applicationContext.xml");
UserService service = (UserService) ctx.getBean("userService44");
//zs,18,Tue Aug 10 15:32:32 CST 2021
//UserDaoImpl add...
service.save();
}
zs,18,Tue Aug 10 15:35:31 CST 2021
UserDaoImpl add…
4.8)集合类型数据注入(了解)
名称:array,list,set,map,props
类型:标签
归属:property标签 或 constructor-arg标签
作用:注入集合数据类型属性
格式:
<property>
<list></list>
</property>
(1)集合类型数据注入——list(掌握)
<property name="al">
<list>
<value>itheima</value>
<value>66666</value>
</list>
</property>
(2)集合类型数据注入——props(掌握)
<property name="properties">
<props>
<prop key="name">itheima666</prop>
<prop key="value">666666</prop>
</props>
</property>
(3)集合类型数据注入——array (了解)
<property name="arr">
<array>
<value>123456</value>
<value>66666</value>
</array>
</property>
(4)集合类型数据注入——set(了解)
<property name="hs">
<set>
<value>itheima</value>
<value>66666</value>
</set>
</property>
(5)集合类型数据注入——map(了解)
<property name="hm">
<map>
<entry key="name" value="itheima66666"/>
<entry key="value" value="6666666666"/>
</map>
</property>
代码演示
- 修改代码 ```java package com.itheima.service.impl;
import com.itheima.service.UserService;
import java.util.*;
public class UserServiceImpl5 implements UserService {
//前两个是重点
private List<String> list;
private Properties p;
//了解
private int[] array;
private Set<String> set;
private Map<String,String> map;
public void save() {
System.out.println("UserServiceImpl5 save...");
System.out.println("list->" + list);
System.out.println(list instanceof ArrayList);//true
System.out.println("properties->" + p);
System.out.println("array->" + Arrays.toString(array));
System.out.println("set->" + set);
System.out.println("map->" + map);
}
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
public Properties getP() {
return p;
}
public void setP(Properties p) {
this.p = p;
}
public int[] getArray() {
return array;
}
public void setArray(int[] array) {
this.array = array;
}
public Set<String> getSet() {
return set;
}
public void setSet(Set<String> set) {
this.set = set;
}
public Map<String, String> getMap() {
return map;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
}
2.
修改配置文件
```xml
<!--
# 集合类型数据注入
1. properties标签的name属性指定的是UserServiceImpl5中对应的属性名
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="userServiceImpl5" class="com.itheima.service.impl.UserServiceImpl5">
<property name="list">
<list>
<value>zs</value>
<value>ls</value>
<value>ww</value>
</list>
</property>
<property name="p">
<props>
<prop key="username">admin</prop>
<prop key="password">123</prop>
</props>
</property>
<property name="array">
<array>
<value>100</value>
<value>200</value>
</array>
</property>
<property name="set">
<set>
<value>ml</value>
<value>qq</value>
</set>
</property>
<property name="map">
<map>
<entry key="name" value="zhangsan"/>
<entry key="age" value="18"/>
</map>
</property>
</bean>
- 修改测试类
@Test
public void test06(){
ApplicationContext ctx
= new ClassPathXmlApplicationContext("applicationContext.xml");
UserService service = (UserService) ctx.getBean("userServiceImpl5");
service.save();
}
UserServiceImpl5 save…
list->[zs, ls, ww]
true
properties->{password=123, username=admin}
array->[100, 200]
set->[ml, qq]
map->{name=zhangsan, age=18}
4.9)SpEL
el : expression language 表达式语言
总体含义: 都是数据引用
JSP: el表达式
mybatis : el表达式
#{} / ${}
spring : el表达式
#{} / ${}
js : el表达式
`一共${money}元`
Spring提供了对EL表达式的支持,统一属性注入格式
类型:属性值
归属:value属性值
作用:为bean注入属性值
格式:
<property value="EL"></bean>
# springEL表达式
1. ${}
${} 用于加载外部文件指定的Key值 (在下一节课的properties文件中演示)
2. #{}
#{} 强调的是把内容赋值给属性
注意:所有属性值不区分是否引用类型,统一使用value赋值
所有格式统一使用 value=“”
常量 #{10} #{3.14} #{2e5} #{‘itcast’}
引用bean #{beanId}
引用bean属性 #{beanId.propertyName}
引用bean方法 beanId.methodName().method2()
引用静态方法 T(java.lang.Math).PI
运算符支持 #{3 lt 4 == 4 ge 3}
正则表达式支持 #{user.name matches‘[a-z]{6,}’}
集合支持 #{myList[3]}
代码演示:
修改核心配置文件<!--
value属性: 指定基本类型数据 (8大基本类型+String)
ref属性: 指定的引用类型
springEL
1. ${表达式}
引入配置文件中的数据
2. #{表达式}
强调的是把内容赋值给属性
#{'字符串'}
#{数字,boolean}
#{变量名}
-->
<bean id="myDate" class="java.util.Date"/>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl2">
<!-- <property name="name" value="zs"/>
<property name="age" value="18"/>
<property name="date" ref="myDate"/>
<property name="dao" ref="userDao"/>-->
<property name="name" value="#{'ls'}"/>
<property name="age" value="#{18}"/>
<property name="date" value="#{myDate}"/>
<property name="dao" value="#{userDao}"/>
</bean>
4.10)properties文件
Spring提供了读取外部properties文件的机制,使用读取到的数据为bean的属性赋值
操作步骤
1.准备外部properties文件
2.开启context命名空间支持xmlns:context="http://www.springframework.org/schema/context"
3.加载指定的properties文件
<context:property-placeholder location="classpath:filename.properties"/>
4.使用加载的数据
<property name="propertyName" value="${propertiesName}"/>
注意:如果需要加载所有的properties文件,可以使用
*.properties
表示加载所有的properties文件注意:读取数据使用${propertiesName}格式进行,其中propertiesName指properties文件中的属性名
测试代码:
- 新增一个配置文件
name=zs
age=20
public class UserServiceImpl implements UserService {
//1. 声明需要注入的资源,并声明对应的set方法
String name;
int age;
UserDao userDao;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void save() {
System.out.println("UserServiceImpl run:" + name + "," + age);
userDao.find();
}
}
配置文件修改
<?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.ioc.dao.impl.UserDaoImpl"/>
<!--
3. 使用加载的数据
${外部文件中的key}
-->
<bean id="userService" class="com.itheima.ioc.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"/>
<property name="name" value="${name}"/>
<property name="age" value="${age}"/>
</bean>
</beans>
测试类修改
public class UserTest {
@Test
public void test01(){
//2.加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//3.获取资源: 通过配置文件中的id
UserService userService = (UserService) ctx.getBean("userService");
userService.save();
}
}
打印结果:
UserServiceImpl run:zs,20
UserDao find…
总结
# 思路
1. 哲学三问 : 是什么? 为什么? 怎么办?
2. 是什么 : 今天学了什么? 干什么用的? 好在哪里?
3. 为什么 : 原理
4. 怎么办 : 动手
# 编程 (工科)
1. 理解 : 思想
1). 思想是诸多实践的提炼
2). 初级: 理解的不完全正确,都比不去理解好
2. 动手
1). 基于一知半解,动手,增进你的理解
# 举个例子: Spring的IOC
1. IOC是什么? 控制反转...
干什么用的? 解耦
DI:依赖注入
IOC与DI说得是同一件事,通俗来讲DI就是资源的需求方要被动等待IOC容器提供资源使用;
2. 原理
1). 直接创建对象
2). 面向接口编程 : 解耦左边
3).将new对象的公共代码封装到一个工具类中(工厂类)
4). 配置文件+反射 : 解耦右边
-> 代码冗余
4). 工厂模式(容器) : 封装(工厂模式+反射+静态配置--》spring雏形)
3. 怎么办
1). 入门案例
2). 各种配置
bean标签:
属性:
id class scope init-mehtod destroy-method factory-method factory-bean lazy-init
子标签:
set注入:<property name="xxx" value="xx" ref="xxxx">
如果属性是集合类型:
list set array map props等
构造器注入:<constructor-arg name="xxx" value="xx" ref="xxxx">
写两遍 (第一遍边看边写, 第二遍尽量自己写)
Maven注意点
maven设置
maven仓库的数据残留
用cleanLastUpdated.bat脚本程序,清理仓库中的残留jar包
重新刷新maven即可
idea创建工程
# 学习阶段两个创建工程方案
1. 一天一个project
2. 一天一个module (推荐!!!)
# 工程(project)和模块(module)
1. 一个project可以包含多个module
1). 一个project理论上是一个项目
2). 每个module是一个项目各个模块
2. A模块出问题了,B模块也运行不了
# 创建方案(框架阶段)
1. 一个project : empty project
2. 每个案例一个module