前言
- Spring 是一款目前主流的 Java EE 轻量级开源框架 ,是 Java 世界最为成功的框架之一。Spring 由“Spring 之父”Rod Johnson 提出并创立,其目的是用于简化 Java 企业级应用的开发难度和开发周期。
- Spring 自诞生以来备受青睐,一直被广大开发人员作为 Java 企业级应用程序开发的首选。时至今日,Spring 俨然成为了 Java EE 代名词,成为了构建 Java EE 应用的事实标准。
- Spring 框架不局限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何 Java 应用都可以从 Spring 中受益。Spring 框架还是一个超级粘合平台,除了自己提供功能外,还提供粘合其他技术和框架的能力。
接下来让我们跟着思维导图一起来学习了解Spring。
1. Spring简介
1.1 Spring的概述
Spring框架是一个开源的Java应用程序框架,旨在简化开发复杂的企业级Java应用程序。同时,也是一个分层的、面向切面的 Java 应用程序的一站式轻量级解决方案,它是 Spring 技术栈的核心和基础,是为了解决企业级应用开发的复杂性而创建的。 它提供了一套全面的解决方案,涵盖了从基本的核心功能到企业级应用开发所需的各种特性。
1.2 Spring的用途(功能作用)
Spring的功能作用
功能 | 作用说明 |
依赖注入(Dependency Injection,DI) | Spring框架通过依赖注入来实现对象之间的解耦。它使得对象之间的依赖关系由容器动态注入,而不是由对象自己负责创建或查找依赖。这样可以简化对象的创建和管理,提高代码的可维护性和可测试性。 |
控制反转(Inversion of Control,IoC) | IoC是依赖注入的一种实现方式,它将对象的创建和管理控制权转移到框架或容器中。通过IoC容器,开发者只需定义对象的声明,并由容器负责创建和管理对象的生命周期。这样可以降低对象之间的耦合,提高代码的可复用性。 |
切面编程(Aspect-Oriented Programming,AOP) | Spring框架提供了AOP的支持,使得开发者可以更容易地将横切关注点(如日志记录、事务管理等)与核心业务逻辑分离。AOP通过在运行时动态地将这些横切关注点织入到应用程序中,提高了代码的模块化和可重用性。 |
MVC框架 | Spring框架提供了Spring MVC,是一个基于模型-视图-控制器(Model-View-Controller,MVC)设计模式的Web框架。它可以帮助开发者构建灵活、可扩展的Web应用程序,并提供了一些常见的Web开发功能,如请求处理、视图解析、数据绑定等。 |
1.3 Spring的核心
简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。介于SpringMVC与Mybatis之间的中间层框架,作用:承上启下,相当于粘合剂。
核心
核心 | 核心描述 |
控制反转(IoC) | Inverse of Control 的简写,译为“控制反转”,指把创建对象过程交给 Spring 进行管理。 |
面向切面(AOP) | Aspect Oriented Programming 的简写,译为“面向切面编程”。 AOP 用来封装多个类的公共行为,将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,减少系统的重复代码,降低模块间的耦合度。另外,AOP 还解决一些系统层面上的问题,比如日志、事务、权限等。 |
1.4 Spring核心架构
Spring Core:提供依赖注入和Bean管理功能,主要组件是 BeanFactory
,它使用控制反转模式将应用程序配置和依赖规范与实际的应用代码分开;
Spring Context:扩展了BeanFactory
的概念,增加了对国际化、事件传播,以及验证等的支持,此外还提供了许多企业服务及对模版框架集成的支持;
Spring Web:建立于Context模块之上,提供了一个适合于Web应用的上下文。另外,这个模块还提供了一些面向服务支持,也提供了Spring和其它Web框架的集成;
Spring Web MVC:是一个全功能的构建 Web 应用程序的 MVC 实现,容纳了大量视图技术,如 JSP、Velocity、POI等;
Spring AOP:为Spring容器管理的对象提供了对面向切面编程的支持;
Spring DAO:该层封装了对数据库的访问,并且处理了其抛出的错误消息,同时还基于AOP模块提供了事务管理;
Spring ORM:Spring支持多种ORM框架(Mybatis、Hibernate),简化了数据库操作。
1.5 Spring的特点
- 轻量级:Spring框架是一款轻量级的框架,它的核心库非常小巧,只需很少的依赖就可以运行。
- 松耦合:Spring框架采用了依赖注入(Dependency Injection)和控制反转(Inversion of Control,IoC)的方式,通过容器动态注入对象的依赖关系,使得对象之间的耦合度降低。
- 面向切面编程(AOP):Spring框架提供了对面向切面编程的直接支持,可以将横切关注点(如事务管理、安全性、日志记录等)与核心业务逻辑相分离。
- 容器管理:Spring框架提供了一个容器(ApplicationContext),用于管理应用程序中的对象(Bean)。容器负责对象的创建、配置和生命周期的管理,开发者只需通过配置文件或注解定义Bean的声明,容器会负责实例化和管理这些Bean。
- 支持多种开发领域:Spring框架不仅适用于传统的Java EE开发,还可以应用于各种领域,如Web开发(Spring MVC)、数据访问(Spring JDBC、Spring ORM)、消息传递、安全性等。
- 测试友好:由于Spring框架的松耦合设计和依赖注入的支持,使得应用程序中的对象更易于进行单元测试。
- 社区支持和丰富的生态系统:Spring框架是一个开源项目,拥有庞大的社区支持和活跃的开发者社区。
2. Spring之IOC的特点
2.1 IOC的特点
IOC的特性
特性 | 说明 |
松耦合 | IOC通过将对象之间的依赖关系交由容器管理,降低了对象之间的耦合度。对象不再直接创建和管理依赖,而是通过容器动态注入依赖,使得对象之间的关联关系更加灵活和可扩展。 |
依赖注入 | IOC通过依赖注入(Dependency Injection)的方式,将对象的依赖通过构造函数、属性注入或接口注入的方式注入到对象中。这种注入的方式使得对象的依赖关系更加清晰明确,降低了对象的创建和维护的复杂性。 |
解耦业务逻辑 | IOC可以将对象的创建和依赖关系的管理委托给容器,从而将业务逻辑与对象的创建和依赖关系的管理解耦。可以实现业务逻辑的复用和管理的集中化,提高代码的可读性和维护性。 |
单一职责原则 | IOC的设计遵循单一职责原则,即每个对象只负责自己的业务逻辑,不涉及其他对象的创建和管理。 |
可测试性 | 由于对象的依赖关系由容器管理,因此在进行单元测试时,可以使用Mock对象替代真实的依赖关系。 |
可扩展性 | IOC的设计使得系统的扩展更加容易。当需要添加新的功能或更改现有功能时,只需要通过配置文件或注解修改依赖关系和配置信息,而无需修改对象的源代码。 |
配置灵活性 | IOC通过配置文件或注解的方式描述对象的依赖关系和配置信息,使得系统的配置更加灵活。 |
2.2 IOC控制反转实例
2.2.1 Spring-context.xml文件
在resources下创建一个Spring Config下创建一个xml文件,在文件中配置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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 凡是在Spring核心配置文件spring-context.xml中配置,那么javaBean就交给了spring容器管理--> <bean class="com.yx.ioc.web.UserAction" id="userAction"> <property name="userservice" ref="userService"></property> </bean> <bean class="com.yx.ioc.web.GoodsAction" id="goodsAction"> <property name="userservice" ref="userServiceImpl1"></property> </bean> <bean class="com.yx.ioc.service.UserServiceImpl" id="userService"></bean> <bean class="com.yx.ioc.service.UserServiceImpl1" id="userServiceImpl1"></bean> </beans>
2.2.2 pom.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>yx_spring</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>yx_spring Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <spring.version>5.0.1.RELEASE</spring.version> <javax.servlet.version>4.0.0</javax.servlet.version> <junit.version>4.12</junit.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <!-- 2、导入spring依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <!-- 5.1、junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <!-- 5.2、servlet --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>${javax.servlet.version}</version> <scope>provided</scope> </dependency> </dependencies> <build> <finalName>yx_spring</finalName> <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging --> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.1</version> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>3.2.2</version> </plugin> <plugin> <artifactId>maven-install-plugin</artifactId> <version>2.5.2</version> </plugin> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>2.8.2</version> </plugin> </plugins> </pluginManagement> </build> </project>
2.2.3 web文件代码
用于响应请求
UserAction
package com.yx.ioc.web; import com.yx.ioc.service.UserService; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-08-15 16:01 * 用户模块模拟使用用户修改信息的方法 * *程序员手动实例化的对象的弊端 * 1.一旦依赖的接口的实现需要大幅度的改动、迭代,则维护的成本提高。 * 2.当接口的实现类不统一的情况下,维护的成本更高。 * */ public class UserAction { // 实例化业务逻辑层 private UserService userservice; public UserService getUserservice() { return userservice; } public void setUserservice(UserService userservice) { this.userservice = userservice; } /** * 修改用户信息的请求 * @return */ public String update(){ // 调用修改用户信息的方法 userservice.update(); return "list"; } }
GoodsAction
package com.yx.ioc.web; import com.yx.ioc.service.UserService; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-08-15 16:02 * 商品模块模拟使用用户修改信息的方法 */ public class GoodsAction { // 实例化业务逻辑层 private UserService userservice; public UserService getUserservice() { return userservice; } public void setUserservice(UserService userservice) { this.userservice = userservice; } /** * 修改用户信息的请求 * @return */ public String update(){ // 调用修改用户信息的方法 userservice.update(); return "list"; } }
2.2.4 service文件代码
用来编写服务请求响应
UserService接口类
package com.yx.ioc.service; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-08-15 15:46 * 用户修改信息接口类 */ public interface UserService { //定义一个方法模拟更改用户信息 /** * 用户修改信息的方法 */ public void update(); }
UserServiceImpl实现类
package com.yx.ioc.service; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-08-15 15:47 * 用户修改信息实现类 */ public class UserServiceImpl implements UserService { /** * 实现接口修改信息的方法 */ public void update() { //修改用户信息的功能 System.out.println("更改用户个人信息......"); // 上传头像的功能 // System.out.println("上传用户头像......"); } }
UserServiceImpl1实现类
package com.yx.ioc.service; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-08-15 15:47 * 用户修改信息实现类 */ public class UserServiceImpl1 implements UserService { /** * 实现接口修改信息的方法 */ public void update() { //修改用户信息的功能 System.out.println("更改用户个人信息......"); // 上传头像的功能 System.out.println("上传用户头像......"); } }
2.2.5 效果测试类
Demo1类
package com.yx.ioc.demo; import com.yx.ioc.web.GoodsAction; import com.yx.ioc.web.UserAction; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-08-15 17:01 */ public class Demo1 { public static void main(String[] args) { // 加载spring核心配置文件(建模),获取spring的上下文对象,上下文对象中可以获取任何JavaBean对象 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/Spring-context.xml"); // 用户模块 UserAction userAction = (UserAction) context.getBean("userAction"); userAction.update(); // 商品模块 GoodsAction goodsAction= (GoodsAction) context.getBean("goodsAction"); goodsAction.update(); } }
效果
我们可以根据修改Spring-context.xml文件中的bean属性来达到我们想要的功能效果。
3. Spring的三种配置方式
//方式一:单独加载指定spring.xml配置文件 ApplicationContext ac=new ClassPathXmlApplicationContext("classpath:spring.xml"); //方式二:一次加载多个配置文件,数组方式 ApplicationContext ac= new ClassPathXmlApplicationContext (new String[]{"spring-mybatis.xml","spring-redis.xml"}); //方式三:使用*通配符方式 ApplicationContext ac=new ClassPathXmlApplicationContext("classpath:spring-*.xml");
4. Bean元素的常用属性
属性 | 描述 |
id | Bean 的唯一标识符,Spring 容器对 Bean 的配置和管理都通过该属性完成。id 的值必须以字母开始,可以使用字母、数字、下划线等符号。 |
name | name 属性中可以为 Bean 指定多个名称,每个名称之间用逗号或分号隔开。Spring 容器可以通过 name 属性配置和管理容器中的 Bean。 |
class | 该属性指定了 Bean 的具体实现类,它必须是一个完整的类名,即类的全限定名。 |
scope | 用于设定 Bean 实例的作用域,属性值可以为 singleton(单例) 、prototype(原型) 、request、session 和 global Session。其默认值是 singleton |
constructor-org | <bean> 元素的子元素,可以使用此元素传入构造参数进行实例化。该元素的 index 属性指定构造参数的序号(从 0 开始),type 属性指定构造参数的类型 |
property | <bean> 元素的子元素,用于调用 Bean 实例中的 setter 方法来属性赋值,从而完成依赖注入。该元素的 name 属性用于指定 Bean 实例中相应的属性名 |
ref | <property> 和 <constructor-arg> 等元素的子元素,该元素中的 bean 属性用于指定对某个 Bean 实例的引用 |
value | <property> 和 <constractor-arg> 等元素的子元素,用于直接指定一个常量值 |
list | 用于封装 List 或数组类型的依赖注入 |
set | 用于封装 Set 类型的依赖注入 |
map | 用于封装 Map 类型的依赖注入 |
entry | 元素的子元素,用于设置一个键值对。其 key 属性指定字符串类型的键值,ref 或 value 子元素指定其值 |
init-method | 容器加载 Bean 时调用该方法,类似于 Servlet 中的 init() 方法 |
destory-method | 容器删除 Bean 时调用该方法,类似于 Servlet 中的 destroy() 方法。该方法只在 scope=singleton 时有效 |
lazy-init | 懒加载,值为 true,容器在首次请求时才会创建 Bean 实例;值为 false,容器在启动时创建 Bean 实例。该方法只在 scope=singleton 时有效 |
5. Spring的三种注入方式
5.1 Set注入
Spring-context.xml文件配置
<bean class="com.yx.ioc.web.GoodsAction" id="goodsAction"> <property name="userservice" ref="userServiceImpl1"></property> <property name="gname" value="乐事"></property> <property name="age" value="3"></property> <property name="people"> <list> <value>老人</value> <value>小孩</value> <value>青年</value> </list> </property> </bean>
GoodsAction代码
package com.yx.ioc.web; import com.yx.ioc.service.UserService; import java.util.List; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-08-15 16:02 * 商品模块模拟使用用户修改信息的方法 */ public class GoodsAction { // 实例化业务逻辑层 private UserService userservice; private String gname;//名称 private int age;//保质期 private List<String> people;//使用人群 // Set和get方法 public String getGname() { return gname; } public void setGname(String gname) { this.gname = gname; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public List<String> getPeople() { return people; } public void setPeople(List<String> people) { this.people = people; } public UserService getUserservice() { return userservice; } public void setUserservice(UserService userservice) { this.userservice = userservice; } public void pros(){ System.out.println(this.getGname()); System.out.println(this.getAge()); System.out.println(this.getPeople()); } }
测试类Demo1
GoodsAction goodsAction= (GoodsAction) context.getBean("goodsAction"); goodsAction.pros();
输出结果
5.2 构造注入
Spring-context.xml文件配置
<bean class="com.yx.ioc.web.UserAction" id="userAction"> <property name="userservice" ref="userService"></property> <constructor-arg name="uname" value="liubing"></constructor-arg> <constructor-arg name="age" value="18"></constructor-arg> <constructor-arg name="hooby"> <list> <value>唱</value> <value>跳</value> <value>Rap</value> </list> </constructor-arg> </bean>
UserAction类代码
package com.yx.ioc.web; import com.yx.ioc.service.UserService; import java.util.List; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-08-15 16:01 * 用户模块模拟使用用户修改信息的方法 * *程序员手动实例化的对象的弊端 * 1.一旦依赖的接口的实现需要大幅度的改动、迭代,则维护的成本提高。 * 2.当接口的实现类不统一的情况下,维护的成本更高。 * */ public class UserAction { // 实例化业务逻辑层 private UserService userservice; private String uname;//姓名 private int age;//年龄 private List<String> hooby;//爱好 public String getUname() { return uname; } public void setUname(String uname) { this.uname = uname; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public List<String> getHooby() { return hooby; } public void setHooby(List<String> hooby) { this.hooby = hooby; } // 无参构造 public UserAction() { } //有参构造 public UserAction(String uname, int age, List<String> hooby) { this.uname = uname; this.age = age; this.hooby = hooby; } public void pros(){ System.out.println(this.getUname()); System.out.println(this.getAge()); System.out.println(this.getHooby()); }
测试类Demo1代码
UserAction userAction = (UserAction) context.getBean("userAction"); userAction.pros();
输出结果
6. Spring中自动装配中的byname和byType的区别:
- Byname:JavaBean会根据属性名在Spring的上下文中进行寻找,根据Spring上下文中的Bean的id进行查找,只要找到了那么就会自动注入。
- ByType:JavaBean会根据属性名对应的接口类型,在Spring上下文中查找,是根据spring上下文中是否又该类型接口的实现类,如果有则会自动注入;如果找到两个及两个以上则会报错,运行错误。
7. Spring上下文与tomcat服务器整合
配置项目到服务器中
创建一个Listener文件夹,创建一个监听器
SpringloadListener类监听器
package com.yx.ioc.Listener; import org.springframework.context.support.ClassPathXmlApplicationContext; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-08-17 1:25 * 监听器 */ @WebListener public class SpringloadListener implements ServletContextListener { public void contextInitialized(ServletContextEvent sce) { System.out.println("初始化: 将Spring上下文放入tomcat上下文"); // 将Spring上下文放入tomcat上下文 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/Spring-context.xml"); // 获取tomcat上下文 ServletContext servletcontext= sce.getServletContext(); servletcontext.setAttribute("springContext",context); } }
创建一个Servlet,用来处理相应请求。
UserServlet类
package com.yx.ioc.web; import com.yx.ioc.service.UserService; import org.springframework.context.support.ClassPathXmlApplicationContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-08-17 1:39 * */ @WebServlet("/userList") public class UserServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 当处理用户请求的时候,获取spring的上下文对象 ClassPathXmlApplicationContext context = (ClassPathXmlApplicationContext) req.getServletContext().getAttribute("springContex"); UserService userService= (UserService) context.getBean("userService"); // 打印输出验证 System.out.println(userService); // 调用方法 userService.update(); } }
启动服务器,运行项目在浏览器运行路径,查询控制台输出的结果。