文章目录
1. 链接
2. Spring概述
2.1 Sprig框架概述
- Spring是轻量级的开源JavaEE框架
- Spring可以解决企业应用开发的复杂性
- Spring有两个核心部分:IOC和AOP
- IOC:控制反转,把创建对象的过程交给Spring进行管理。是面向对象编程中的一种设计原则,可以用来降低计算机代码之间的耦合度,其中最常见的方式叫做依赖注入(Dependency Injection,简称DI)。Spring 就是采用依赖注入的方式,为我们管理容器中的 bean 实例对象
- AOP:面向切面,可以在不修改源代码的前提下,通过预编译方式和运行期间动态代理方式实现对原有代码的增强(添加新功能)
- Spring特点:
- 方便解耦,简化开发
- AOP编程的支持
- 方便程序的测试
- 方便集成各种框架
- 降低JavaAPI开发难度
- 方便进行事务的操作
2.2 入门案例
目标
使用 Spring 创建 bean 实例对象,并为其属性赋值
创建maven工程,引入相关依赖
因为后续测试还会创建其他 maven 工程,因此我们先创建一个 maven 父工程(spring5-learn),再创建本章对应的 maven 子工程(spring-getting-start)
在 spring-getting-start 工程中引入 spring-beans
、spring-context
、spring-core
、spring-expression
的依赖,这四个依赖正是 Spring Core Container 所需的依赖,此外 Springn 还需依赖 commons-logging 实现日志功能
如下是 pom.xml 中引入的依赖配置,为了测试方便,我们引入了 spring-test
和jupiter
相关依赖
<dependencies>
<!-- spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<!-- spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<!-- spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<!-- spring-expression -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<!-- commons-logging -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!-- jupiter -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
<!-- spring-test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
创建实体类
public class Student {
private Integer stuId;
private String stuName;
public Student() {
}
public Student(Integer stuId, String stuName) {
this.stuId = stuId;
this.stuName = stuName;
}
public Integer getStuId() {
return stuId;
}
public void setStuId(Integer stuId) {
this.stuId = stuId;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
@Override
public String toString() {
return "Student{" +
"stuId=" + stuId +
", stuName='" + stuName + '\'' +
'}';
}
}
编写Spring配置文件
注:resource 包下的配置文件在执行时会被拷贝至类路径的根目录
<?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元素定义一个由IOC容器创建的对象 -->
<!-- class属性指定用于创建bean的全类名 -->
<!-- id属性指定用于引用bean实例的标识 -->
<bean id="student" class="Student">
<!-- 使用property子元素为bean的属性赋值 -->
<property name="stuId" value="007"/>
<property name="stuName" value="lbw"/>
</bean>
</beans>
编写测试代码
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring {
@Test
public void gettingStart() {
//1.创建 IOC容器对象
ApplicationContext iocContainer = new ClassPathXmlApplicationContext("getting-start.xml");
//2.根据id获取bean实例对象
Student student= (Student) iocContainer.getBean("student");
//3.打印bean
System.out.println(student);
}
}
3. IOC容器
3.1 IOC和DI
IOC(Inversion of Control):反转控制
早在2004年,Martin Fowler就提出了“哪些方面的控制被反转了?”这个问题。他总结出是依赖对象的获得被反转了,因为大多数应用程序都是由两个或是更多的类通过彼此的合作来实现企业逻辑,这使得每个对象都需要获取与其合作的对象(也就是它所依赖的对象)的引用。如果这个获取过程要靠自身实现,那么这将导致代码高度耦合并且难以维护和调试
在应用程序中的组件需要获取资源时,传统的方式是组件主动的从容器中获取所需要的资源,在这样的模式下开发人员往往需要知道在具体容器中特定资源的获取方式。比如 ClassA 中需要用到 ClassB 的对象,一般情况下,需要在 ClassA 的代码中显式的 new 一个 ClassB 的对象
反转控制的思想完全颠覆了应用程序组件获取资源的传统方式:反转了资源的获取方向——改由容器主动的将资源推送给需要的组件,开发人员不需要知道容器是如何创建资源对象的,只需要提供接收资源的方式即可。采用依赖注入技术之后,ClassA 的代码只需要定义一个私有的 ClassB 对象,不需要直接 new 来获得这个对象,而是通过相关的容器控制程序来将 ClassB 对象在外部 new 出来并注入到 A 类里的引用中。而具体获取的方法、对象被获取时的状态由配置文件(如 XML)来指定.
DI(Dependency Injection):依赖注入
可以将 DI 看作是 IOC 的一种实现方式:即组件以一些预先定义好的方式(例如:setter 方法)接受来自于容器的资源注入。相对于 IOC 而言,这种表述更直接
3.2IOC容器在Spring中的实现
在通过IOC容器读取bean的实例之前,需要先将IOC容器本身实例化,Spring提供了IOC容器的两种实现方式:
1.beanFactory:IOC容器的基本实现,是Spring内部的基础设施,是面向Spring本身的,不是提供给开发人员使用的
2. ApplicationContext:beanFactory的子接口,提供了更多高级特性。面向使用Spring的开发者
beanFactory:加载配置文件时不会创建对象,在获取对象(使用)时才会去创建对象
ApplicationContext加载配置文件时就会创建对象
在使用时更倾向于使用第二种,在服务器启动时就创建对象,而不是在操作时完成,给用户一种比较快的错觉
ctrl+h
打开ApplicationContext的结构
ApplicationContext
的主要实现类:
ClassPathXmlApplicationContext
:对应类路径下的XML格式的配置文件
FileSystemXmlApplicationContext
:对应文件系统中的XML格式的配置文件
在初始化时就创建单例的bean,也可以通过配置的方式指定创建的bean是多实例的
ConfigurableApplicationContext
接口:
是ApplicationContext
的子接口,包含一些扩展方法
refresh()
和close()
让ApplicationContext
具有启动、关闭和刷新上下文的能力
WebApplicationContext
接口:
WebApplicationContext
,是继承于ApplicationContext
的一个接口,扩展了ApplicationContext
,是专门为Web应用准备的,它允许从相对于Web根目录的路径中装载配置文件完成初始化
3.3举例说明IOC为什么可以降低代码耦合度
1.原始方式
自己new一个对象,再通过setter方法注入属性值
Student stu = new Student();
stu.setStuId(7);
stu.setStuName("Oneby");
2.进阶方式:通过工厂创建对象
可以先通过 XML 配置文件配置 bean 的属性
<bean id="student" class="Student">
<property name="stuId" value="007"/>
<property name="stuName" value="lbw"/>
</bean>
再通过工厂模式 + 反射的方法创建该对象的实例,并注入属性值
public class StudentFactory {
public static Student getStudent(){
String className = ...; // 通过 XML 解析获取全类名
String[] fieldNames = ..; // 通过 XML 解析获取字段名
String[] fieldValues = ...; // 通过 XML 解析获取字段值
Class clazz = Class.forName(className); // 通过反射创建对象实例
for (int i = 0; i < fieldNames.length; i++) {
// 依次为字段赋值
}
return clazz; // 返回创建的实例对象
}
}
IOC过程:xml解析、工厂模式、反射
反射:java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
反射就是把java类中的各种成分映射成一个个java对象
见入门案例
3.4 bean管理操作
什么是bean管理操作
- Spring创建对象
- Spring注入属性
bean管理操作的两种方式
- 基于xml配置文件
- 基于注解方式
3.4.1基于xml方式
基于xml方式创建对象
-
在spring的配置文件中使用bean标签,标签中添加属性,就可以实现对象创建
-
常用属性:
- id:唯一的标识
- class:创建对象所在类的全路径(包类路径)
-
创建对象时,默认也是执行无参的构造方法完成对象创建
基于xml方式注入属性
- DI:依赖注入,就是注入属性
使用set方法
通过property
标签指定属性名,spring会找到对应的setter方法,注入其属性值
使用有参的构造方法
使用constructor-arg
标签为对象的属性赋值
通过级联属性赋值
添加computer类
public class Computer {
String computerId;
String computerName;
public Computer() {
}
public Computer(String computerId, String computerName) {
this.computerId = computerId;
this.computerName = computerName;
}
public String getComputerId() {
return computerId;
}
public String getComputerName() {
return computerName;
}
public void setComputerId(String computerId) {
this.computerId = computerId;
}
public void setComputerName(String computerName) {
this.computerName = computerName;
}
@Override
public String toString() {
return "Computer{" +
"computerId='" + computerId + '\'' +
", computerName='" + computerName + '\'' +
'}';
}
}
在Student类中添加Computer属性
public class Student {
private Integer stuId;
private String stuName;
private Computer computer;
public Student() {
}
public Student(Integer stuId, String stuName, Computer computer) {
this.stuId = stuId;
this.stuName = stuName;
this.computer = computer;
}
public Integer getStuId() {
return stuId;
}
public void setStuId(Integer stuId) {
this.stuId = stuId;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public Computer getComputer() {
return computer;
}
public void setComputer(Computer computer) {
this.computer = computer;
}
@Override
public String toString() {
return "Student{" +
"stuId=" + stuId +
", stuName='" + stuName + '\'' +
", computer=" + computer +
'}';
}
}
演示级联属性的赋值
<?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元素定义一个由IOC容器创建的对象 -->
<!-- class属性指定用于创建bean的全类名 -->
<!-- id属性指定用于引用bean实例的标识 -->
<bean id="student" class="Student">
<!-- 使用property子元素为bean的属性赋值 -->
<property name="stuId" value="007"/>
<property name="stuName" value="lbw"/>
<property name="computer" ref="computer"/>
<property name="computer.computerId" value="128"/>
<property name="computer.computerName" value="hp"/>
</bean>
<bean id="computer" class="Computer">
</bean>
</beans>
通过 p 名称空间注入属性值
为了简化XML文件的配置,越来越多的XML文件采用属性而非子元素配置信息。Spring从2.5版本开始引入了一个新的p命名空间,可以通过元素属性的方式配置Bean的属性。使用p命名空间后,基于XML的配置方式将进一步简化。
<!--演示 p 名称空间注入属性值-->
<bean id="student" class="Student" p:stuId="1" p:stuName="zx"/>
xml注入其他类型的属性
- 字面量
在计算机科学中,字面量(literal)是用于表达源代码中一个固定值的表示法(notation)。几乎所有计算机编程语言都具有对基本值的字面量表示,诸如:整数、浮点数以及字符串;而有很多也对布尔类型和字符类型的值也支持字面量表示;还有一些甚至对枚举类型的元素以及像数组、记录和对象等复合类型的值也支持字面量表示法。 --百度百科
有个不太好,但是足以说明问题的解释,那就是 对象字面量就是引号引起来的部分,必须是等号右边的部分。虽然这样的解释不太好,但是确实如此,这就是字面量。
- 可以使用字符串表示的值,可以通过value属性或value子节点的方式指定
- 基本数据类型及其封装类、String等类型都可以采取字面值注入的方式
- 若字面值中包含特殊字符,可以使用<![CDATA[]]>把字面值包裹起来
- null
通过 <null/>
标签将引用类型字段的值设置为 null
<!--演示null值的使用-->
<bean id="student" class="Student">
<property name="stuId" value="233"/>
<!-- 将 stuName 字段的值设置为 null -->
<property name="stuName">
<null/>
</property>
<!-- 将 computer 字段的值设置为 null -->
<property name="computer">
<null/>
</property>
</bean>
3.引用外部 bean
通过 <property>
标签中的 ref
属性引用外部 bean
<!-- 引用外部声明的 bean -->
<bean id="student" class="Student">
<property name="stuId" value="233"/>
<property name="stuName" value="Oneby"/>
<!-- 通过 ref 属性引用外部的 bean -->
<property name="computer" ref="computer"/>
</bean>
<!-- 外部 bean -->
<bean id="computer" class="Computer">
<property name="computerId" value=