简介
本文是基于狂神说java的教学视频的,希望记录自己的学习过程,同时也欢迎大家交流。
??spring是一个开源且免费的框架,主要用于解决web应用开发。其特点是轻量级且非侵入式。
??spring两个核心概念是:支持控制翻转(IOC)和面向切片编程(AOP)。同时,由于这两个特性,使得其对事务的支持性极强。
Spring的组成模块如下:source
我们常用的功能包括:
- spring Boot:
- 快速开发的脚手架
- 构建单个微服务
- spring cloud
- 是基于spring boot实现的
- 协调各个微服务
学习spring和springMVC是掌握spring boot的基础。
核心知识点
??在没有学习spring之前就听说过大名鼎鼎的IOC和AOP这两个spring和核心概念。下面来详细了解一下。
1. IOC
所谓控制翻转是指的依赖对象的方式反转了。之前对象的创建是依赖于代码的编写,控制反转的思想就是,将对象创建的过程交给用户,由用户自己来决定使用什么样的对象。作为程序的设计者,只需要为用户提供相应的接口实现即可。其中使用到的是:
- set接口
- 设计思想:工厂模式
(图片来自网络)
??IOC保证了我们不需要再对程序进行任何的修改了,只需要修改xml文件,对象的完全托付给spring进行管理。
2. Hello Spring 测试案例
过程说明:
- 使用maven创建项目;
- 导入spring依赖;
- 创建测试实体类;
- 创建spring核心配置文件;
- 测试spring对象管理功能。
项目结果如下:
2.1 使用maven创建项目
使用maven创建一个新的空项目,将项目中的src目录删除,并在项目下新建模块。在子模块的基础上进行测试。
2.2 导入spring依赖
<dependencies><!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.2</version></dependency></dependencies>
2.3 编写测试实体类
package com.yindarui.POJO;
public class Hello {
private String str;private int id;public int getId() {
return id;}public void setId(int id) {
this.id = id;}public String getStr() {
return str;}public void setStr(String str) {
this.str = str;}@Overridepublic String toString() {
return "Hello{" +"str='" + str + '\'' +", id=" + id +'}';}
}
2.4 编写spring的核心配置文件:applicationContext.xml
这里我们只使用property标签来为对象赋值。
<?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"><!--这个配置文件就是spring IOC的核心,即容器管理对象,将对象创建的过程变得透明--><!--id是你绑定的对象在容器中的名称,在使用时我们只需要指定该对象在容器中的名字就可以创建该对象,过程可以理解为如下:Hello hello = new hello();--><bean id="hello" class="com.yindarui.POJO.Hello"><!--property是bean的子元素,str就是HelloSpring里的str变量,张三就是给str变量赋的值--><property name="str" value="张三"/><property name="id" value="123"/></bean>
</beans>
2.5 测试类
package HelloSpringTest;import com.yindarui.POJO.Hello;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test1 {
@Testpublic void test() {
// 加载配置文件,即获取容器ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 通过context来获取对象Hello hello = (Hello) context.getBean("hello");
// 查看对象的值是否被修改了System.out.println(hello.toString());}
}
2.6 结果
Hello{
str='张三', id=123}
2.7 执行原理
??spring创建对象的原理是:
1. 对于一个没有有参构造的类,spring将利用该类无参构造来初始化对象,且利用property标签
调用该类的set方法来为对象赋值。
2. 对于一个含有 有参构造的类,由于有参构造会覆盖无参构造,此时无法正常利用默认无参构造初始化对象,则会报错。此时需要使用spring使用constructor-arg 标签
来创建对象。
<?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"><!--这个配置文件就是spring IOC的核心,即容器管理对象,将对象创建的过程变得透明--><!--id是你绑定的对象在容器中的名称,在使用时我们只需要指定该对象在容器中的名字就可以创建该对象,过程可以理解为如下:Hello hello = new hello();--><bean id="hello" class="com.yindarui.POJO.Hello">
<!-- name是指定的构造函数中的参数名--><constructor-arg name="str" value="李四"/>
<!-- id是指定的构造函数的参数的位置,从零开始--><constructor-arg index="1" value="1"/>
<!-- 采用ref的方式使得我们不需要显示的指定构造函数参数的索引或类型--><constructor-arg ref="tele"/></bean><bean id="tele" class="java.lang.String"/>
</beans>
结果:
// 注意这里的tel的默认参数是空字符串,而不是null
Hello{
str='李四', id=1, tel=''}
2.8 对象何时被创建
测试:
- 在实体类的构造函数中添加输出语句;
- 在context对象创建前添加输出语句;
- 在context对象创建后添加输出语句;
测试类:
package HelloSpringTest;import com.yindarui.POJO.Hello;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;/****/
public class Test1 {
@Testpublic void test() {
System.out.println("context object will be created then!");
// 加载配置文件,即获取容器ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");System.out.println("context object is created!");
// 通过context来获取对象Hello hello = (Hello) context.getBean("hello");Hello hello2 = (Hello) context.getBean("hello");System.out.println(hello == hello2 ? "两个引用指向的是同一个对象": "两个引用指向的不是同一个对象");
// 查看对象的值是否被修改了System.out.println(hello.toString());}
}
结果:
构造函数被创建
context object is created!
两个引用指向的是同一个对象
Hello{
str='李四', id=1, tel=''}
分析:使用spring管理对象时,对象会在用户加载这个配置文件时被创建,用户使用只需要知道自己要使用的类在容器中的名称即可。同时,每个对象在一个容器中只有一份。
3. 配置文件
3.1 别名
为bean起的别名。
<alias name="hello" alias="hello2"/>
3.2 Bean
<!-- id——bean的唯一标识符class——bean绑定的类的全限定名name——起别名,使用空格分隔来以起多个别名 --><bean id="h1" class="java.lang.String" name="ss1 ss2" />
3.3 import
??将多个编写的applicationContext.xml合并为一个总的。
4. 依赖注入(dependency injection DI)
??bean对象的创建依赖于容器,bean对象的所有属性,由容器来注入。其实就是按照配置文件的方式对类进行初始化,根据不同的类型大致有以下几种:
- 基本数据类型
- 引用数据类型
- 集合
- 列表
- map
准备测试的类:
package com.yindarui.POJO;import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;/****/
public class DependencyInjectionTest {
private int id;private String name;private Map<String, Integer> score;private int[] nums;private String[] strs;private List<String> list;private Set<String> set;public void setId(int id) {
this.id = id;}public void setName(String name) {
this.name = name;}public void setScore(Map<String, Integer> score) {
this.score = score;}public void setNums(int[] nums) {
this.nums = nums;}public void setStrs(String[] strs) {
this.strs = strs;}public void setList(List<String> list) {
this.list = list;}public void setSet(Set<String> set) {
this.set = set;}public int getId() {
return id;}public String getName() {
return name;}public Map<String, Integer> getScore() {
return score;}public int[] getNums() {
return nums;}public String[] getStrs() {
return strs;}public List<String> getList() {
return list;}public Set<String> getSet() {
return set;}@Overridepublic String toString() {
return "DependencyInjectionTest{" +"id=" + id +", name='" + name + '\'' +", score=" + score +", nums=" + Arrays.toString(nums) +", strs=" + Arrays.toString(strs) +", list=" + list +", set=" + set +'}';}
}
4.1 构造器注入
4.2 set方式注入
配置文件:
<?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="testName" class="java.lang.String"/><bean id="DITest" class="com.yindarui.POJO.DependencyInjectionTest">
<!-- 1.普通值注入--><property name="id" value="1"/>
<!-- 2. bean注入, 注入的是另一个bean ref--><property name="name" ref="testName"/>
<!-- 3. 注入map集合,注入的是一个键值对--><property name="score"><props><prop key="语文">100</prop><prop key="数学">100</prop><prop key="英语">60</prop></props></property>
<!-- 4. 注入基本类型数组--><property name="nums"><array><value>1</value><value>2</value><value>3</value></array></property><property name="strs"><array>
<!-- 直接赋值--><value>"我是一个元素"</value>
<!-- 使用ref赋值--><ref bean="listBean"/></array></property>
<!-- 5. 注入list集合,为引用数据类型--><property name="list"><list><value>"好好学习"</value><ref bean="listBean"/></list></property>
<!-- 6. 注入set集合, 为引用数据类型--><property name="set"><set><value>2</value><value>3</value>
<!-- 这个值是无法加入的,set元素不可重复--><value>3</value></set></property></bean><bean id="listBean" class="java.lang.String"/>
</beans>
测试方法
@Testpublic void testForDI() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("DITest.xml");DependencyInjectionTest diTest = (DependencyInjectionTest) context.getBean("DITest");System.out.println(diTest.toString());System.out.println(diTest.getStrs()[1] == diTest.getList().get(1));}
测试结果
DependencyInjectionTest{
id=1, name='', score={
数学=100, 语文=100, 英语=60}, nums=[1, 2, 3], strs=["我是一个元素", ], list=["好好学习", ], set=[2, 3]}
// 注意,list中第二个空字符串和strs中第二个空字符串同一个对象
true
4.3 其他方式注入
??spring中提供了俩种快捷的注入方式:
- c命名空间注入:要求类中有有参构造。
- p命名空间注入:要求类中有有效的无参构造,代替了property标签,在bean标签中直接为参数注入值;
??命名空间的使用要求导入约束:
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
5. bean作用域
作用域 | 中文 | 描述 |
---|---|---|
singleton | 单例(默认) | 对于一个对象,整个容器中保留一份 |
prototype | 原型 | 将单个bean定义定义为任意数量的对象实例 |
reques | 请求 | |
session | 一个session中 | |
application | 整个web程序 | |
websocket | 一个socket中 |