什么是spring框架?spring框架到底有什么用?
ccwgpt 2024-09-14 00:10 36 浏览 0 评论
什么是spring框架,spring框架究竟有什么用呢?我们可以用spring框架来做些什么呢?这是我今天要说的内容。
当然,百度spring框架会出现一大堆spring框架的介绍,以及IOC和AOP。但是这些官方的语言,看书都有解释,关键是我不知道为什么要用spring,spring框架和不用框架到底区别在哪,还有它到底是通过什么来表明我用的框架就是spring框架的?
spring很抽象,spring是框架,框架的主要目的是什么呢?大概所有框架的目的都一样吧,那就是简化开发。而它存在的目的也是为了简化java开发。
它是怎样来简化开发的呢?让我们看看spring采取的关键策略。
基于POJO的轻量级和最小侵入性编程;
通过依赖注入和面向接口实现松耦合;
基于切面和惯例进行声明式编程;
通过切面和模板减少样板式代码。
这就是spring框架的四种关键策略。我们下面详细谈谈。
spring框架的最小侵入性
Spring竭力避免因自身的API而弄乱你的应用代码。 Spring不会强迫你实现Spring规范的接口或继承Spring规范的类, 相反, 在基于Spring构建的应用中, 它的类通常没有任何痕迹表明你使用了Spring。只能通过xml配置文件来看出spring的思想。
最坏的场景是, 一个类或许会使用Spring注解, 但它依旧是POJO。
那可能有人要问了,不侵入如何实现spring框架强大的功能,spring框架不是很强大吗?在这里我要说明,spring框架是很强大,但它的强大在于它的理念,它的思想,而不是它实现了多强大的功能。
当然不侵入有不侵入的解决方法,在我的理解里它的解决方法也算是spring的核心吧!那就是配置文件或者注解。
让我们来看一个javabean。它是一个普通的java类。
public class exampleBean(){
public String testPrint(){
System.out.println("===test===");
}
}
Spring的非入侵式就是不强制类要实现Spring的任何接口或类,没有任何地方表明它是一个Spring组件。 意味着这个类在Spring应用和非Spring应用中都可以发挥同样的作用。
那这个类在不耦合的情况下是如何发挥作用的呢?这就要提到spring框架的DI(依赖注入)了。
依赖注入
任何一个有实际意义的应用都会由两个或者更多的类组成, 这些类相互之间进行协作来完成特定的业务逻辑。 按照传统的做法, 每个对象负责管理与自己相互协作的对象(即它所依赖的对象) 的引用, 这将会导致高度耦合和难以测试的代码。而spring框架利用依赖注入恰恰解决了这一难题。
耦合具有两面性 。 一方面, 紧密耦合的代码难以测试、 难以复用、 难以理解, 并且典型地表现出“打地鼠”式的bug特性 。 另一方面, 一定程度的耦合又是必须的——完全没有耦合的代码什么也做不了。 为了完成有实际意义的功能, 不同的类必须以适当的方式进行交互。 总而言之, 耦合是必须的, 但应当被小心谨慎地管理。
public void DealData(){
public Data data;
public void setData(Data data){
this.data=data;
}
public void add(){
data.add();
}
}
通过DI, 对象的依赖关系将由系统中负责协调各对象的第三方组件在创建对象的时候进行设定。 对象无需自行创建或管理它们的依赖关系。
应用切面
DI能够让相互协作的软件组件保持松散耦合, 而面向切面编程(aspect-oriented programming, AOP) 允许你把遍布应用各处的功能分离出来形成可重用的组件。
面向切面编程往往被定义为促使软件系统实现关注点的分离一项技术。 系统由许多不同的组件组成, 每一个组件各负责一块特定功能。 除了实现自身核心的功能之外, 这些组件还经常承担着额外的职责。 诸如日志、 事务管理和安全这样的系统服务经常融入到自身具有核心业务逻辑的组件中去, 这些系统服务通常被称为横切关注点, 因为它们会跨越系统的多个组件。
如果将这些关注点分散到多个组件中去, 你的代码将会带来双重的复杂性。
实现系统关注点功能的代码将会重复出现在多个组件中。 这意味着如果你要改变这些关注点的逻辑, 必须修改各个模块中的相关实现。
即使你把这些关注点抽象为一个独立的模块, 其他模块只是调用它的方法, 但方法的调用还是会重复出现在各个模块中。
组件会因为那些与自身核心业务无关的代码而变得混乱。 一个向地址簿增加地址条目的方法应该只关注如何添加地址, 而不应该关注它是不是安全的或者是否需要支持事务
图1.2展示了这种复杂性。 左边的业务对象与系统级服务结合得过于紧密。 每个对象不但要知道它需要记日志、 进行安全控制和参与事务, 还要亲自执行这些服务。
在整个系统内, 关注点(例如日志和安全)的调用经常散布到各个模块中, 而这些关注点并不是模块的核心业务
AOP能够使这些服务模块化, 并以声明的方式将它们应用到它们需要影响的组件中去。 所造成的结果就是这些组件会具有更高的内聚性并且会更加关注自身的业务, 完全不需要了解涉及系统服务所带来复杂性。 总之, AOP能够确保POJO的简单性。
如图1.3所示, 我们可以把切面想象为覆盖在很多组件之上的一个外壳。 应用是由那些实现各自业务功能的模块组成的。 借助AOP, 可以使用各种功能层去包裹核心业务层。 这些层以声明的方式灵活地应用到系统中, 你的核心应用甚至根本不知道它们的存在。 这是一个非常强大的理念, 可以将安全、 事务和日志关注点与核心业务逻辑相分离。
利用AOP, 系统范围内的关注点覆盖在它们所影响组件之上
为了示范在Spring中如何应用切面, 让我们重新回到骑士的例子, 并为它添加一个切面。
每一个人都熟知骑士所做的任何事情, 这是因为吟游诗人用诗歌记载了骑士的事迹并将其进行传唱。 假设我们需要使用吟游诗人这个服务类来记载骑士的所有事迹。 程序清单1.9展示了我们会使用的Minstrel类。
package sia.knights;
import java.io.PrintStream;
public class Minstrel {
private PrintStream stream;
public Minstrel(PrintStream stream) {
this.stream = stream;
}
public void singBeforeQuest() {
stream.println("Fa la la, the knight is so brave!");
}
public void singAfterQuest() {
stream.println("Tee hee hee, the brave knight " +
"did embark on a quest!");
}
}
正如你所看到的那样, Minstrel是只有两个方法的简单类。 在骑士执行每一个探险任务之前, singBeforeQuest()方法会被调用; 在骑士完成探险任务之后, singAfterQuest()方法会被调用。 在这两种情况下, Minstrel都会通过一个PrintStream类来歌颂骑士的事迹, 这个类是通过构造器注入进来的。
把Minstrel加入你的代码中并使其运行起来, 这对你来说是小事一桩。 我们适当做一下调整从而让BraveKnight可以使用Minstrel。 程序清单1.10展示了将BraveKnight和Minstrel组合起来的第一次尝试。
package sia.knights;
public class BraveKnight implements Knight {
private Quest quest;
private Minstrel minstrel;
public BraveKnight(Quest quest, Minstrel minstrel) {
this.quest = quest;
this.minstrel = minstrel;
}
public void embarkOnQuest() {
minstrel.singBeforeQuest();
quest.embark();
minstrel.singAfterQuest();
}
}
这应该可以达到预期效果。 现在, 你所需要做的就是回到Spring配置中, 声明Minstrel bean并将其注入到BraveKnight的构造器之中。
但是, 请稍等……
我们似乎感觉有些东西不太对。 管理他的吟游诗人真的是骑士职责范围内的工作吗? 在我看来, 吟游诗人应该做他份内的事, 根本不需要骑士命令他这么做。 毕竟, 用诗歌记载骑士的探险事迹, 这是吟游诗人的职责。 为什么骑士还需要提醒吟游诗人去做他份内的事情呢?此外, 因为骑士需要知道吟游诗人, 所以就必须把吟游诗人注入到BarveKnight类中。 这不仅使BraveKnight的代码复杂化了, 而且还让
我疑惑是否还需要一个不需要吟游诗人的骑士呢? 如果Minstrel为null会发生什么呢? 我是否应该引入一个空值校验逻辑来覆盖该场景?
简单的BraveKnight类开始变得复杂, 如果你还需要应对没有吟游诗人时的场景, 那代码会变得更复杂。 但利用AOP, 你可以声明吟游诗人必须歌颂骑士的探险事迹, 而骑士本身并不用直接访问Minstrel的方法。
要将Minstrel抽象为一个切面, 你所需要做的事情就是在一个Spring配置文件中声明它。 程序清单1.11是更新后的knights.xml文件, Minstrel被声明为一个切面。
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="knight" class="sia.knights.BraveKnight">
<constructor-arg ref="quest" />
</bean>
<bean id="quest" class="sia.knights.SlayDragonQuest">
<constructor-arg ref="fakePrintStream" />
</bean>
<bean id="minstrel" class="sia.knights.Minstrel">
<constructor-arg ref="fakePrintStream" />
</bean>
<bean id="fakePrintStream" class="sia.knights.FakePrintStream" />
<aop:config>
<aop:aspect ref="minstrel">
<aop:pointcut id="embark"
expression="execution(* *.embarkOnQuest(..))"/>
<aop:before pointcut-ref="embark"
method="singBeforeQuest"/>
<aop:after pointcut-ref="embark"
method="singAfterQuest"/>
</aop:aspect>
</aop:config>
</beans>
————————————————
版权声明:本文为CSDN博主「continuebreak」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_40726316/article/details/90573478
这里使用了Spring的aop配置命名空间把Minstrel bean声明为一个切面。 首先, 需要把Minstrel声明为一个bean, 然后在元素中引用该bean。 为了进一步定义切面, 声明(使用) 在embarkOnQuest()方法执行前调用Minstrel的singBeforeQuest()方法。 这种方式被称为前置通知(before advice) 。 同时声明(使用)在embarkOnQuest()方法执行后调用singAfter Quest()方法。 这种方式被称为后置通知(after advice) 。
首先, Minstrel仍然是一个POJO, 没有任何代码表明它要被作为一个切面使用。 当我们按照上面那样进行配置后, 在Spring的上下文中, Minstrel实际上已经变成一个切面了。
其次, 也是最重要的, Minstrel可以被应用到BraveKnight中, 而BraveKnight不需要显式地调用它。 实际上, BraveKnight完全不知道Minstrel的存在。
必须还要指出的是, 尽管我们使用Spring魔法把Minstrel转变为一个切面, 但首先要把它声明为一个Spring bean。 能够为其他Spring bean做到的事情都可以同样应用到Spring切面中, 例如为它们注入依赖。
使用模板消除样板式代码
你是否写过这样的代码, 当编写的时候总会感觉以前曾经这么写过? 我的朋友, 这不是似曾相识。 这是样板式的代码(boilerplate code) 。 通常为了实现通用的和简单的任务, 你不得不一遍遍地重复编写这样的代码。
遗憾的是, 它们中的很多是因为使用Java API而导致的样板式代码。 样板式代码的一个常见范例是使用JDBC访问数据库查询数据。 举个例子, 如果你曾经用过JDBC, 那么你或许会写出类似下面的代码。
正如你所看到的, 这段JDBC代码查询数据库获得员工姓名和薪水。 我打赌你很难把上面的代码逐行看完, 这是因为少量查询员工的代码淹没在一堆JDBC的样板式代码中。 首先你需要创建一个数据库连接, 然后再创建一个语句对象, 最后你才能进行查询。
为了平息JDBC可能会出现的怒火, 你必须捕捉SQLException, 这是一个检查型异常, 即使它抛出后你也做不了太多事情。
最后, 毕竟该说的也说了, 该做的也做了, 你不得不清理战场, 关闭数据库连接、 语句和结果集。 同样为了平息JDBC可能会出现的怒火, 你依然要捕SQLException。
程序清单1.12中的代码和你实现其他JDBC操作时所写的代码几乎是相同的。 只有少量的代码与查询员工逻辑有关系, 其他的代码都是JDBC的样板代码。
JDBC不是产生样板式代码的唯一场景。 在许多编程场景中往往都会导致类似的样板式代码, JMS、 JNDI和使用REST服务通常也涉及大量的重复代码。
Spring旨在通过模板封装来消除样板式代码。 Spring的JdbcTemplate使得执行数据库操作时, 避免传统的JDBC样板代码成为了可能。
举个例子, 使用Spring的JdbcTemplate(利用了 Java 5特性的JdbcTemplate实现) 重写的getEmployeeById()方法仅仅关注于获取员工数据的核心逻辑, 而不需要迎合JDBC API的需求。 程序清单1.13展示了修订后的getEmployeeById()方法。
正如你所看到的, 新版本的getEmployeeById()简单多了, 而且仅仅关注于从数据库中查询员工。 模板的queryForObject()方法需要一个SQL查询语句, 一个RowMapper对象(把数据映射为一个域对象) , 零个或多个查询参数。 GetEmp loyeeById()方法再也看不到以前的JDBC样板式代码了, 它们全部被封装到了模板中。
我已经向你展示了Spring通过面向POJO编程、 DI、 切面和模板技术来简化Java开发中的复杂性。 在这个过程中, 我展示了在基于XML的配置文件中如何配置bean和切面。
但这些文件是如何加载的呢? 它们被加载到哪里去了? 让我们再了解下Spring容器, 这是应用中的所有bean所驻留的地方。下次聊。
如果本文对你有帮助,别忘记给我个3连 ,点赞,转发,评论,
,咱们下期见!答案获取方式:已赞 已评 已关~
相关推荐
- 十分钟让你学会LNMP架构负载均衡(impala负载均衡)
-
业务架构、应用架构、数据架构和技术架构一、几个基本概念1、pv值pv值(pageviews):页面的浏览量概念:一个网站的所有页面,在一天内,被浏览的总次数。(大型网站通常是上千万的级别)2、u...
- AGV仓储机器人调度系统架构(agv物流机器人)
-
系统架构层次划分采用分层模块化设计,分为以下五层:1.1用户接口层功能:提供人机交互界面(Web/桌面端),支持任务下发、实时监控、数据可视化和报警管理。模块:任务管理面板:接收订单(如拣货、...
- 远程热部署在美团的落地实践(远程热点是什么意思)
-
Sonic是美团内部研发设计的一款用于热部署的IDEA插件,本文其实现原理及落地的一些技术细节。在阅读本文之前,建议大家先熟悉一下Spring源码、SpringMVC源码、SpringBoot...
- springboot搭建xxl-job(分布式任务调度系统)
-
一、部署xxl-job服务端下载xxl-job源码:https://gitee.com/xuxueli0323/xxl-job二、导入项目、创建xxl_job数据库、修改配置文件为自己的数据库三、启动...
- 大模型:使用vLLM和Ray分布式部署推理应用
-
一、vLLM:面向大模型的高效推理框架1.核心特点专为推理优化:专注于大模型(如GPT-3、LLaMA)的高吞吐量、低延迟推理。关键技术:PagedAttention:类似操作系统内存分页管理,将K...
- 国产开源之光【分布式工作流调度系统】:DolphinScheduler
-
DolphinScheduler是一个开源的分布式工作流调度系统,旨在帮助用户以可靠、高效和可扩展的方式管理和调度大规模的数据处理工作流。它支持以图形化方式定义和管理工作流,提供了丰富的调度功能和监控...
- 简单可靠高效的分布式任务队列系统
-
#记录我的2024#大家好,又见面了,我是GitHub精选君!背景介绍在系统访问量逐渐增大,高并发、分布式系统成为了企业技术架构升级的必由之路。在这样的背景下,异步任务队列扮演着至关重要的角色,...
- 虚拟服务器之间如何分布式运行?(虚拟服务器部署)
-
在云计算和虚拟化技术快速发展的今天,传统“单机单任务”的服务器架构早已难以满足现代业务对高并发、高可用、弹性伸缩和容错容灾的严苛要求。分布式系统应运而生,并成为支撑各类互联网平台、企业信息系统和A...
- 一文掌握 XXL-Job 的 6 大核心组件
-
XXL-Job是一个分布式任务调度平台,其核心组件主要包括以下部分,各组件相互协作实现高效的任务调度与管理:1.调度注册中心(RegistryCenter)作用:负责管理调度器(Schedule...
- 京东大佬问我,SpringBoot中如何做延迟队列?单机与分布式如何做?
-
京东大佬问我,SpringBoot中如何做延迟队列?单机如何做?分布式如何做呢?并给出案例与代码分析。嗯,用户问的是在SpringBoot中如何实现延迟队列,单机和分布式环境下分别怎么做。这个问题其实...
- 企业级项目组件选型(一)分布式任务调度平台
-
官网地址:https://www.xuxueli.com/xxl-job/能力介绍架构图安全性为提升系统安全性,调度中心和执行器进行安全性校验,双方AccessToken匹配才允许通讯;调度中心和执...
- python多进程的分布式任务调度应用场景及示例
-
多进程的分布式任务调度可以应用于以下场景:分布式爬虫:importmultiprocessingimportrequestsdefcrawl(url):response=re...
- SpringBoot整合ElasticJob实现分布式任务调度
-
介绍ElasticJob是面向互联网生态和海量任务的分布式调度解决方案,由两个相互独立的子项目ElasticJob-Lite和ElasticJob-Cloud组成。它通过弹性调度、资源管控、...
- 分布式可视化 DAG 任务调度系统 Taier 的整体流程分析
-
Taier作为袋鼠云的开源项目之一,是一个分布式可视化的DAG任务调度系统。旨在降低ETL开发成本,提高大数据平台稳定性,让大数据开发人员可以在Taier直接进行业务逻辑的开发,而不用关...
- SpringBoot任务调度:@Scheduled与TaskExecutor全面解析
-
一、任务调度基础概念1.1什么是任务调度任务调度是指按照预定的时间计划或特定条件自动执行任务的过程。在现代应用开发中,任务调度扮演着至关重要的角色,它使得开发者能够自动化处理周期性任务、定时任务和异...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- MVC框架 (46)
- spring框架 (46)
- 框架图 (58)
- flask框架 (53)
- quartz框架 (51)
- abp框架 (47)
- jpa框架 (47)
- laravel框架 (46)
- springmvc框架 (49)
- 分布式事务框架 (65)
- scrapy框架 (56)
- shiro框架 (61)
- 定时任务框架 (56)
- java日志框架 (61)
- JAVA集合框架 (47)
- grpc框架 (55)
- ppt框架 (48)
- 内联框架 (52)
- winform框架 (46)
- gui框架 (44)
- cad怎么画框架 (58)
- ps怎么画框架 (47)
- ssm框架实现登录注册 (49)
- oracle字符串长度 (48)
- oracle提交事务 (47)