Spring容器与依赖注入(DI)

news/2024/5/19 2:06:31/文章来源:https://blog.csdn.net/qq_55917018/article/details/127066098

1 Spring框架简介

1.1 什么是Spring

        Spring框架是一个开源的轻量级的DI和AOP容器框架,致力于简化企业级应用开发,让开发者使用简单的Java Bean来实现从前只有EJB才能实现的功能。

1.2 为什么要使用Spring

        Spring堪称Java世界中最强大的框架,其亮点非常的多,主要体现在以下几个方面。

(1)使用Spring可以实现DI(依赖注入)。实现面向接口编程,以解决项目开发中组件间的解耦问题,让项目模块得以独立测试、灵活扩展和替换。

(2)使用Spring可以实现AOP(面向切面)。AOP可以在无需修改原有类源代码的情况下为它们切入增强功能。

(3)使用Spring可以实现声明式事务管理,无需在项目中写死事务处理边界,具有更高灵活性。

(4)Spring可与大部分的Java开源框架(如Hibernate、MyBatis、Struts2等)进行整合,并进一步简化这些框架的编码。

(5)Spring可以实现分布式远程调用、消息队列、安全验证等诸多大型应用所需的复杂功能,可以大大简化企业级系统的开发。在Spring出现之前,这些功能一般开发者都难以解决,只能依赖于大型厂商(如IBM、Oracle、SAP等)提供的昂贵的EJB容器;但现在,开源世界的Spring都可以做到,而且更为灵活和轻盈。

2 面向接口编程与容器框架

2.1 面向接口编程

Spring首先是一个容器框架,用于管理系统中的JavaBean。那么我们为何需要一个容器框架呢,这是由Java世界推崇的面向接口编程所决定的。

JavaEE平台的其中一个特点是倡导面向接口编程,JavaEE本身就是由SUN提出的各种规范和接口构成的。例如,JSP技术中的Servlet、Filter、Listener、ServletRequest、ServletResponse、HttpSession等对象统统都是接口。

为什么要面向接口编程呢,面向接口,可以降低组件与组件之间的依赖,实现弱耦合,被依赖组件随时可以被替代。例如Tomcat服务器,不过是一组JSP/Servlet接口的实现容器,我们完全可以用其它实现同样接口的容器(如Jetty)来替代它。此外,面向接口编程也使得组件的独立开发与测试提供了可能,否则开发上层模块的开发者就需要等待下层模块完成才能开工,各个模块无法并行开发。

虽然面向接口编程的想法不错,但使用时却要解决一个核心问题——具体对象从何而来?

参考如下代码:“CategoryDao”是一个接口,而“CategoryDaoImpl”是它的实现类,获取对象的常规方式是使用“new”调用实现类的构造方法。如果我们用这种方式来构建具体使用对象,就谈不上面向接口编程了,因为具体实现类已被写死在调用代码中了。

CategoryDao categoryDao = new CategoryDaoImpl();
categoryDao.save(categoryName);

2.2 工厂模式

在传统的面向对象编程中,对象是调用者创建(new)出来的,调用者和被调用者产生了强耦合,而工厂模式在可以在调用者中隐藏具体类型,解决这一问题。

参考如下代码:“ObjectFactory”是对象工厂,可以根据不同的DAO名称获取对应的DAO实现类对象。具体可以使用Java反射技术与XML配置来实现。

CategoryDao categoryDao = (CategoryDao)ObjectFactory.getInstance("categoryDao");
categoryDao.save(categoryName);

2.3 使用Spring充当Bean容器

        Spring框架首先实现了上述的“工厂模式”功能,它就是一个bean(对象)工厂,我们称为bean容器。我们可以把系统需要用到的所有功能对象通过配置的方式放入到Spring容器中,然后在需要使用时从Spring获取。

        当然,Spring远不止这么简单,它更进一步的实现了我们称为“依赖注入”的对象获取方式,我们将在下文讨论。

3 通过Spring容器配置并获取对象

        下面我们正式体验Spring框架的对象管理功能。

(1)获取并添加Spring框架的依赖

使用Spring前,我们需要浏览一下Spring的官方站点,上面有官方文档和相关Maven坐标的描述。

Spring Framework

Spring框架有众多部件,根据官方文档,我们可以通过以下maven坐标得到Spring框架的核心支持(spring-context)。

<!-- Spring DI容器 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>4.2.5.RELEASE</version></dependency>

(2)在“类路径”下加Spring的bean配置文件“applicationContext.xml”,并配置需要Spring管理的类对象。

<?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"><bean id="categoryDao" class="demo.dao.impl.CategoryDaoImpl" />……
</beans>  

注意,所谓“类路径”,指的是Eclipse Web项目中的“src目录”或者Maven项目中的“src/main/resources”路径。

