前言:

曾几何时,Spring框架提供了比J2EE更轻量级和更灵活的解决方案。即使在2013年左右,我也很高兴详细了解当时的新款Spring 4。如今,7年后,当我看到春天的时候,我感到一阵恐慌。注释和@ComponentScan已经用更好的东西取代了XML,这需要一个可视化工具来理解您的系统。Spring变成了一头不断生长(和变化)的水螅。我接手并试图理解他人编写的Spring应用程序,这让我很痛苦。最后但并非最不重要的一点是,Clojure教会了我代码可以/应该是多么简单。那么,我对Spring的主要问题是什么?

(为了明确起见,当我说Spring时,我指的主要是Spring控制反转(IoC)及其依赖注入子集。)

Spring的缺点

不可理解性

系统构成的黑箱:

注释和组件扫描对于让应用程序快速启动和运行来说非常棒。但当您试图理解所述应用程序时,它们是一场噩梦。由于@Configurations@bean来自您的代码库、公司库中的任何地方,并且可能来自±100MB的Spring依赖项(真实情况),因此不可能清楚地了解应用程序的结构和配置。您基本上需要一次又一次地为Spring和所有库进行RTFM,以便记住可能需要的所有内容,并通读整个代码库。诸如IntelliJ SpringBeans视图之类的工具可能会有所帮助(如果您能够正常工作的话)。

在这里,我完全同意Python的禅宗“显式优于隐式”

在一个典型的Clojure项目中,我转到核心/主名称空间,其中主函数启动服务器并为其提供一个处理函数,可能(手动)使用一些中间件包装,可能在内部使用库进行路由。我还可能阅读配置并传递它。我可以轻松地单击浏览代码,并查看代码中的具体部分以及它们是如何协同工作的。即使是在cljdoc这样的大型系统中。org有一个主功能启动服务器(这里是Integrant),并为其提供配置和“系统定义”(类似于Springbean树)。一切都是明确的和可导航的。

按注释编程

能够向方法和类添加元数据非常棒。我对@GetMapping(“/”)之类的东西没有任何反对意见。但它通常被用来绕过Java的限制,并通过诸如@Scheduled@Transactional之类的注释实现横切关注点。我曾经是AOP的坚定支持者,由于语言的限制,AOP仍然是Java开发人员不可或缺的工具,但我也意识到它的成本不容忽视。问题是,您无法轻松看到它在做什么(因为它什么都没做,只是数据)。为了给您一个透视图,替换@Transactional Person findPersonInDb(String personId) {..}在Clojure中,我只需要用一个自定义宏来包装它,例如:

(defn find-person-in-db [person-id]
  (transactional
    ...))

实质性的区别是,我可以控制单击导航到宏,并查看它在做什么,因此所有行为都在那里,供我检查和理解。祝你在Spring找到答案!

故障排除

Spring是让很多事情快速起步的好时机——直到某些事情失败或不按预期工作为止。Spring是一个松散耦合的意大利面大球,在我痛苦的经历中,解决它是非常困难的。有很多文档,但我经常找不到我需要的答案。也许官方文件太肤浅,有时依赖于大量已有的知识。搜索互联网有时提供了一个解决方案,有时至少提供了有用的指针,有时提供了误导性/旧信息,有时什么都没有。在进行故障排除时,您需要艰难地通过这个庞大复杂的类,这些类以某种方式协同工作(或应该协同工作),以(似乎)神秘的方式受到类路径上的jar和@Configurations的影响,并希望您能够偶然发现问题的原因。

例如,我花了相当长的时间来理解Spring MVC应用程序中的错误处理是如何工作的。我们有一个@ControllerAdvice(["myapp.endpoint.api"]) myapp.endpoint.api.advice.ErrorHandler调用的ErrorHandler(如果您记得抛出正确的异常类型),@Component myapp.spring.ErrorPagesCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>将container.addErrorPages(new ErrorPage("/error"))错误发送到org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController,然后它将神奇地呈现我们的错误。类路径上的html。我意识到我再也不明白(如果我真的明白的话)它到底是如何工作的了。但要以所需的方式显示错误,无疑是一场斗争。

