Spring 介绍
官方文档:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html
spring 是一个开源的 java 框架,一个轻量级的、非入侵式的框架。
spring 框架是以 interface21 框架为基础,经过重新设计,并且不断丰富内容。于 2004 年 3 月 24 日发布了 1.0 正式版
spring 理念:使现有点技术更加容易使用,它本身是一个大杂烩,整合了现有的技术框架!
spring 核心技术:IOC (控制反转), AOP (面向切面编程)
Spring 特点
- 方便解耦,简易开发
- AOP 编程的支持
- 方便程序测试
- 方便和其他框架整合,像 SSM(SpringMvc + Spring + Mybatis)
- 方便进行事务的操作
- 降低 API 的使用难度
Spring 7 大模块
核心容器(Spring Core):核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转 (IOC)模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
Spring 上下文(Spring Coutext):Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
IOC 概念
IOC,Inversion of Control : 控制反转, 是一个理论,一个指导思想。 指导开发人员如何使用对象,管理对象的。 把对象的创建,属性赋值,对象的声明周期都交给代码之外的容器管理。
在 Spring 之前的业务中,用户的需求可能会影响我们原来的代码,需要根据用户的需求去修改代码,如果程序代码量很大,修改一次的成本就会变得十分昂贵
例如:
// 定义 DAO 接口
public interface UesrDAO {
void getUser();
}
//DAO 接口实现类
public class UserDAOImpl implements UesrDAO{
@Override
public void getUser() {
System.out.println("默认获取用户的信息");
}
}
// 业务层接口
public interface UserService {
void getUser();
}
// 实现业务层调用 DAO 层
public class UserServiceImpl implements UserService{
private UesrDAO uesrDAO=new UserDAOImpl();
public void getUser() {
uesrDAO.getUser();
}
}
public class MyText {
public static void main(String[] args) {
// 用户实际接触的是业务层,dao 层是不需要接触的
UserService userService=new UserServiceImpl();
userService.getUser();
}
}
// 控制台输出:默认获取用户的信息
这时候有个需求说要增加一个实现 mysql 获取用户信息,这时候我们就需要添加 DAO
// 实现 MySQL 获取用户数据
public class UserDAOMySQLImpl implements UesrDAO{
public void getUser() {
System.out.println("MySQL获取用户数据!");
}
}
为了让客户使用到 MySQL 获取用户信息就一定要去业务层修改
// 实现业务层调用 DAO 层
public class UserServiceImpl implements UserService{
// 这里原本的 UserDAOImpl 要改成 UserDAOMySQLImpl
private UesrDAO uesrDAO=new UserDAOMySQLImpl();
public void getUser() {
uesrDAO.getUser();
}
}
当代码量十分庞大的时候,实现了多个对象,我们就需要改动很多的地方,这是一个很大的代价,并且十分麻烦,这就造成了用户需求变了,就得去改动大量的代码。
所以需要一个方法来解决这个问题,使对象生成不在写死,而是改成由用户需求来生成对象。
private UesrDAO uesrDAO;
public void setUesrDAO(UesrDAO uesrDAO) {
this.uesrDAO = uesrDAO;}
使用 set 进行动态实现值的注入,这使得程序可以实现需要什么实现就用对应的接口
之前,程序是主动创建对象!控制权在程序员手上!所以用户的改动需求就需要程序员去改动代码。
使用了 set 注入后,程序不再具有主动性,而是变成了被动的接受对象!
这种思想,从本质上解决了问题,我们程序猿不用再去管理对象的创建了,系统的耦合性大大降低,可以更加专注的在业务都实现上!这是 IOC 的原型!
IOC 本质:控制反转 IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现 IoC 的一种方法,也有人认为 DI 只是 IOC 的另一种说法。没有 IOC 的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
控制反转是一种通过描述(XML 或注解)并通过第三方去生产或获取特定对象的方式。在 Spring 中实现控制反转的事 IoC 容器,其实现方法是依赖注入(Dependency Injection,DI)。
AOP 概念
AOP (Aspect Orient Programming),直译过来就是 面向切面编程。AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。面向对象编程将程序抽象成各个层次的对象,而面向切面编程是将程序抽象成各个切面。
为什么需要 AOP:在开发的多个模块过程中,这些模块会有某段代码是重复的,我们经常把这段代码抽象成 一个方法,然后再我们需要这段代码的时候去调用这个方法,这样的话但需要改变这段代码的时候直接改变这个方法就好了。然而需求总是变化的,有一天,新增了一个需求,需要再多出做修改,我们需要再抽象出一个方法,然后再在需要的地方分别调用这个方法,又或者我们不需要这个方法了,我们还是得删除掉每一处调用该方法的地方。实际上涉及到多个地方具有相同的修改的问题我们都可以通过 AOP 来解决。
AOP 要达到的效果是,保证开发者不修改源代码的前提下,去为系统中的业务组件添加某种通用功能。
按照 AOP 框架修改源代码的时机,可以将其分为两类:
- 静态 AOP 实现, AOP 框架在编译阶段对程序源代码进行修改,生成了静态的 AOP 代理类(生成的 *.class 文件已经被改掉了,需要使用特定的编译器),比如 AspectJ。
- 动态 AOP 实现, AOP 框架在运行阶段对动态生成代理对象(在内存中以 JDK 动态代理,或 CGlib 动态地生成 AOP 代理类),如 SpringAOP。
Spring 中的 AOP 是通过动态代理实现的。
第一个 Spring 程序
构建一个 maven 项目
然后再 pom.xml 文件中加入
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.10</version>
</dependency>
导入 org.springframework 包会自动帮我们导入其他的包,像 spring-beans、spring-core 之类的组件会自动导入
// 创建一个类
public class Hello {
private String str;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
public String toString() {
return "Hello{" +
"str='" + str + '\'' +
'}';
}
}
配置元数据(现在的 Spring 已经可以使用注解去配置了,但这里展示的还是使用 xml 配置)
在 resource 文件夹下创建 beans.xml (官方的名字是:applicationContext.cml,但这里命名无所谓)
<?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 https://www.springframework.org/schema/util/spring-util.xsd">
<!-- 使用 Spring 来创建对象,在 Spring 这些都成为 bean-->
<!-- <bean id="自己命名" class="想要的类对应的路径" -->
<!-- property 中 value 对应的是具体的值 ref 对应的是这个 spring 容器中创建好的对象(eg. 此处的 hello)-->
<bean id="hello" class="com.Spring.Hello">
<!--<property name="想要设置字段的名字" value="设置的值"></property> -->
<property name="str" value="Spring"></property>
</bean>
</beans>
public class MyText {
public static void main(String[] args) {
// 获取 Spring 的上下文对象,拿到 Spring 容器
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 我们的对象现在都在 Spring 管理了,我们需要使用就直接去里面取出来就好了
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello.toString());
}
}
// 然后控制台就输出了:Hello {str='Spring'}
- hello 是谁创建的?
- hello 是由 Spring 创建的
- hello 对象的属性怎么设值?
- hello 对象的属性是由 Spring 容器控制的
<!--
类型 变量名 = new 类型 ();
Hello hello = new Hello ():
id = 变量名
class = new 的对象
property 相当于给对象中的属性设置一个值
-->
这个过程就叫控制反转:
控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用 Spring 后,对象由 Spring 来创建
反转:程序本身不创建对象,而变成被动的接收对象。
依赖注入:就是利用 set 方法来进行注入。
IOC 是一种编程思想,由主动点编程编程被动的接收。
要实现不同的操作,只需要在 xml 配置文件中进行修改,所谓的 IOC 就是:对象由 Spring 来创建,管理,装配!
IOC 创建对象的方式
- 它是使用无参的构造方法来创建对象的,也是它的默认实现
public class User {
private String name;
public User(){
System.out.println("无参构造方法");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show() {
System.out.println("name=" + name);
}
}
配置文件
<?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 https://www.springframework.org/schema/util/spring-util.xsd">
<bean id="user" class="com.Spring.User">
<property name="name" value="张三"></property>
</bean>
</beans>
测试
public class MyText {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user = (User) context.getBean("user");
user.show();
}
}
// 控制台输出的是:
// 无参构造方法
// name = 张三
和我们普通创建对象一样,在没有参数的构造方法的时候,它默认走的是无参的构造方法来创建对象
假设我们使用有参构造来创建对象
- 通过下标赋值
public class User { private String name; // 当设立一个有参构造方法时,如果不再设置无参构造方法,那就不会有无参的构造方法 // 当完全没有构造方法时,系统默认有个无参的构造方法 public User(String name){ this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void show() { System.out.println("name=" + name); } }
<?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 https://www.springframework.org/schema/util/spring-util.xsd"> <bean id="user" class="com.Spring.User"> <constructor-arg index="0" value="李四"></constructor-arg> </bean> </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" 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 https://www.springframework.org/schema/util/spring-util.xsd"> <bean id="user" class="com.Spring.User"> <constructor-arg type="java.lang.String" value="王五"></constructor-arg> </bean> </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" 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 https://www.springframework.org/schema/util/spring-util.xsd"> <bean id="user" class="com.Spring.User"> <constructor-arg name="name" value="李六"></constructor-arg> </bean> </beans>
总结:在配置文件加载的时候,容器中管理的对象就已经初始化了!
有待更新...