什么是spring框架?spring框架到底有什么用?
ccwgpt 2024-09-14 00:10 40 浏览 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连 ,点赞,转发,评论,
,咱们下期见!答案获取方式:已赞 已评 已关~
相关推荐
- 一个基于.Net Core遵循Clean Architecture原则开源架构
-
今天给大家推荐一个遵循CleanArchitecture原则开源架构。项目简介这是基于Asp.netCore6开发的,遵循CleanArchitecture原则,可以高效、快速地构建基于Ra...
- AI写代码翻车无数次,我发现只要提前做好这3步,bug立减80%
-
写十万行全是bug之后终于找到方法了开发"提示词管理助手"新版本那会儿,我差点被bug整崩溃。刚开始两周,全靠AI改代码架构,结果十万行程序漏洞百出。本来以为AI说没问题就稳了,结果...
- OneCode低代码平台的事件驱动设计:架构解析与实践
-
引言:低代码平台的事件驱动范式在现代软件开发中,事件驱动架构(EDA)已成为构建灵活、松耦合系统的核心范式。OneCode低代码平台通过创新性的注解驱动设计,将事件驱动理念深度融入平台架构,实现了业务...
- 国内大厂AI插件评测:根据UI图生成Vue前端代码
-
在IDEA中安装大厂的AI插件,打开ruoyi增强项目:yudao-ui-admin-vue31.CodeBuddy插件登录腾讯的CodeBuddy后,大模型选择deepseek-v3,输入提示语:...
- AI+低代码技术揭秘(二):核心架构
-
本文档介绍了为VTJ低代码平台提供支持的基本架构组件,包括Engine编排层、Provider服务系统、数据模型和代码生成管道。有关UI组件库和widget系统的信息,请参阅UI...
- GitDiagram用AI把代码库变成可视化架构图
-
这是一个名为gitdiagram的开源工具,可将GitHub仓库实时转换为交互式架构图,帮助开发者快速理解代码结构。核心功能一键可视化:替换GitHubURL中的"hub...
- 30天自制操作系统:第六天:代码架构整理与中断处理
-
1.拆开bootpack.c文件。根据设计模式将对应的功能封装成独立的文件。2.初始化pic:pic(可编程中断控制器):在设计上,cpu单独只能处理一个中断。而pic是将8个中断信号集合成一个中断...
- AI写代码越帮越忙?2025年研究揭露惊人真相
-
近年来,AI工具如雨后春笋般涌现,许多人开始幻想程序员的未来就是“对着AI说几句话”,就能轻松写出完美的代码。然而,2025年的一项最新研究却颠覆了这一期待,揭示了一个令人意外的结果。研究邀请了16位...
- 一键理解开源项目:两个自动生成GitHub代码架构图与说明书工具
-
一、GitDiagram可以一键生成github代码仓库的架构图如果想要可视化github开源项目:https://github.com/luler/reflex_ai_fast,也可以直接把域名替换...
- 5分钟掌握 c# 网络通讯架构及代码示例
-
以下是C#网络通讯架构的核心要点及代码示例,按协议类型分类整理:一、TCP协议(可靠连接)1.同步通信//服务器端usingSystem.Net.Sockets;usingTcpListene...
- 从复杂到优雅:用建造者和责任链重塑代码架构
-
引用设计模式是软件开发中的重要工具,它为解决常见问题提供了标准化的解决方案,提高了代码的可维护性和可扩展性,提升了开发效率,促进了团队协作,提高了软件质量,并帮助开发者更好地适应需求变化。通过学习和应...
- 低代码开发当道,我还需要学习LangChain这些框架吗?| IT杂谈
-
专注LLM深度应用,关注我不迷路前两天有位兄弟问了个问题:当然我很能理解这位朋友的担忧:期望效率最大化,时间用在刀刃上,“不要重新发明轮子”嘛。铺天盖地的AI信息轰炸与概念炒作,很容易让人浮躁与迷茫。...
- 框架设计并不是简单粗暴地写代码,而是要先弄清逻辑
-
3.框架设计3.框架设计本节我们要开发一个UI框架,底层以白鹭引擎为例。框架设计的第一步并不是直接撸代码,而是先想清楚设计思想,抽象。一个一个的UI窗口是独立的吗?不是的,...
- 大佬用 Avalonia 框架开发的 C# 代码 IDE
-
AvalonStudioAvalonStudio是一个开源的跨平台的开发编辑器(IDE),AvalonStudio的目标是成为一个功能齐全,并且可以让开发者快速使用的IDE,提高开发的生产力。A...
- 轻量级框架Lagent 仅需20行代码即可构建自己的智能代理
-
站长之家(ChinaZ.com)8月30日消息:Lagent是一个专注于基于LLM模型的代理开发的轻量级框架。它的设计旨在简化和提高这种模型下代理的开发效率。LLM模型是一种强大的工具,可以...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- 框架图 (58)
- flask框架 (53)
- quartz框架 (51)
- abp框架 (47)
- springmvc框架 (49)
- 分布式事务框架 (65)
- scrapy框架 (56)
- shiro框架 (61)
- 定时任务框架 (56)
- java日志框架 (61)
- mfc框架 (52)
- abb框架断路器 (48)
- beego框架 (52)
- java框架spring (58)
- grpc框架 (65)
- tornado框架 (48)
- 前端框架bootstrap (54)
- orm框架有哪些 (51)
- 知识框架图 (52)
- ppt框架 (55)
- 框架图模板 (59)
- 内联框架 (52)
- cad怎么画框架 (58)
- ssm框架实现登录注册 (49)
- oracle字符串长度 (48)