另一个难点是理解为什么Spring返回404而不是预期的文件。我对它的请求处理有很多来之不易的知识,也许有一天会成为一篇博客文章。

了解@Scheduled jobs实际上是如何调度的,并试图找出为什么一个作业没有按预期运行,以及增加线程池大小以使其不再被较慢的作业停止的神奇调用是什么,这需要几天的时间和多次失败的尝试,我甚至放弃了一次或两次。搜索互联网提供了一些帮助,但肯定远远不够。这是我的一般经验,与Spring有关。

在Spring升级后搜索突然出现的ClassNotFound运行时错误,试图找出哪个Spring JAR有这个类,哪个版本是正确的,或者如何更改配置以停止需要更改…​ 不,谢谢你。

为什么是Spring IoC?

这是一个由两部分组成的问题:为什么是Spring IoC?为什么是Spring?

许多开发人员都知道,Spring是一个成熟且流行的解决方案。它还为几乎所有问题提供了解决方案,这些解决方案通常能够很好地协同工作。您也可以快速开始。另一方面,你可能会争辩说,这是夸大其词,有遗留问题,而且——通过尝试为每个人做每件事——没有做得完美,更小、专注的解决方案可能更好(尽管你需要整合它们)。

为什么选择依赖注入和IoC?您可以从中找到许多原因:使用依赖注入和IoC容器的好处是什么?。

其中一些是:

  • 简化-您的类不需要知道如何创建它们的依赖项(以及它们需要什么)。您可以将实例化和连接类的问题分离出来。
  • 灵活性—您现在可以提供不同的/修饰的实现。因此,在测试中,您可以提供模拟实现,在大型复杂系统中,通过交换新的实现(这部分取决于对接口的编程),您可以使用疑难解答装饰器包装依赖项,从而使其更容易逐步重构。
  • 生命周期控制

查看维基百科上列出的优点和缺点。但它有明显的好处,这并不意味着你应该在任何地方、任何事情上都使用它。记住成本和劣势,做出有根据的决策。