(3)创建Spring容器(工厂),并通过bean的名称获取bean对象

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");CategoryDao categoryDao = (CategoryDao)ctx.getBean("categoryDao");categoryDao.save("科幻");

 

4 使用Spring实现依赖注入

        所谓依赖注入DI(Dependency Injection),一些文献也称之控制反转IOC(Inversion of Control):是一种松耦合的开发模式,指对象是被动地接收它的依赖类对象,而非自己主动去查找或创建。在开发中A类依赖于B类(如业务对象依赖于数据访问对象),往往是A类中直接代码创建B类对象使用(或使用JNDI查找B类对象)。而在依赖注入中,A类中的B对象不由A自身创建,而是由容器C在实例化A类对象时主动将A所依赖的B对象注入给它。

        通过bean元素的property子元素,可以通过bean对象的属性实现依赖注入。        property子元素中,name属性用于声明属性名,ref属性用于引用已声明的复杂类型bean对象,value属性用于指定普通类型常量值。

<bean id="userBiz" class="com.demo.biz.impl.UserBizImpl"><property name="userDao" ref="userDao" />
</bean>

5 Bean的作用域。

        Spring默认使用单例模式管理bean对象,也就是说对于同一个类Spring中只保留一个实例,我们多次通过Spring的“getBean()”获取的是相同的一个实例。而一些实际的场合(单例模式,适用于无状态Bean,不适用于有状态Bean),单例模式不适用,这时我们可以通过bean的scope属性来改变Bean的作用域。

通过bean元素的scope属性,可以指定Bean对象在Spring容器中的作用域。其取值如下表所示。

scope属性取值

含义

singleton

默认值,Spring容器中对该bean做单例模式处理,对所有id与该bean定义匹配的bean请求,Spring只会返回bean的同一实例。

prototype

每一次请求都会产生一个新的bean实例,相当与一个new的操作,对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。

request

request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效。

session

‍session作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效。

global session

‍global session作用域类似于标准的HTTP Session作用域,不过它仅仅在基于portlet的web应用中才有意义。

示例:

<bean id="userDao" class="com.demo.dao.impl.UserDaoImpl" scope="prototype" />    

注意:若配置为request、session、global session时,若使用的是Servlet 2.4及以上的web容器,那么需要在web应用的XML声明文件web.xml中增加下述ContextListener声明:

<listener><listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>

6 Web环境中启动Spring容器

        在Web环境中,应用程序是由Web服务器启动的,Spring要作为对象容器(对象工厂)为各层提供依赖注入功能,就必须在Web服务器启动时创建Spring实例,并在整个应用程序生命周期中保持唯一。这时,我们就不能在main函数中随便创建ApplicationContext()对象了,因为Web应用程序并不是由main函数启动的。

        针对这个问题,Spring提供了Web服务器的监听程序,使用监听器监听Web应用程序的启动事件,并在事件处理函数中创建Spring实例并使用单例模式缓存起来(存放到Web应用程序上下文中,即ServletContext类型的application对象)。这样在Web程序的任意地方,就可以获取到唯一的Spring实例并实现依赖注入了。

        下面介绍在Web环境中使用Spring的注意事项:

(1)在项目种添加Spring Web依赖

<!-- Spring容器 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>4.2.5.RELEASE</version></dependency><!-- Spring Web --><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>4.2.5.RELEASE</version></dependency>

(2)配置web.xml,设置Spring Web监听器,在Web应用启动时创建并缓存Spring容器

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">	<!-- 启动Spring容器的监听器 --><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext.xml</param-value></context-param>
</web-app>

(3)在Servlet/JSP等请求处理器中获取Spring容器和它所管理的Bean

        在请求上下文中,可以通过以下方法获取Spring容器

WebApplicationContextUtils.getRequiredWebApplicationContext(ServletContext object)

下面是Servlet中使用Spring容器的示例

@WebServlet("/admin/category-list")
public class CategoryListServlet extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//获取Spring容器ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(this.getServletContext());//获取Spring管理的bean对象CategoryBiz categoryBiz = (CategoryBiz)ctx.getBean("categoryBiz");//执行请求处理request.setAttribute("categories", categoryBiz.getAll());request.getRequestDispatcher("/admin/category-list.jsp").forward(request, response);}
}

7 Spring DI的其它用法

7.1 构造方法(构造器)注入

        通过bean元素的constructor-arg子元素,可以通过bean对象的构造方法实现依赖注入。

        在constructor-arg子元素中,index用于指定参数的索引,name用于指定参数名,ref用于引用已声明的bean对象,value用于指定普通类型常量值。

<bean id="userBiz2" class="com.demo.biz.impl.UserBizImpl2"><constructor-arg index="0" ref="userDao" />
</bean>

7.2  三种实例化bean的方式

(1)使用类构造方法实例化

<bean id="userDao" class="com.demo.dao.impl.UserDaoImpl"></bean>

