Spring-day01 IoC
# 框架阶段1. 时间 (8天)1). spring : 3天2). springmvc : 2天3). maven高级 : 1天5). springboot 1天6). 综合案例: 1天2. SSM1). 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 {@Overridepublic void addUser() {System.out.println("添加用户");}@Overridepublic void deleteUser() {System.out.println("删除用户");}@Overridepublic void updateUser() {System.out.println("修改用户");}@Overridepublic 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@Overridepublic 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、实例化beanObject beanObject = Class.forName(value).newInstance();//4、放入容器map.put(key,beanObject);}} catch (Exception e) {e.printStackTrace();}}//5、公共获得beanpublic 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/beanshttps://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 {@Testpublic void test01(){//2.加载配置文件ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");//3.获取资源: 通过配置文件中的idUserService 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 {@Testpublic void test01(){//2.加载配置文件ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");// ApplicationContext ctx = new AnnotationConfigApplicationContext();//3.获取资源: 通过配置文件中的idUserService 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 {@Testpublic void test01(){//2.加载配置文件ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");//3.获取资源: 通过id和name都能获取到bean// userService,userService1,userService2都可以// userService3 因为没有指定,所以会报以下异常:// NoSuchBeanDefinitionException: No bean named 'userService3' availableUserService 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...");}@Overridepublic void save() {System.out.println("UserServiceImpl run...");}}
@Testpublic 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..");}@Overridepublic 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"/>
- 测试类修改
@Testpublic void method03(){//1. 创建工厂对象ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");//2. 从ioc容器中获取beanUserService 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...");}
}
```javapackage 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"/>
测试类修改
@Testpublic 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"/>
测试类修改
@Testpublic 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;}
}
```javapublic interface UserDao {void add();}
package com.itheima.dao.impl;import com.itheima.dao.UserDao;public class UserDaoImpl implements UserDao {@Overridepublic 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标签内子标签property1). 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>
- 修改测试类
@Testpublic 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>
- 修改测试类
@Testpublic 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);//trueSystem.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>
- 修改测试类
@Testpublic 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属性: 指定的引用类型springEL1. ${表达式}引入配置文件中的数据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=zsage=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;}@Overridepublic 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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://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 {@Testpublic void test01(){//2.加载配置文件ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");//3.获取资源: 通过配置文件中的idUserService userService = (UserService) ctx.getBean("userService");userService.save();}}
打印结果:
UserServiceImpl run:zs,20
UserDao find…
总结
# 思路1. 哲学三问 : 是什么? 为什么? 怎么办?2. 是什么 : 今天学了什么? 干什么用的? 好在哪里?3. 为什么 : 原理4. 怎么办 : 动手# 编程 (工科)1. 理解 : 思想1). 思想是诸多实践的提炼2). 初级: 理解的不完全正确,都比不去理解好2. 动手1). 基于一知半解,动手,增进你的理解# 举个例子: Spring的IOC1. 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. 一天一个project2. 一天一个module (推荐!!!)# 工程(project)和模块(module)1. 一个project可以包含多个module1). 一个project理论上是一个项目2). 每个module是一个项目各个模块2. A模块出问题了,B模块也运行不了# 创建方案(框架阶段)1. 一个project : empty project2. 每个案例一个module