我们通常在Clojure-f.ex中使用依赖注入。接下来是数据库访问库。jdbc要求您将目标数据源传递给每个调用。(这使您可以自由地创建自己的包装器来控制数据源并将其传递给库(如果您愿意的话)在Cognitect AWS API中构造AWS客户端时,可以让它创建默认的底层HTTP客户端,也可以提供自己的客户端,这样就可以覆盖默认的依赖关系。我们甚至有一些人喜欢使用的依赖注入框架,如组件和上下文,而其他经验丰富的开发人员则觉得它们不必要。

选择

当谈到Spring生态系统作为一个整体时,您应该始终应用Alex的合理库原则:不要添加库,直到没有库的痛苦如此之大,您无法忍受没有它的生活(并且在适当探索了其他选择之后)。

当您需要依赖注入时,最好手动组合系统。当前的小型微服务时代与诞生Spring的巨型应用时代截然不同。你可以自己做(为什么不?!)或者使用一种重量轻、重点突出的解决方案来解决更为手动的问题,例如Feather。尽可能喜欢编程配置。Feather仍然是由CDI的@Provides驱动的注释,但至少您在一个“module”类中声明了这些注释,您显式地向Feather注册了这些注释,并显式地向Feather请求所需的实例。在过去,我们使用Guice和手动调用来绑定每个微服务的主类。对于我这个当时经验丰富的Spring用户来说,这似乎很奇怪,也很错误,但我开始理解并欣赏它。甚至还有用于Spring Boot的(实验性)编程配置DSL JaFu(Kotlin,KoFu也有一个)。

据一些人说,Jakarta(Java EE的后代)是Spring生态系统的一个更干净、更小、更好的替代品。您还可以针对特定需求搜索单个解决方案。

我从一位受人尊敬的同事那里听到了Micronaut的好消息,它提供了低开销的DI和AOP、REST客户端/服务器、反应式、断路器等,但它仍然依赖(似乎)类路径扫描进行配置,因此保留了我在Spring中的主要问题。还有反应型Helidon SE,它具有“透明的”的开发经验;纯java应用程序开发,无注释,无依赖注入”与这两个领域相同的领域是Quarkus,但其IoC基于CDI,因此与Spring有相同的问题。Eclipse Vert.X 专注于反应式、事件驱动的应用程序有所不同,但提供了类似的功能(HTTP客户端/服务器、OpenAPI、GraphQL、DB访问、配置、断路器、安全性、度量),并具有编程配置;相反,它不提供依赖注入(但您可能不需要它(尽管总线本身也有问题))。

其他人在说什么

在为本文做研究时,我发现了一些值得分享的经验和观点。

著名的挪威软件架构师Johannes Brodwall写道(2013年,再次遥遥领先于我):

我发现DI容器给我的一些直觉让我改进了设计,但同时,我发现当我移除容器时,解决方案变小了(这很好!),更易于导航和理解,更易于测试。我发现使用容器的成本非常高,这会导致复杂性和大小的增加,以及一致性的降低。

在这场Quora讨论中,有很多好的建议:为什么大多数母语不是Java的程序员似乎对Spring框架持反对意见,他们对Spring框架的哲学有什么不喜欢的?

这方面的问题是:Spring有点破坏了我们从使用Java中获得的简单性好处。Spring谨慎地将复杂性引入到您的项目中,当它工作时,框架表面上很简单,但老实说,有多少人可以解释Spring中发生的事情?调试Spring错误通常看起来像是魔术,需要90%的猜测和模式匹配。Spring通常可以在项目开始时为您节省数周的工作时间,您可能会觉得这些好处是免费的,但事实并非如此。在某些方面,您可以将其与在项目中使用动态编程语言的早期好处进行类比。在项目的初始阶段,它会大大加快您的速度,但复杂性和技术债务会在稍后的阶段打击您。

(当然,他与动态编程语言的比较与我和其他人使用Clojure的经验相反。)

所以他们改成了基于注释的配置,被迫学习,但我还是不喜欢。它仍然不是真正的Java。许多事情都是靠魔法发生的——当它们没有发生时,它们都以同样的方式失败,什么都没有发生。因此,您编辑并重新编译,同样不会发生任何事情。无法判断您是否注释了错误的内容,或者您的注释所说的内容是否与您认为的不同,或者您是否构建了错误的测试。

如果有像样的文档,我还没有看到。我最近研究了RequestParam,它是Spring MVC中普遍存在的一部分,以了解其语义。该页面实际上是无用的。Javadoc是API通信的主要方式;即使有更好的文档存在,这个页面也不会告诉我太多。

关于现代Java应用程序:

Main方法有一行起始Spring和许多类,每个类有5个注释。它们是如何被实例化的,以什么顺序,如果出现问题,如何调试这个过程

下面是我最讨厌Spring的几件事:

它确实会减慢应用程序的启动时间,在运行应用程序之前,你不会知道你的应用程序是否正常工作——在大型商业环境中,这意味着最多需要一个小时的构建和部署时间…然后会得到大量的stacktrace,其中一半与内部spring类有关,一旦您超越了简单的单例布线场景,Spring就会变得非常丑陋、非常脆弱和不可预测,这有助于您起步,但您走得越远,维护的噩梦就越大。

结论

那么,Spring是邪恶的,应该不惜任何代价避免吗?不需要。它使人们能够克服Java的局限性,并提供了许多库来解决实际问题。但它也是巨大、复杂的,而且维护成本很高。对引入库持怀疑态度,考虑多种解决方案,并为您的案例选择最佳解决方案,而不仅仅是Spring解决方案。即使在使用DI和IoC(Spring或其他)时,也要努力实现最大的透明度,并且更喜欢编程配置而不是类路径扫描。如果其他一切都失败了,请编写良好的(java)文档,以便您的继任者能够理解您的系统。

到此这篇关于深入介绍Spring框架及故障排除的文章就介绍到这了,更多相关 Spring框架 内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

深入介绍Spring框架及故障排除的更多相关文章

  1. xcode6.1 – Xcode 6.1中项目模板中缺少类前缀

    项目模板上曾经有一个类前缀字段,这有助于区分项目类和框架类.Xcode6.1项目模板中不再提供此功能.这背后的意图是什么?

  2. ios – 伞框架

    错误.应用程序,通常位于…错误仍然存在你也可以在这里添加(子)框架的路径.

  3. ios – UIView框架大小的问题

    我正在开发一个iPad项目,目前正在使用Landscape视图.我试着这样做:为什么这总是返回960?虽然在景观中,视图本身的高度尺寸应为768对吗?

  4. 安装自定义cocoa框架的最佳方法

    我有一个自定义框架,遵循Apple的框架编程指南>>中的建议.Installingyourframework我在/Library/Frameworks中安装.我通过使用以下脚本添加RunScript构建阶段来完成此操作:在我的项目中,我然后链接/Library/Frameworks/MyFramework并将其导入我的类中,如下所示:这非常有效,除了我总是在调试器控制台中看到以下消息:Loadin

  5. ios – 在设备上构建和运行时,仅将嵌入式框架与其他动态框架链接失败

    TL;博士将您的嵌入式框架与其他框架链接,并且不将其他框架与您的应用程序链接,导致Build&在设备上运行.描述:建立:我的设置非常简单(Swift2.3&XcodeXcode8.0;Build版本8S162m):>使用Carthage(0.17.2)我用xcodebuild8.0和TOOLCHAINS=com.apple.dt.toolchain.Swift_2_3carthagebui

  6. iOS 8嵌入式框架中的头文件

    我正在尝试创建一个用于iOS8的嵌入式框架.在创建一个名为SampleKit(BTW;这里有任何约定,我应该使用前缀吗?)之后,它包含一个令我困惑的头文件:我知道FOUNDATION_EXPORT是extern或extern“C”的宏,但我不确定这两个常量.我应该在哪里为他们设定价值?解决方法项目>构建设置>版本控制>当前项目版本:

  7. 在Monotouch上模拟.NET的框架?

    有没有人使用过他们发现与Monotouch兼容的.NET模拟框架?在尝试使用之前,我很好奇与NMock,NSubstitute,Moq和其他框架的兼容性.Xamarin刚刚加强了它的单元测试支持,但没有提到模拟框架.仅供参考,我希望在VS2010上为非UI位做很多开发,并在UI进入时移动到iOS平台.谢谢您的帮助.解决方法我建议只使用手动模拟:如果我不得不猜测RhinoMocks,Moq等大量使用Reflection.Emit(你怎么能做他们能做的疯狂?),这将无法在MonoTouch上使用AOT编译器运

  8. 在ios上使用来自框架的boost :: filesysystem路径

    我一直在使用Boost作为PeteGoodliffe脚本构建的框架已有一段时间了.效果很好.最近我遇到了一个问题,可以通过将以下代码放入另一个全新的XCode项目中的视图控制器的viewDidLoad中来重现:当路径对象被销毁时会导致EXC_BAD_ACCESS.有没有其他人遇到这个问题?

  9. ios – 在约束依赖于框架的自定义视图中使用自动布局

    我正在编写一个以编程方式初始化的自定义视图.我重写updateConstraints以添加此视图所需的所有约束.:问题是self.bounds返回CGRectZero的等价物.我做了我的研究并根据这个objc.ioarticle,这是预期的,因为在调用layoutSubviews之前框架不会被设置.它也提到了Toforcethesystemtoupdatethelayoutofaviewtreei

  10. ios – “禁用模块时使用’@import’”错误 – 启用模块和链接框架= YES

    我有一个使用CocoaPods并使用’SCLAlertView-Objective-C’窗格的项目.该pod使用@importUIKit;模块样式导入.我在目标和项目设置中将“启用模块(C&Objective-C)”和“自动链接框架”设置为YES.当模块被禁用时,我仍然得到“使用’@import’错误.有没有什么可以阻止Xcode能够启用模块,如使用.pch文件,任何链接器标志,或者我没有提到的任

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部