当我大约10年前开始我的职业生涯时,Struts MVC就是市场上的常态。 但是,多年来,我观察到Spring MVC逐渐流行起来。 鉴于Spring MVC与Spring容器的无缝集成以及它提供的灵活性和可扩展性,这对我来说并不奇怪。

从到目前为止的Spring旅程中,我通常会看到人们在配置Spring框架时犯了一些常见的错误。 与人们仍然使用Struts框架的时间相比,这种情况发生的频率更高。 我想这是灵活性和可用性之间的权衡。 另外,Spring文档中有很多示例,但缺乏解释。 为了填补这一空白,本文将尝试阐述和解释我经常看到的3个常见问题。

在Servlet上下文定义文件中声明bean

因此,我们每个人都知道Spring使用ContextLoaderListener加载Spring应用程序上下文。 不过,当宣布
DispatcherServlet ,我们需要创建名称为“ $ {servlet.name} -context.xml”的servlet上下文定义文件。 有没有想过为什么?

应用程序上下文层次结构

并非所有开发人员都知道Spring应用程序上下文具有层次结构。 让我们看一下这种方法:

org.springframework.context.ApplicationContext.getParent()

它告诉我们Spring Application Context具有父级。 那么,这个父母干什么呢?

如果下载源代码并进行快速引用搜索,则应该发现Spring Application Context将parent作为其扩展名。 如果您不介意阅读代码,请让我向您展示方法BeanFactoryUtils.beansOfTypeIn includedAncestors()中的用法示例:

if (lbf instanceof HierarchicalBeanFactory) {HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf;if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {Map parentResult = beansOfTypeIncludingAncestors((ListableBeanFactory) hbf.getParentBeanFactory(), type);...}
}
return result;
}

如果遍历整个方法,您将发现在搜索父上下文之前,Spring Application Context会扫描以在内部上下文中查找bean。 通过这种策略,Spring Application Context将有效地进行反向广度优先搜索以查找bean。

ContextLoaderListener

这是每个开发人员都应该知道的众所周知的类。 它有助于从预定义的上下文定义文件中加载Spring应用程序上下文。 由于实现了ServletContextListener ,因此将在加载Web应用程序后立即加载Spring应用程序上下文。 当加载包含带有@PostContruct批注或批处理作业的bean的Spring容器时,这带来了无可争议的好处。

相反,在初始化servlet之前,不会构造servlet上下文定义文件中的任何bean定义。 何时初始化Servlet? 这是不确定的。 在最坏的情况下,您可能需要等到用户对servlet映射URL进行第一次点击才能加载spring上下文。

根据以上信息,您应该在哪里声明所有珍贵的豆子? 我觉得这样做的最佳位置是ContextLoaderListener加载的上下文定义文件,而没有其他地方。 这里的窍门是将ApplicationContext作为servlet属性存储在键org.springframework.web.context.WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE下
稍后, DispatcherServlet将从ServletContext加载此上下文,并将其分配为父应用程序上下文。

protected WebApplicationContext initWebApplicationContext() {WebApplicationContext rootContext =WebApplicationContextUtils.getWebApplicationContext(getServletContext());...
}

由于这种行为,强烈建议创建一个空的servlet应用程序上下文定义文件,并在父上下文中定义您的bean。 这将有助于避免在加载Web应用程序时重复创建Bean,并确保立即执行批处理作业。

从理论上讲,在servlet应用程序上下文定义文件中定义bean会使该bean唯一且仅对该servlet可见。 但是,在使用Spring的8年中,除了定义Web Service端点之外,我几乎没有发现此功能的任何用途。

这是一个小错误,但是如果您不注意它,它将引起您的注意。 Log4jConfigListener是我在-Dlog4j.configuration首选的解决方案,我们可以控制的log4j加载不改变服务器的引导过程。

显然,这应该是在web.xml中声明的第一个侦听器。 否则,您浪费所有的时间来声明正确的日志记录配置。

由于对Bean的探索管理不善而复制了Bean

在Spring的早期,开发人员在xml文件上打字的时间比Java类花费的时间更多。 对于每个新bean,我们需要自己声明和连接依赖项,这是干净,整洁但非常痛苦的。 毫无疑问,Spring框架的更高版本向更高的可用性发展。 如今,开发人员可能只需要声明事务管理器,数据源,属性源,Web服务端点,其余的就可以进行组件扫描和自动装配。

我喜欢这些新功能,但是这种强大的力量需要承担巨大的责任。 否则,事情会很快变得混乱。 XML文件中的组件扫描和bean声明是完全独立的。 因此,如果对bean进行注释以进行组件扫描并手动进行声明,则在bean容器中完全可能具有相同类的相同bean。 幸运的是,这种错误应该只发生在初学者身上。

当我们需要将一些嵌入式组件集成到最终产品中时,情况变得更加复杂。 然后,我们确实需要一种策略来避免重复的bean声明。

上图显示了我们日常生活中遇到的种种现实问题。 大多数情况下,系统是由多个组件组成的,通常,一个组件可为多个产品提供服务。 每个应用程序和组件都有自己的bean。 在这种情况下,最好的声明方式是避免重复的bean声明?