(2)使用静态工厂方法实例化

        首先定义静态工厂方法。

public static UserDao getInstance(){System.out.println("执行了静态工厂方法。");return new UserDaoImpl();}

然后配置,通过静态工厂实例化bean。

<bean id="userDao" class="com.demo.dao.impl.UserDaoFactory" factory-method="getInstance" />

(3)使用实例工厂方法实例化

        首先定义实例工厂方法。

public UserDao createInstance(){System.out.println("执行了对象工厂方法。");return new UserDaoImpl();}

然后配置,通过实例(对象)工厂实例化bean

<bean id="userDaoFactory" class="com.demo.dao.impl.UserDaoFactory" />
<bean id="userDao" factory-bean="userDaoFactory" factory-method="createInstance" />

7.3 Bean的生命周期管理

        在实例化bean时,有时有必要执行一些初始化代码来使它处于可用状态,或者在丢弃bean时需要执行一些清理工作。Spring为这种需求提供了初始化方法init-method和销毁方法destory-method配置,使得bean对象的生命周期管理更为细致。

public class UserDaoImpl implements UserDao {public void init(){System.out.println("执行了UserDao的初始化方法");}public void save() {System.out.println("执行UserDao,用户信息保存成功。");}public void destory(){System.out.println("执行了UserDao的销毁化方法");}
}

通过配置即可在适当时机调用初始化和销毁方法。

<bean id="userDao" class="com.demo.dao.impl.UserDaoImpl" init-method="init" destroy-method="destory" />

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_203646.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

单调栈题目:柱状图中最大的矩形

文章目录题目标题和出处难度题目描述要求示例数据范围解法思路和算法代码复杂度分析题目 标题和出处 标题&#xff1a;柱状图中最大的矩形 出处&#xff1a;84. 柱状图中最大的矩形 难度 7 级 题目描述 要求 给定整数数组 heights\texttt{heights}heights 表示柱状图中…

正弦信号发生器的设计

目 录 1 引言 1 2 总体结构设计 2 2.1 单片机概述 2 2.1.1 单片机的发展 2 2.1.2 单片机的用途 3 2.2 系统设计的功能 3 2.3 波形发生和输出频率的方法 4 2.3.1 波形发生的方法 4 2.3.2 输出频率的方法 4 3 系统硬件设计 5 3.1 硬件电路芯片的选择 5 3.1.1 CPU芯片 AT89C51 5 3…

MyBatis中的复杂映射

上一章中实现的MyBatis对象映射较为简单&#xff0c;对象中的属性和数据库中的表字段是一一对应的&#xff08;无论数量和名称都完全一样&#xff09;&#xff0c;如果对象中的属性名和表中的字段名不一致怎么办&#xff1f;又或者Java对象中存在复杂类型属性&#xff08;即类似…

百分点数据科学产教融合计划继续扩大招募

从全球发展来看&#xff0c;数字经济已经成为重组全球要素资源、重塑全球经济结构、改变全球竞争格局的关键力量&#xff0c;是全球共同的发展战略。作为新经济中的数据科学&#xff0c;伴随社会各领域对数字人才需求的与日俱增&#xff0c;也成为了这一波科技革命中的人才竞争…

中国新出海故事:人、疫情与纽带

【潮汐商业评论/原创】 《枪炮、病菌与钢铁》中对人类社会发展的洞察与新千禧年发生了奇妙的呼应&#xff0c;战争、疫情成为了这十年的历史注脚&#xff0c;但时代的车轮总是滚滚向前的&#xff0c;新的世界版图里&#xff0c;全球化、数字化的浪潮构成了新世界跳动的脉搏&am…

第2章 ROS 通信机制 4 —— 常用命令

文章目录1 应用场景2 rosnode 功能包 plumbing_pub_sub编译执行3 rostopic 功能包 plumbing_pub_sub编译执行4 rosservice (服务通信) 功能包 plumbing_server_client编译执行5 rosmsg (话题通信) 功能包 plumbing_pub_sub编译执行6 rossrv (服务通信) 功能包 plumbing_server_…

常见网络知识面试题总结

&#x1f353;个人主页&#xff1a;个人主页 &#x1f352;系列专栏&#xff1a;C/C基础与进阶 &#x1f4ac;推荐一款模拟面试、刷题神器&#xff0c;从基础到大厂面试题&#x1f449;点击跳转刷题网站进行注册学习 目录 1、OSI七层模型与TCPIP四层模型是什么&#xff1f; 2…

核爆!字节跳动算法大佬手写1000页数据算法笔记:Github已标星79k

数据结构是什么 数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。通常情况下&#xff0c;精心选择的数据结构可以带来更高的运行或者存储效率。数据结构往往同高效的检索算法和索引技术有关。 算法是什么 算法是对解题方案…

