Welcome Huihui's Code World ! !
接下来看看由辉辉所写的关于Spring的相关操作吧
目录
Welcome Huihui's Code World ! !
一.什么是Spring
二.Spring的特点
三.什么是IOC
场景模拟:
控制反转:
使用步骤
1 创建Maven的war项目然后配置web的相关依赖以及项目结构的配置
2在pom.xml文件中配置Spring的依赖
3 在resources下创建并配置spring-context.xml
4 在业务层中创建WorkBiz接口及其实现类
5 在项目中创建MVC的包结构,并创建Web层,并获取Spring的容器对象
6 测试
7 总结
四.IOC的实现方式
五.IOC依赖注入的三种方式
1.Setter方法注入(Setter Injection):
2.构造函数注入(Constructor Injection):
3.接口注入(Interface Injection):
byName:
byType:
六.spring与web容器的整合
1.监听器的初始化方法 只执行一次
2.spring的上下文要存放在Tomcat上下文中
▲Spring是一个开源框架,它由Rod Johnson创建。它是为了解决企业应用开发的复杂性而创建的
▲ Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情
简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架
轻量级和非侵入性:Spring框架采用轻量级的设计理念,不侵入应用程序的业务逻辑,使得应用程序可以更加灵活和可维护
控制反转(IoC)和依赖注入(DI):IoC是Spring框架的核心概念,它通过DI将对象的创建和依赖关系的管理从应用程序代码中解耦出来。这样可以降低代码的耦合性,提高代码的可测试性和可维护性
面向切面编程(AOP):Spring框架通过AOP提供了一种在应用程序中优雅地处理横切关注点的方式。通过AOP,可以将一些与主要业务逻辑无关的功能,如日志记录、事务管理等,从应用程序代码中分离出来,使得代码更加简洁和可维护
数据访问和集成:Spring框架提供了一系列的数据访问和集成模块,如JDBC、ORM(Object-Relational Mapping)、事务管理等。这些模块可以帮助开发人员更加方便地与数据库进行交互,处理事务以及与第三方系统进行集成
Web开发支持:Spring框架提供了一系列的Web开发支持模块,如Spring MVC、Spring WebFlux等。这些模块可以帮助开发人员构建灵活、可扩展和高性能的Web应用程序
那么在这篇博客中,我们就来详细的解剖一下IOC【控制反转】,首先让我们看一看IOC到底是个什么吧!!!
▲IOC(Inversion of Control,控制反转)是软件开发中的一种设计原则和编程思想。它指的是将对象的创建和依赖关系的管理转移给外部容器(通常是框架或容器),从而实现了对象间的解耦
⭕在传统的开发模式中,对象之间的依赖关系是由对象自己负责管理的。例如,如果一个对象需要依赖其他对象,它会通过直接实例化其他对象或使用静态方法获取依赖对象。这样的实现方式使得对象之间高度耦合,难以进行更改和测试,因而会使得项目难以维护
▲而在IOC的思想下,对象的创建和依赖关系的管理被转移给一个外部容器。容器负责实例化对象,并在对象之间建立依赖关系。对象只需要声明自己所需要的依赖,容器会自动注入这些依赖。这样可以大大降低代码的耦合性,使得代码更加模块化、可扩展和可测试
了解了IOC是什么之后,可能我们对于IOC的便捷之处还没有一个更加直观的了解,那么接下来我将用代码(不过都是一个简单的模拟)来展示,这样也可以更加直观的感觉出IOC的便捷!!
场景模拟:
在一个公司的管理系统中,管理层都需要管理公司的事物以及员工, 但是每个管理层管理员工所关注的点是不同的,因为每个管理者的工作是不同的 因此需要做出一个十分好用的管理系统还是需要考虑很多方面的,有一天你所在的公司接到了一个项 目:xx公司的管理系统 恰好你就被派任到此项目了,此时你就需要完成一个公司的人员管理系统 接下来就是甲方给你提需求了! 需求1: 现在人事管理的模块和财务管理的模块都需要查询到用户的信息 那么我只需要写一个dao方法和一个biz,然后在人事和财务的web层中调用用户的biz层package com.wh.biz.impl; import com.wh.biz.WorkerBiz; /** * @author 王辉 * @site www.shihuihuila.com * @create 2023-08-15 16:35 */ public class WokerBizImpl implements WorkerBiz { @Override public void list() { System.out.println("查询员工(用户)信息"); } }
package com.wh.web; import com.wh.biz.WorkerBiz; /** * @author 王辉 * @site www.shihuihuila.com * @create 2023-08-15 16:38 */ public class FinanceAction {//财务 private WorkerBiz workerBiz = new WokerBizImpl(); public void list() {//调用业务逻辑层查询的方法 workerBiz.list(); } }
package com.wh.web; import com.wh.biz.WorkerBiz; /** * @author 王辉 * @site www.shihuihuila.com * @create 2023-08-15 16:38 */ public class HRAction {//人事 private WorkerBiz workerBiz = new WokerBizImpl(); public void list() {//调用业务逻辑层查询的方法 workerBiz.list(); } }
结果
但是客户那边商量之后,突然间又换了一个需求
需求2: 同时在人事模块,财务模块拿到所有的用户数据,并且要求人事模块中的用户数据是通过年龄排序的 对应策略:修改biz中list方法,添加年龄排序功能
package com.wh.biz.impl; import com.wh.biz.WorkerBiz; /** * @author 王辉 * @site www.shihuihuila.com * @create 2023-08-15 16:35 */ public class WokerBizImpl1 implements WorkerBiz { @Override public void list() { System.out.println("查询员工(用户),按照年龄来排序..."); } }
package com.wh.web; import com.wh.biz.WorkerBiz; /** * @author 王辉 * @site www.shihuihuila.com * @create 2023-08-15 16:38 */ public class HRAction {//人事 private WorkerBiz workerBiz = new WokerBizImpl1(); public void list() {//调用业务逻辑层查询的方法 workerBiz.list(); } }
package com.wh.web; import com.wh.biz.WorkerBiz; /** * @author 王辉 * @site www.shihuihuila.com * @create 2023-08-15 16:38 */ public class FinanceAction {//财务 private WorkerBiz workerBiz = new WokerBizImpl(); public void list() {//调用业务逻辑层查询的方法 workerBiz.list(); } }
结果
客户那边思来想去,认为财务模块中的数据也需要另作要求
需求3: 同时在人事模块,财务模块拿到所有的用户数据,并且要求人事模块中的用户数据是通过年龄排序的,财务模块中的用户数据是通过薪资排序的 对应策略,修改biz中list方法,添加排薪资排序功能
package com.wh.biz.impl; import com.wh.biz.WorkerBiz; /** * @author 王辉 * @site www.shihuihuila.com * @create 2023-08-15 16:35 */ public class WokerBizImpl1 implements WorkerBiz { @Override public void list() { System.out.println("查询员工(用户),按照年龄来排序..."); } }
package com.wh.biz.impl; import com.wh.biz.WorkerBiz; /** * @author 王辉 * @site www.shihuihuila.com * @create 2023-08-15 16:35 */ public class WokerBizImpl2 implements WorkerBiz { @Override public void list() { System.out.println("查询员工(用户),按照薪资排序..."); } }
package com.wh.web; import com.wh.biz.WorkerBiz; /** * @author 王辉 * @site www.shihuihuila.com * @create 2023-08-15 16:38 */ public class HRAction {//人事 private WorkerBiz workerBiz = new WokerBizImpl1(); public void list() {//调用业务逻辑层查询的方法 workerBiz.list(); } }
package com.wh.web; import com.wh.biz.WorkerBiz; /** * @author 王辉 * @site www.shihuihuila.com * @create 2023-08-15 16:38 */ public class FinanceAction {//财务 private WorkerBiz workerBiz = new WokerBizImpl2(); public void list() {//调用业务逻辑层查询的方法 workerBiz.list(); } }
结果
相信聪明的你也应该发现问题了吧,当客户需求不断变更的时候我们就需要不断的修改代码,我这里只用了两个Action来展示,大家可能觉得不过如此,不就只需要增加几个不同功能的impl类,然后将所实例化的那行代码中的impl类进行改动嘛。但是我们要想,员工/用户的信息在一般情况下,在很多的地方都需要用到,那要是有200个web中都用到了用户的信息,那不是要修改200次? 要是200个中有一百个是按照年龄排序的,另外一百个是按照薪资排序的,那不是还得一个个看仔细了之后修改? 可见,这样的方式非常的费时间,不易维护(提出新需求,没方法快速修改)
前面我们已经说到了在IOC的思想下,对象的创建和依赖关系的管理被转移给一个外部容器
那我们就来看一下ioc到底是怎么进行这一波骚操作的吧
控制反转:
使用步骤
1 创建Maven的war项目然后配置web的相关依赖以及项目结构的配置
不会使用IDEA创建Maven项目的看这个
不会使用Eclipse创建Maven的项目的看这个
2在pom.xml文件中配置Spring的依赖
4.0.0 com.javaxl T224_spring war 0.0.1-SNAPSHOT T224_spring Maven Webapp http://maven.apache.org 5.0.1.RELEASE 4.0.0 4.12 junit junit 3.8.1 test org.springframework spring-context ${spring.version} org.springframework spring-aspects ${spring.version} junit junit ${junit.version} test javax.servlet javax.servlet-api ${javax.servlet.version} provided T224_spring org.apache.maven.plugins maven-compiler-plugin 3.7.0 1.8 UTF-8
3 在resources下创建并配置spring-context.xml
4 在业务层中创建WorkBiz接口及其实现类package com.wh.biz.impl; import com.wh.biz.WorkerBiz; /** * @author 王辉 * @site www.shihuihuila.com * @create 2023-08-15 16:35 */ public class WokerBizImpl implements WorkerBiz { @Override public void list() { System.out.println("查询员工(用户)信息"); } }
package com.wh.biz.impl; import com.wh.biz.WorkerBiz; /** * @author 王辉 * @site www.shihuihuila.com * @create 2023-08-15 16:35 */ public class WokerBizImpl1 implements WorkerBiz { @Override public void list() { System.out.println("查询员工(用户),按照年龄来排序..."); } }
package com.wh.biz.impl; import com.wh.biz.WorkerBiz; /** * @author 王辉 * @site www.shihuihuila.com * @create 2023-08-15 16:35 */ public class WokerBizImpl2 implements WorkerBiz { @Override public void list() { System.out.println("查询员工(用户),按照薪资排序..."); } }
5 在项目中创建MVC的包结构,并创建Web层,并获取Spring的容器对象
package com.wh.web; import com.wh.biz.WorkerBiz; /** * @author 王辉 * @site www.shihuihuila.com * @create 2023-08-15 16:38 */ public class HRAction {/人事 // private WorkerBiz workerBiz = new WokerBizImpl1(); private WorkerBiz workerBiz;//实例化业务逻辑层 public void list() { workerBiz.list(); }//调用业务逻辑层查询的方法 public WorkerBiz getWorkerBiz() {//workerBiz的get方法 return workerBiz; } public void setWorkerBiz(WorkerBiz workerBiz) {//workerBiz的get方法 this.workerBiz = workerBiz; } }
package com.wh.web; import com.wh.biz.WorkerBiz; /** * @author 王辉 * @site www.shihuihuila.com * @create 2023-08-15 16:38 */ public class FinanceAction {//财务 // private WorkerBiz workerBiz = new WokerBizImpl1(); private WorkerBiz workerBiz;//实例化业务逻辑层 public void list() {//调用业务逻辑层查询的方法 workerBiz.list(); } public WorkerBiz getWorkerBiz() {//workerBiz的get方法 return workerBiz; } public void setWorkerBiz(WorkerBiz workerBiz) {//workerBiz的get方法 this.workerBiz = workerBiz; } }
6 测试
package com.wh.ioc; import com.wh.web.HRAction; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @author 王辉 * @site www.shihuihuila.com * @create 2023-08-16 18:46 */ public class IOCTest { @SuppressWarnings("resource") public static void main(String[] args) { //建模 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/spring-context.xml"); HRAction hrAction = (HRAction) context.getBean("hrAction"); hrAction.list(); } }
package com.wh.ioc; import com.wh.web.FinanceAction; import com.wh.web.HRAction; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @author 王辉 * @site www.shihuihuila.com * @create 2023-08-16 18:46 */ public class IOCTest { @SuppressWarnings("resource") public static void main(String[] args) { //建模 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/spring-context.xml"); HRAction hrAction = (HRAction) context.getBean("hrAction"); hrAction.list(); FinanceAction financeAction = (FinanceAction) context.getBean("financeAction"); financeAction.list(); } }
7 总结
需要什么功能,或是说需要修改,只需要在spring-context中进行配置/修改便可(web层中进行相应的封装便可)
原来的代码进行修改或增加功能,都需要手动的进行查找,先将修改功能的模块写好,在去寻找需要修改功能的Action,一个一个的手动修改,可以说是十分的繁琐。但是我们使用IOC的方式,就只需要修改配置文件,这样一对比,是不是就能够非常直观的感受到使用IOC的好处了!!
依赖注入(Dependency Injection,DI):通过DI,容器在创建对象时,自动将依赖对象注入到对象中。依赖注入可以通过构造函数、属性注入或接口注入等方式进行。
依赖查找(Dependency Lookup):通过依赖查找,对象使用容器提供的查找机制,主动获取所需的依赖对象
可以看到ioc的实现方式主要有两种,那么我们今天就来探究一下其中的依赖注入!
1.Setter方法注入(Setter Injection):
通过在目标对象中定义对应的setter方法,从而实现对依赖对象的注入。依赖对象通过调用setter方法设置给目标对象
顾名思义就是需要提供set方法,那如果我没有提供set方法呢?我们可以试一下将action中的set方法给注释掉
可以看到报出了一个错误,意思是在其中没有set方法
package com.wh.web; import com.wh.biz.WorkerBiz; import java.util.List; /** * @author 王辉 * @site www.shihuihuila.com * @create 2023-08-15 16:38 */ public class FinanceAction { // private WorkerBiz workerBiz = new WokerBizImpl1(); private WorkerBiz workerBiz;//实例化业务逻辑层 public void list() {//调用业务逻辑层查询的方法 System.out.println(name); System.out.println(age); System.out.println(hobby); workerBiz.list(); } public WorkerBiz getWorkerBiz() {//workerBiz的get方法 return workerBiz; } public void setWorkerBiz(WorkerBiz workerBiz) {//workerBiz的set方法 this.workerBiz = workerBiz; } private String name; private int age; private List
hobby; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public List getHobby() { return hobby; } public void setHobby(List hobby) { this.hobby = hobby; } }
唱 跳 RAP 2.构造函数注入(Constructor Injection):
通过在目标对象的构造函数中定义参数,从而实现对依赖对象的注入。依赖对象在创建目标对象时通过构造函数传递进来
package com.wh.web; import com.wh.biz.WorkerBiz; import java.util.List; /** * @author 王辉 * @site www.shihuihuila.com * @create 2023-08-15 16:38 */ public class FinanceAction { // private WorkerBiz workerBiz = new WokerBizImpl1(); private WorkerBiz workerBiz;//实例化业务逻辑层 public void list() {//调用业务逻辑层查询的方法 System.out.println(name); System.out.println(age); System.out.println(hobby); workerBiz.list(); } private String name; private int age; private List
hobby; public FinanceAction() {//空参构造 } public FinanceAction(String name, int age, List hobby) {//有参构造 this.name = name; this.age = age; this.hobby = hobby; } }
唱 跳 RAP 结果
3.接口注入(Interface Injection):
通过在目标对象中定义一个接口,并在接口中定义一个设置依赖对象的方法,从而实现对依赖对象的注入。目标对象实现该接口并实现依赖对象的设置方法
注意:
autowire="xx" (其中填的是byName/byType)
byName:是通过spring管理的bean对象的ID进行查找,如果找不到,则注入失败,反之成功
package com.wh.web; import com.wh.biz.WorkerBiz; import java.util.List; /** * @author 王辉 * @site www.shihuihuila.com * @create 2023-08-15 16:38 */ public class FinanceAction { // private WorkerBiz workerBiz = new WokerBizImpl1(); private WorkerBiz workerBiz;//实例化业务逻辑层 public void list() {//调用业务逻辑层查询的方法 workerBiz.list(); } public WorkerBiz getWorkerBiz() {//workerBiz的get方法 return workerBiz; } public void setWorkerBiz(WorkerBiz workerBiz) {//workerBiz的get方法 this.workerBiz = workerBiz; } }
结果
byType:
是通过spring管理的bean对象的接口实现类进行查找,如果没有或者2个以上,则注入失败,反之成功
但是在使用byType时,同一类型的对象,在spring容器中必须唯一。如果不唯一,会报不唯一的异常
package com.wh.web; import com.wh.biz.WorkerBiz; import java.util.List; /** * @author 王辉 * @site www.shihuihuila.com * @create 2023-08-15 16:38 */ public class FinanceAction { // private WorkerBiz workerBiz = new WokerBizImpl1(); private WorkerBiz workerBiz;//实例化业务逻辑层 public void list() {//调用业务逻辑层查询的方法 workerBiz.list(); } public WorkerBiz getWorkerBiz() {//workerBiz的get方法 return workerBiz; } public void setWorkerBiz(WorkerBiz workerBiz) {//workerBiz的get方法 this.workerBiz = workerBiz; } }
结果
Q:为什么需要进行这一步操作?
A: 建模的过程是十分耗时的
解决问题的思路:
1.建模必不可少
2.保证建模只执行一次
3.建模后期望在每一个servlet都能够拿到spring的上下文对象
Q:怎么处理?A:
1.监听器的初始化方法 只执行一次
package com.wh.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.shihuihuila.com * @create 2023-08-16 18:37 */ @WebListener public class Listener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { System.out.println("初始化执行"); ServletContext servletContext = sce.getServletContext(); String springConfigLocation = servletContext.getInitParameter("springConfigLocation"); System.out.println(springConfigLocation+"..."); //拿到spring上下文 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/spring-context.xml"); //将spring的上下文保存在Tomcat上下文中 servletContext.setAttribute("springContext", context); } }
2.spring的上下文要存放在Tomcat上下文中
package com.wh.ioc; import com.wh.web.FinanceAction; 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; /** * spring与web容器的整合原理 * why:建模的过程是十分耗时的 * 解决问题: * 1.建模必不可少 * 2.建模只保障只执行一次 * 3.建模后期望在每一个servlet都能够拿到spring的上下文对象ClassPathXmlApplicationContext * how: * 1.监听器的初始化方法 只执行一次 * 2.spring的上下文要存放在Tomcat上下文中 * @author 王辉 * @site www.shihuihuila.com * @create 2023-08-16 19:37 * */ @WebServlet("/springDemo") public class DemoServlet 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 { //ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/spring-context.xml"); ClassPathXmlApplicationContext springcontext = (ClassPathXmlApplicationContext) req.getServletContext().getAttribute("springContext"); FinanceAction financeAction = (FinanceAction) springcontext.getBean("financeAction"); financeAction.list(); } }
运行即可
好啦,今天的分享就到这了,希望能够帮到你呢!