这是我建议的策略:

  • 确保每个组件都必须以专用的软件包名称开头。 当我们需要进行组件扫描时,它使我们的工作变得更轻松。
  • 不要指示开发组件的团队采用在组件本身中声明Bean的方法(注释与xml声明)。 开发人员负责将组件打包到最终产品中,以确保没有重复的bean声明。
  • 如果组件中包含上下文定义文件,请给它一个包,而不是放在classpath的根目录中。 最好给它起一个特定的名字。 例如, src / main / resources / spring-core / spring-core-context.xmlsrc / main / resource / application-context.xml更好 想象一下,如果在相同的程序包中打包几个包含相同文件application-context.xml的组件,那该怎么办!
  • 如果您已经在一个上下文文件中声明了Bean,则不要为组件扫描提供任何注释( @ Component, @ Service@Repository )。
  • 将特定于环境的bean(例如data-sourceproperty-source)拆分到一个单独的文件中并重用。
  • 不要在常规包装上进行组件扫描。 例如,与扫描org.springframework包相比,如果我们扫描几个子包(例如org.springframework.coreorg.springframework.contextorg.springframework.ui ,…), 则更易于管理。

结论

希望以上技巧对日常使用很有帮助。 如有任何疑问或任何其他想法,请发送反馈以提供帮助。

翻译自: https://www.javacodegeeks.com/2014/07/common-mistakes-when-using-spring-mvc.html

使用Spring MVC时的常见错误相关推荐

  1. Python运行的17个时新手常见错误小结

    Python运行的17个时新手常见错误小结 1 发布时间:『 2017-11-04 11:20 』     帖子类别:『人工智能』  阅读次数:8803 (本文『Python运行的17个时新手常见错误 ...

  2. VS编译时一些常见错误积累LNK,比如LNK2019、LNK2001(实时更新)

    1. lnk2019 LNK2019错误一般是 compile 能找到 header(.h)文件,但是在链接时找不到需要的 lib 库文件或者是 dll 文件. 一般认为在编译 OSG 简单示例的时候 ...

  3. python编辑elif显示错误_Python运行的17个时新手常见错误小结

    1)忘记在 if , elif , else , for , while , class ,def 声明末尾添加 :(导致 "SyntaxError :invalid syntax" ...

  4. [转]在SSIS中,使用“包配置”时的常见错误与解析

    本文转自:http://www.cnblogs.com/invinboy/archive/2008/05/26/1034312.html 在以前的DTS中,在包的开发.测试.发布迁移过程中你必须手动的 ...

  5. 使用 ESP-Prog _ Jlink 进行 JTAG 调试时的常见错误及解决办法

    此篇博客用来记录使用 ESP-PROG / Jlink 来对 ESP32-Lyrat 进行 JTAG 调试时遇到的一些问题以及解决办法.如果对进行 JTAG 相关操作有疑惑,请参考以下资料: 使用 E ...

  6. java ajax 404_java – 在jQuery AJAX中调用Spring控制器时发现404错误

    我是春天的新手.我生成如下的JSON: [ { "customer" : "16", "project" : "19", ...

  7. SQL 数据库还原备份时的常见错误

    1.还原sql数据库时提示"集中备份的数据库与现有数据库不同" 原因:备份的数据库是sqlserver2005,现有数据库是sql2008 解决:通过执行sql语句还原数据库,可以 ...

  8. Spring MVC集成测试:断言给定的模型属性有全局错误

    为了使用Bean验证报告Spring MVC中的全局错误,我们可以创建一个自定义的类级别约束注释. 全局错误与已验证Bean中的任何特定字段都不相关. 在本文中,我将展示如何使用Spring Test ...

  9. Spring MVC错误处理示例

    这篇文章描述了在Spring MVC 3中执行错误处理的不同技术.该代码在GitHub上的Spring-MVC-Error-Handling目录中可用. 它基于带有注释的Spring MVC示例. 在 ...

最新文章

  1. TinyML-TVM是如何驯服Tiny的(上)
  2. Java过滤特殊字符的正则表达式
  3. php xml 增删改查,PHP实现对xml进行简单的增删改查(CRUD)操作示例
  4. 读取CRM 产品主数据所有属性的API
  5. Mysql高级之主从复制
  6. SQL注入漏洞与参数化查询
  7. readlink()不能读取硬链接的目标
  8. 解决谷歌浏览器添加插件时显示程序包无效:“CRX_HEADER_INVALID“
  9. Java提取视频中的音频(JavaCV)
  10. oracle便携智能投影,洁牙设备又添一将!OraCleen S 智能便携牙刷
  11. docker安装和基本命令
  12. 工作十年的程序员,却拿着毕业三年的工资……
  13. XLNet 详解(看不懂你来骂我)
  14. C4D中使用Redshift渲染器翻转贴图
  15. 【P1516】青蛙的约会
  16. java计算机毕业设计在线影视系统源码+数据库+lw文档+系统+部署
  17. 天眼探空经济发展_前沿|“天眼”探空惊艳全球
  18. jQuery实现表单验证
  19. 限量版 情感智能机器人Pepper今天发售了!
  20. 青龙面板-简单获取京东CK

热门文章

  1. JS重写toString(),打印想要的值
  2. php移动代码,移动专区周级收录如何提交 复制这段php代码即可
  3. java泛型程序设计——泛型类的静态上下文中类型变量无效+不能抛出或捕获泛型类的实例
  4. leetcode初级算法4.两个数组的交集 II
  5. drools6.5_Drools 6.5.0.Final可用
  6. gradle入门_Gradle入门:集成测试
  7. 在邮件标头中找到无效的字符_在实践中重试HTTP标头
  8. java 登陆验证失败_使用Java 8流进行快速失败的验证
  9. spring 组件扫描_避免不必要的Spring配置组件扫描
  10. angular java_带有Angular JS的Java EE 7 –第1部分