Spring 介绍
Spring 是一个轻量级的开源框架,目的是简化Java项目开发的复杂性,其核心是IOC
(控制反转容器)和AOP
(面向切面编程)。
Spring 官网:Spring | Home
Spring 框架概览
-
Core Container(核心容器)
-
-
Beans & Core: 提供框架基础,包含IOC(控制反转)DI(依赖注入)功能。
-
Context:建立在Core和Beans之上,提供了类似JNDI注册表的方式来访问容器内的对象——通过名字获取对象。Context从Beans继承了基本功能并增加了对国际化、事件传播、资源加载的支持。该模块也支持JavaEE功能,如EJB、JMX、基本的远程访问等。
-
Expression Language:是JSP2.1 规范中EL表达式的扩展,提供了强大的表达式语言支持。
-
-
Data Access/Integration(数据访问和集成)
-
-
JDBC:提供了JDBC抽象层,声明性事物管理。
-
ORM:提供常用“对象/关系”映射框架的集成,包括PA/JDO/Hibernate/iBatis。
-
OXM:提供了一个抽象层,用于支持“对象/XML”的映射实现,这些实现有JAXB、Castor、XMLBeans、JiBX、Xstream。
-
JMS:Java Messaging Service ,Java消息服务,包含生产和消费一步消息的功能。
-
Transactions : 支持编程式或声明式事务管理,进行管理的类可以是实现了特定接口的类,也可以是普通的类。
-
-
Web(MVC/Remoting)
-
-
Web: 提供基本的面向Web的集成功能,如文件上传、使用Servlet监听器初始化IOC容器和针对Web的应用上下文,同时包含了对远程访问的支持部分。
-
Servelt:提供了SpringMVC实现。
-
Struts: 包含了集成Struts1所需的支持类,不过从Spring3.0开始,这些类已被弃用,建议使用Struts2集成Spring的方案。
-
Portlet: 提供了用于Portlet环境的MVC实现。
-
-
AOP、Aspects、Instrumentation
-
-
AOP:提供了规范的面向切面编程的实现,让我们可以自定义方法拦截器(MethodInterceptor)和切入点(Pointcut),从而将通用功能性代码与业务逻辑完全分离。
-
Aspects : 提供了与AspectJ(专门的AOP框架)的集成。
-
Instrumentation:提供了仪表化支持和用于具体服务器的ClassLoader的实现。
-
-
Test
-
Test模块用于支持Spring与JUnit或TestNG集成,方便对系统功能进行测试。
-
Spring 使用步骤
-
导 jar 包
Spring 框架相关的jar包很多,刚开始只需导入Spring 容器基础 jar 包即可。
<!-- Spring 容器基础包 --> <dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.20</version> </dependency>
-
写配置文件
Spring 配置文件又称为容器文件,用来管理 Spring 工程中所有 JavaBean 的生命周期。容器文件名为
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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 创建一个日期时间对象。id:指定 bean 的名字;class:指定 bean 的类型 --><bean id="now" class="java.util.Date" /></beans>
Spring IOC(控制反转容器)
Spring IOC(控制反转容器),负责 JavaBean 的创建、JavaBean的管理和依赖的维护。IOC 底层原理主要是通过 xml 解析获取类信息,通过反射机制创建类对象,再通过工厂模式管理创建的对象。它将对象的创建和依赖注入的控制权从应用程序转移到容器中,降低了类之间的耦合,增强了代码的灵活性和可维护性。
可以理解为,在创建对象的环节,容器帮我们把new这个步骤做了,当需要对象的时候直接从容器取而不需要自己new,只要自己在配置文件,注册了一个想要的bean,后续就可以直接取对象
Spring IOC XML配置
准备工作:
Student.java
public class Student {//依赖属性:name、age、birthdayprivate String name; //姓名private int age; //年龄private Date birthday; //生日//构造器public Student(){}public Student(String name, int age, Date birthday) {this.name = name;this.age = age;this.birthday = birthday;}//省略 setter、toString等方法
}
StudentDao.java
public class StudentDao {//依赖属性:stuprivate Student stu;//构造器public StudentDao() {}public StudentDao(Student stu) {this.stu = stu;}//setter方法public void setStudent(Student stu) {this.stu = stu;}public void initDao(){System.out.println("初始化 StudentDao");}public void destroyDao(){}
}
配置文件
Spring 配置文件 applicationContext.xm 是 IOC 容器文件,IOC 正是通过此文件进行 JavaBean的创建、管理和维护。其基本格式如下,使用不同的功能,引入的 schema 可能会不同。下文讲解的 Bean的注册、作用域、延迟加载、DI 等配置,皆放在该文件 <beans> 标签下。
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"></beans>
Bean 的生命周期
Bean 的生命周期主要包括:Bean的注册(实例化)、Bean属性设置(DI)、Bean初始化、Bean的使用、Bean的销毁。
Bean 的注册
通过一个 <bean>
标签即可向 IOC容器注册一个JavaBean。
<!-- id: 对象名,唯一不可重复name:对象名,同id,可逗号隔开多个名字class:对象类型,唯一的必须属性init-method:指定 bean 的初始化方法,在 bean 被创建时执行destroy-method:指定 bean 的销毁方法,在 bean 被卸载时执行scope:指定 bean 的作用域
-->
<bean id="today" name="t1,t2,t3" class="java.util.Date" />
<bean id="stu" class="com.lsy.demo.pojo.Student" />
<bean id="studentDao" class="com.lsy.demo.dao.StudentDao" init-method="initDao"lazy-init="false"destroy-method="destroyDao"scope="singleton"/>
Bean 的依赖注入(DI)
注入方式
一个 JavaBean 可能拥有成员属性(即依赖于其它JavaBean,比如上面的Student
依赖于name
、age
、birthday
三个属性,StudentDao
依赖于stu
一个属性),给这些依赖的属性赋值,称为DI(依赖注入)。DI 有两种方式:setter 注入 和 构造器注入。
-
setter 注入
setter 注入,即 IOC 通过类提供的 setter 方法,为类对象的属性注入值。
-
构造器注入
构造器注入,即 IOC 通过类提供的 构造方法,为类对象的属性注入值。
装配形式
无论是 setter 注入,还是构造器注入,都可以采用手动装配和自动装配两种方式。下面通过为Student
类注入name
、age
、birthday
三个属性,并为 StudentDao
注入 stu
属性,讲解两种装配方式。
-
手动装配
手动装配,即通过<property>标签(setter注入)或<constructor-arg>标签(构造器注入),手动配置依赖。
-
setter注入:通过 <property> 配置依赖属性值
<!--属性值是9种简单数据类型(8种基本类型+String),用value;是其它引用数据类型,用 ref --> <bean id="stu" class="com.lsy.demo.pojo.Student"><property name="name" value="libai" /><property name="age" value="20" /><!-- birthday 属性引用一个名字叫 today 的 bean --><property name="birthday" ref="today" /> </bean>
-
构造器注入:通过 <constructor-arg> 配置依赖属性值
方式 1:通过构造方法 形参类型 注入
<bean id="stu" class="com.lsy.demo.pojo.Student"><constructor-arg type="java.lang.String" value="libai"/><constructor-arg type="int" value="20"/><constructor-arg type="java.util.Date" ref="today"/> </bean>
方式 2:通过构造方法 形参名字 注入
<bean id="stu" class="com.lsy.demo.pojo.Student"> <constructor-arg name="name" value="libai"/> <constructor-arg name="age" value="20"/> <constructor-arg name="birthday" ref="today"/> </bean>
方式 3:通过构造方法 形参序号 注入
<bean id="stu" class="com.lsy.demo.pojo.Student"><constructor-arg index="0" value="libai"/><constructor-arg index="1" value="20"/><constructor-arg index="2" ref="today"/> </bean>
-
命名空间简化注入书写形式
p:namespace
,setter注入的简写形式。简写语法:p:属性名=属性值
。c:namespace
,构造器注入的简写形式。简写语法:c:属性名=属性值
。<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:p="http://www.springframework.org/schema/p"xmlns:c="http://www.springframework.org/schema/c"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="today" class="java.util.Date" /><!-- p-namespace 简化 setter注入写法 --><bean id="stu1" class="com.lsy.demo.pojo.Student" p:name="libai" p:age="20"><property name="birthday" ref="today" /></bean><!-- c-namespace 简化 构造器注入写法 --><bean id="stu2" class="com.lsy.demo.pojo.Student" c:name="libai" c:age="20"><constructor-arg name="birthday" ref="today" /></bean> </beans>
注意:使用这两个命名空间,需要在配置文件中添加相应的
schema
格式声明(xmlns:p 和 xmlns:c)。 同时需要注意的是,该简化写法只能简化值为value
的属性,值为ref
的属性无法简化。
-
-
自动装配
自动装配,即通过<bean>标签的
autowire
属性,设置由IOC容器根据设置的装配规则,自动在容器中寻找合适的依赖对象,完成依赖注入。-
装配规则
autowire="default" # 不自动注入 autowire="no" # 不自动注入autowire="byName" # 自动在容器中寻找与属性同名的对象,通过setter 注入 autowire="byType" # 自动在容器中寻找与属性同类型的对象,通过setter 注入 autowire="constructor" # 自动在容器中寻找与构造器形参同名的对象,通过构造器注入
-
示例
<!--IOC通过寻找容器中与 studentDao 依赖的属性 stu同名(autowire="byName")的对象(即 id="stu"的Bean对象),自动完成stu 的注入(即将找到的 id="stu"的JavaBean 赋值给 studentDao 的属性 stu)。--> <bean id="studentDao" class="com.lsy.demo.dao.StudentDao" autowire="byName" />
-
Bean 初始化
<bean class="com.lsy.demo.dao.StudentDao" init-method="initDao"/>
Bean 的延迟加载
Spring 中的 单例 bean 默认是随 IOC 容器的启动初始化(多例 bean 本就是需要时才创建,也就不存在延迟初始化设置) ,为提高容器的加载效率,可以设置 bean 为延迟初始化,这样在需要该 bean 实例时,IOC 才会去创建它。类似单例模式中的即时加载(饿汉式)和懒加载(懒汉式)。
通过给 <bean> 标签添加一个 lazy-init=default|false|true
属性,可设置 bean 是否延迟加载。设置为 true,即启用延迟初始化。默认为不启用。
-
测试方法准备:
public static void main(String[] args) {String path = "applicationContext.xml";ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext(path);//ioc.getBean(StudentDao.class); }
-
立即初始化 配置
<!-- lazy-init 可省略,默认即为不启用延迟加载--> <bean class="com.lsy.demo.dao.StudentDao" init-method="initDao" lazy-init="false" />
测试方法输出结果:
初始化 StudentDao
结果显示 studentDao 的初始化方法已被执行,说明 studentDao 随着IOC容器的加载已被创建并初始化。
-
延迟初始化 配置
<bean class="com.lsy.demo.dao.StudentDao" init-method="initDao" lazy-init="true"/>
测试方法输出结果:
//无输出
结果显示 studentDao 的初始化方法没有执行,说明延迟加载已生效。
那么延迟初始化的 bean 什么时候被创建呢?答案是:使用的时候。将测试方法中注掉的获取 studentDao 的这行代码恢复,再次运行测试,程序将再次输出下面的结果:
初始化 StudentDao
Bean 销毁
<bean class="com.lsy.demo.dao.StudentDao" destroy-method="destroyDao"/>
Bean 的作用域
作用域 | 描述 |
---|---|
singleton | 单例模式(bean 默认作用域) ,实例化的 Bean 在整个 Spring IOC 容器生命周期中只创建一次,单个 Bean 被绑定到单个对象实例。 |
prototype | 多例模式,Spring IOC 容器初始化时不创建 Bean 的实例,而是在通过 getBean 获取 Bean 时才会创建一个新的 Bean 实例并返回, 单个 Bean 定义可以被绑定到多个对象实例。 |
request | 单个 Bean 定义被绑定到单个的 HTTP 请求生命周期。就是每一个 HTTP 请求都有属于他自己的单独实例创建,这个只能在 web-aware Spring ApplicationContext 中有效。 |
session | 单个 Bean 定义会被绑定到 HTTP Session 的生命周期中,这个只能在 web-aware Spring ApplicationContext 中有效。 |
application | 单个 Bean 定义会被绑定到 ServletContext 的生命周期中,这个只能在 WebApplicationContext 中有效。 |
websocket | 单个 Bean 的定义会被绑定到 WebSocket 的生命周期中,这个只能在 WebApplicationContext 中有效。 |
上述几种作用域,在实际开发中 singleton
和 prototype
值最常用的两种。 具体配置中,通过 <bean> 标签的 scope
属性进行配置。
<bean class="com.lsy.demo.dao.StudentDao" scope="singleton"/>
启动 IOC 容器
public static void main(String[] args) {String path = "applicationContext.xml";// 加载 IOC 容器ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext(path);// 获取 beanioc.getBean(...);
}