文章目录
一、什么是spring框架
spring是一个高度灵活的轻量级框架,其目的是降低企业级应用开发的复杂度。spring在javaEE项目中应用广泛,采用Java语言开发,免费开源。
二、spring概述
在程序中由某几个包实现某个功能,这几个包就是一个模块,不同的包由不同的模块构成。Spring、Spring MVC、MyBatis分属于不同的模块。
1. spring功能介绍
1.1 IOC机制
IOC可以创建对象以及管理对象之间的调用关系。IOC机制用来整合其他框架,降低模块间的耦合性/依赖性。
1.2 AOP面向切面编程
将一些方法中的具有相同功能的部分抽取出来,设置为切面。降低代码的冗余性和提高代码的可维护性。
1.3 事务控制
1.4 对jdbc做了轻量级封装
这一部分内容,可以由MyBatis来实现
1.5 提供了上传下载、定时器等工具
2. spring功能模块划分
3. jar包说明
第一部分内容:IOC控制反转
三、IOC介绍
介绍IOC之前,先讲解一下Tomcat服务器。spring和Tomcat都是容器。容器就是装载程序文件的存储器。之前学到了Servlet和jsp都是存储在Tomcat这个容器里的。Servlet和jsp都是Tomcat容器的组件,之所以称为组件,是因为它们只有在Tomcat这个服务器里才可以运行。Servlet和jsp就是由Tomcat这个容器来创建和维护的。
1. 什么是IOC
IOC(Inversion of Control)叫做控制反转。前面我们说道,IOC可以创建对象以及管理对象之间的调用关系。原来类里的对象是由我们自己创建和管理的,现在我们要让spring这个容器来创建和维护对象,我们将控制权交给spring来管理,这就是控制反转。
那我们如何获取对象呢?我们需要先获取spring容器,然后用容器来获取对象;由spring来创建对象并赋值;类写好后,由spring来进行配置。
2. IOC实现控制反转的两种方式
- 使用配置文件将类转为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" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<!--将Cat类创建为bean组件,通过id可获取该bean组件-->
<bean id="cat2" class="com.bean.Cat"></bean>
</beans>
- 使用注解将类转为bean组件
①在要转为组件的类上添加注解
②为注解添加配置文件,通过扫描将注解添加到spring容器中
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--使用注解的方式为类配置成spring的bean组件,前提是需要启动扫描写注解的包-->
<context:component-scan base-package="com"></context:component-scan>
四. 使用配置文件将类转为bean组件
1. 创建文件,引入jar包
2. 添加配置文件
这是个JavaSE项目,在src下创建 spring.xml
配置文件
添加spring配置信息:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
3. spring入门程序——无参/带参构造方法
3.1 Dog类
package com.bean;
public class Dog {
private String name;
private int age;
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 Dog(String name, int age) {
this.name = name;
this.age = age;
}
public Dog() {
System.out.println("无参构造方法,创建了对象");
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//初始化方法
public void init() {
System.out.println(this.name + "dog被初始化");
}
//销毁方法
public void destroy() {
System.out.println(this.name + "dog被销毁");
}
}
3.2 spring.xml
相关介绍:
标签/属性 | 含义或作用 |
---|---|
bean标签 | 配置文件里所有的bean都是spring容器管理的bean组件,也就是类对象 |
id | 用来获取bean组件 |
class | 对象的数据类型 |
scope | 用来设置单例模式,不写默认为单例 |
init-method | 设置初始化方法 |
destroy-method | 设置销毁方法(单例模式下起作用) |
constructor-arg | 设置带参构造方法,不写默认为无参构造方法 |
index | 参数索引(从0开始) |
value | 自定义的参数值 |
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dog1" class="com.bean.Dog" scope="singleton" init-method="init" destroy-method="destroy"></bean>
<bean id="dog2" class="com.bean.Dog">
<!--需要做参数对应,参数索引从0开始-->
<constructor-arg index="0" value="小黄"></constructor-arg>
<constructor-arg index="1" value="3"></constructor-arg>
</bean>
</beans>
3.3 DogTest类
测试类:通过无参或带参方法,创建一个狗对象,并输出对象的信息。
package com.test;
import com.bean.Dog;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class DogTest {
//这里创建静态容器对象
//ApplicationContext是spring对象,这个对象不能调用close方法
//private static ApplicationContext ac = null;
//ClassPathXmlApplicationContext是spring实现类对象,可以调用close方法关闭容器
private static ClassPathXmlApplicationContext ac = null;
static {
ac = new ClassPathXmlApplicationContext("spring.xml");
}
@Test
public void dogTest() {
// bean组件是Object类型
// spring容器通过无参或带参方法创建对象
Dog dog1 = (Dog) ac.getBean("dog1");
dog1.setName("小黑");
dog1.setAge(7);
System.out.println(dog1);
//关闭spring容器
ac.close();
}
}
4. 单例、多例模式
同一个bean组件,默认是单例模式,对应的是同一个对象。
4.1 单例模式测试
- spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="dog" class="com.bean.Dog">
<constructor-arg index="0" value="小白"></constructor-arg>
<constructor-arg index="1" value="2"></constructor-arg>
</bean>
</beans>
- CatTest
package com.test;
import com.bean.Dog;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class DogTest {
// 创建spring对象
private static ApplicationContext ac = null;
static {
ac = new ClassPathXmlApplicationContext("spring.xml");
}
@Test
public void testDog() {
Dog dog = (Dog) ac.getBean("dog");
System.out.println(dog);
Dog dog2 = (Dog) ac.getBean("dog");
System.out.println(dog2);
}
}
- 测试结果
4.2 多例模式测试
多例模式设置:
测试结果:
可以看出这里是调用了两次无参构造方法,创建了两个对象。
5. 懒加载
5.1 懒加载的作用/应用范围
Spring框架提供了懒加载机制。懒加载可以让指定的bean不在启动时创建对象,而是在第一次使用时才创建,可以降程序运行过程中对时间和内存的消耗。懒加载机制只有在单例模式下才起作用(默认bean组件是单例模式),对于多例模式的懒加载没有意义(多例bean是在使用时才会创建)。
没有指定是哪个bean组件,默认是第一个bean组件
- 不设置懒加载:
<context:component-scan base-package="com"></context:component-scan>
<bean id="dog1" class="com.bean.Dog"></bean>
@Test
public void dogLazTest() {
}
测试结果:单例bean组件自动创建了对象
- 设置懒加载:
lazy-init 默认是 false,单例模式下才起作用,默认bean组件是单例模式
<context:component-scan base-package="com"></context:component-scan>
<bean id="dog1" class="com.bean.Dog" lazy-init="true"></bean>
@Test
public void dogLazTest() {
}
测试结果:单例bean组件没有自动创建
6. 初始化方法、销毁方法
-
方法创建:
-
spring框架的配置文件
-
不同模式下,方法的执行情况
单例模式下:bean对象随着框架的关闭而销毁
多例模式下:bean对象不会随着框架的关闭而销毁
初始化方法:创建后马上执行初始化方法
销毁方法:销毁前马上执行销毁方法 -
测试结果:
4.1 多例模式下的测试结果:没有执行销毁方法
4.2 单例模式下的测试结果:框架关闭时,会销毁bean对象,因此会执行销毁方法
-
注意
7. IOC功能——依赖注入DI(dependency injection)
依赖注入讲的是,IOC如何给属性注入值。
7.1 实现方式
- 使用配置文件(本文介绍的就是使用配置文件)
- 使用注解(第二篇介绍使用注解)
7.2 注入方式
- 手动注入
- 自动匹配
8. 手动注入
标签/属性 | 含义/作用 |
---|---|
property标签 | 为属性赋值 |
name | 属性名 |
value | 属性值 |
list标签 | 为list集合赋值 |
set标签 | 为set集合赋值 |
array标签 | 为数组赋值 |
value标签 | 为list/set/array设置值 |
ref标签 | 引入外部对象 |
bean | 对象id |
map标签 | 为map集合赋值 |
entry标签 | 添加map集合属性 |
key | 设置键 |
value | 设置值 |
props标签 | 为properties集合赋值 |
prop标签 | 添加property集合属性 |
key | 设置键 |
prop标签里 | 设置值 |
8.1 八种基本数据类型+其封装类型+String
- 通过setter方法设置属性
配置文件:
<bean id="dog1" class="com.bean.Dog" scope="singleton" init-method="init" destroy-method="destroy"></bean>
测试文件:
@Test
public void dogTest() {
Dog dog1 = (Dog) ac.getBean("dog1");
dog1.setName("小黑");
dog1.setAge(7);
System.out.println(dog1);
}
- 通过构造方法设置属性
配置文件:
<bean id="dog2" class="com.bean.Dog">
<constructor-arg index="0" value="小黄"></constructor-arg>
<constructor-arg index="1" value="3"></constructor-arg>
</bean>
测试文件:
@Test
public void dogTest() {
Dog dog2 = (Dog) ac.getBean("dog2");
System.out.println(dog2);
}
- 通过属性注入设置属性
配置文件:
<bean id="dog1" class="com.bean.Dog">
<property name="name" value="小蓝"></property>
<property name="age" value="6"></property>
</bean>
测试文件:
@Test
public void testDog() {
Dog dog = (Dog) ac.getBean("dog1");
System.out.println(dog);
}
测试结果:
8.2 属性是对象
外部注入——通过property标签的ref引用其它bean标签
配置文件:
<bean id="dog" class="com.bean.Dog">
<property name="name" value="小白"></property>
<property name="age" value="5"></property>
</bean>
<bean id="boy" class="com.bean.Boy">
<property name="name" value="小王"></property>
<property name="age" value="8"></property>
<property name="dog" ref="dog"></property>
</bean>
测试文件:
@Test
public void testDog() {
Dog dog = (Dog) ac.getBean("dog");
System.out.println(dog);
}
内部注入——直接在property标签里内嵌bean标签
配置文件:
<bean id="boy" class="com.bean.Boy">
<property name="dog">
<bean class="com.bean.Dog">
<property name="name" value="小黄"></property>
<property name="age" value="9"></property>
</bean>
</property>
</bean>
测试文件:
@Test
public void testDog() {
Dog dog = (Dog) ac.getBean("dog");
System.out.println(dog);
}
8.3 属性是集合、数组
属性值分别写在 list、array标签里的value标签里。
配置文件:
<bean id="boy" class="com.bean.Boy">
<!--list集合-->
<property name="hobbies">
<list>
<value>游泳</value>
<value>跑步</value>
<value>跳舞</value>
</list>
</property>
<!--数组-->
<property name="jobs">
<array>
<value>学生</value>
<value>后端开发</value>
<value>全栈工程师</value>
</array>
</property>
</bean>
测试代码:
// 集合、数组等属性依赖注入
@Test
public void listAndArray() {
Boy boy = (Boy) ac.getBean("boy3");
List<String> hobbies = boy.getHobbies();
hobbies.forEach(hobby -> {
System.out.println(hobby);
});
String[] jobs = boy.getJobs();
for (int i=0; i < jobs.length; i++) {
System.out.println(jobs[i]);
}
}
8.4 属性是map集合、properties集合
配置文件:
<bean id="boy" class="com.bean.Boy">
<!--Map集合-->
<property name="langMap">
<map>
<!--如果存的是对象的话,可以用ref来引用-->
<entry key="zh" value="中文"></entry>
<entry key="en" value="英文"></entry>
</map>
</property>
<!--property集合-->
<property name="langProp">
<props>
<prop key="zh">中文</prop>
<prop key="en">英文</prop>
</props>
</property>
</bean>
测试代码:
// map集合、properties集合测试
@Test
public void mapAndProperties() {
Boy boy = (Boy) ac.getBean("boy4");
Map<Integer, String> lanMap = boy.getLanMap();
for (int i = 0; i < lanMap.size(); i++) {
System.out.println(lanMap.get(i));
}
Properties langPro = boy.getLanPro();
System.out.println(langPro.getProperty("zh"));
System.out.println(langPro.getProperty("en"));
}
8.5 通过构造方法给属性赋值
构造方法:必须有对应的构造方法,才能使用如下的配置
public Boy(String name, Integer age, Dog dog, List<String> hobbies, String[] jobs, Map<String, String> langMap, Properties langProp) {
this.name = name;
this.age = age;
this.dog = dog;
this.hobbies = hobbies;
this.jobs = jobs;
this.langMap = langMap;
this.langProp = langProp;
}
配置文件:
<bean id="boy2" class="com.bean.Boy">
<constructor-arg index="0" value="小李"></constructor-arg>
<constructor-arg index="1" value="10"></constructor-arg>
<constructor-arg index="2" ref="dog"></constructor-arg>
<constructor-arg index="3">
<list>
<value>跑步</value>
<value>跳远</value>
</list>
</constructor-arg>
<constructor-arg index="4">
<array>
<value>老师</value>
<value>父亲</value>
</array>
</constructor-arg>
<constructor-arg index="5">
<map>
<entry key="zh" value="中文"></entry>
<entry key="en" value="英文"></entry>
</map>
</constructor-arg>
<constructor-arg index="6">
<props>
<prop key="zh">中文</prop>
<prop key="en">英文</prop>
</props>
</constructor-arg>
</bean>
9. 自动注入
自动注入一共有三种方式:
方式 | 解释 |
---|---|
byType | 根据类属性的数据类型自动注入 (常用) |
byName | 根据类属性名自动注入 |
constructor | 根据构造方法自动注入 |
byType:根据类属性的数据类型在spring容器里查找与它同类型的bean(属性的数据类型=bean的class)。如果找到一个,那么就给该属性注入值;找到多个报异常;没有找到,该属性就是默认值。
byName:根据属性的名字在spring容器里查找与该属性同名的bean(属性名=bean的id)。如果找到并且该bean的类型与属性的数据类型相同,则注入值;如果类型不同,则发送异常;如果没有找到与属性同名的bean,则不注入值。
constructor:根据类里的构造方法的参数的数据类型去spring容器里查找是否有bean可以为参数赋值(参数的数据类型=bean的id)。如果参数个数类型都有相匹配的bean赋值,执行该构造方法;只要有一个参数没有匹配上,就执行无参构造方法;如果没有无参构造方法,就只能报异常了
byType
- byType正确获取
- 如果在spring容器中匹配到多个类型相同的bean就报异常
byName
- byName正确获取,狗类里有一个Dog类型的属性,其属性名是dog
- 属性名和bean里的id匹配但数据类型不一样,会报异常。
constructor