PC 端网页特效

一、元素偏移量 offset 系列 (一)offset 概述 1、offset 翻译过来就是偏移量,我们使用 offset 系列相关属性可以动态的得到该元素的位置(偏移)、大小等。 (1)获得元素距离带有定位父元素的位置; (2)获得元素自身的大小(宽度高度); (3)注意:返回的数值都不带单位…

使用polkadot.js在substrate frontier上安装ERC20token合约

使用polkadot.js在substrate frontier上安装ERC20token合约参考资料Substrate Frontier Node Template github.com/substrate-developer-hub/frontier-node-template frontier-node-template/examples/contract-erc20/truffle/contracts/MyToken.json安装ERC20 token合约 sourc…

SwiftUI AR教程之应用程序中使用 RealityKit 生成 3D 文本(教程含完整源码)

项目文件 基本设置 我们将从 Xcode 上的“增强现实应用程序”模板开始: 我使用 SwiftUI 作为界面,使用 Swift 作为语言,使用 RealityKit 作为内容技术: 您现在应该拥有基本的增强现实应用程序模板代码。 使用 RealityKit 生成 3D 文本网格 我们将向我们的项目添加一个函…

快速入门SSMS的使用

快速入门SSMS的使用1.Install SSMS2.Demo2.1 Export DDL2.2 XXXXX3.XXXX4.Waken1.Install SSMS 官方地址 SSMS Website: https://learn.microsoft.com/zh-tw/docs/. 也可以直接下载 Download Website: https://aka.ms/ssmsfullsetup.双击安装 要有电脑的管理员权限 快速启动…

springboot基于JAVA游戏周边商城设计与实现毕业设计源码261622

Springboot游戏周边商城的开发 摘 要 现今人们的生活方式逐渐丰富&#xff0c;电脑和网络已经融入了人们生活中的滴滴点点&#xff0c;无时不刻的影响着我们的日常生活&#xff0c;网络游戏已经进入到了大多数人的生活之中。在游戏的世界中人们会得到很多游戏商品&#xff0c;然…

死锁检测组件原理及代码实现

一、引言 所谓死锁&#xff0c;是指多个线程或进程各自持有某些资源&#xff0c;同时又等待着别的线程或进程释放它们现在所保持的资源&#xff0c;否则就不能向前推进。如下图&#xff1a;线程各自占有一把锁&#xff0c;还需要申请别的线程当前持有的锁&#xff0c;形成锁资…

Cisco简单配置(十四)—第一跳冗余协议—HSRP

为什么使用第一跳冗余 默认网关限制 如果路由器或路由器接口&#xff08;作为默认网关&#xff09;发生故障&#xff0c;配置该默认网关的主机将与外部网络隔离。在交换网络中&#xff0c;每个客户端仅收到一个默认网关。即使存在第二个路由可以从本地网段传输数据包&#xf…

微信小程序 java高校新生报到宿舍安排管理系统python php

将小程序权限按管理员和用户这两类涉及用户划分。 (a) 管理员&#xff1b;管理员使用本程序涉到的功能主要有&#xff1a;个人中心、宿舍管理、学生管理、宿舍安排管理、缴费信息管理、程序管理等功能 (b)用户进入程序前台可以实现首页、互助沟通、我的等功能 uni-app框架&…

基于java校园志愿者管理系统(java毕业设计)

基于java校园志愿者管理系统 校园志愿者系统是基于java编程语言&#xff0c;mysql数据库&#xff0c;springboot框架&#xff0c;idea开发工具进行开发&#xff0c;本系统主要分为志愿者和管理员两个角色&#xff0c;其中志愿者的主要功能是查看系统公告&#xff0c;活动信息&…

红队工具合集,安全er值得拥有

背景 圈内很多师傅一直在做红队安全工具箱,用于在hvv、渗透等工作中提升工作效率。依照ATT&CK威胁图谱的指导,我们很容易整理出常用的红队工具合集,在这里为大家展示。 工具介绍 信息搜集 信息搜集一直是渗透测试工作开展的重中之重,找到无人关注的老旧应用,先对…

leetcode 617. Merge Two Binary Trees 合并二叉树(简单)

直接用递归调用给定函数,先判断如果root1为空返回root2,如果root2为空返回root1,都存在的情况下建立新节点node,然后对root1和root2的左子节点调用递归并赋给node的左子节点,再对root1和root2的右子节点调用递归并赋给node的右子节点,返回node即可。一、题目大意 给你两棵…

虚拟机安装

ubuntu 虚拟机安装配置&#xff0c;以 18.04 为例 一、安装步骤 > 安装 vmware wmware 下载地址 &#xff1a; download 点击进入下载界面 点击并下载 windows 平台下的安装包 安装时直接一键下一步即可&#xff0c;也可根据自己需求勾选&#xff0c;最后的注册码可以自行…