springmvc项目中InitializingBean执行2次
为了修复生产数据,需要执行一段一次性的代码。 鉴于是spring老项目,就想到了InitializingBean。
代码如下。服务启动后,log里发现出现2条“一次性任务开始”。 好在里面逻辑做了防重控制,没有受到什么影响。
@Slf4j @Component public class TransToBankBean implements InitializingBean { @Autowired private FixedLdysZhOrdersService xxxService; @Override public synchronized void afterPropertiesSet() { log.info("一次性任务开始"); .... } }
今天理了一下程序配置。发现web.xml配置有问题。
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml,classpath:spring-mybatis.xml,classpath:spring-dubbo.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <listener> <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class> </listener> <servlet> <servlet-name>SpringMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> <async-supported>true</async-supported> </servlet> <servlet-mapping> <servlet-name>SpringMVC</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>/index.jsp</welcome-file> </welcome-file-list> </web-app>
注意到上面web.xml中有两个contextConfigLocation, 一个位于context-param参数中, 另一个位于servelt的init-param参数中。
问题就出现在这个contextConfigLocation上。
contextConfigLocation,名如其义,指的是context配置(文件)的位置。
servelt/init-param的contextConfig是为了加载DispatcherServlet的, 而context-param的contextConfig是为了加载web程序需要加载的数据库等等配置。
再来说说servlet节点配置:
servlet有这么几个属性:servlet-name、servlet-class、init-param。其中,servlet-class通常就是我们熟知的 DispatcherServlet。init-param中可以指定contextConfigLocation。
1) init-param里如果未配置contextConfigLocation,则要求程序在WEB-INF存在名为[servlet-name]-servlet.xml的配置文件,否则程序启动会报异常:java.io.FileNotFoundException:Could not open ServletContext resource [/WEB-INF/SpringMVC-servlet.xml] 。(注意:我这里servlet-name的值是SpringMVC,所以文件名字会是 SpringMVC-servlet.xml)
2) init-param里如果有contextConfigLocation配置,则DispatcherServlet会使用这个指定的配置文件作为配置。例如,我指定的参数值是classpath:spring-mvc.xml, 这个文件定义在main/resources下,编译后存在于程序包的classes目录中。
显然,上面web.xml中两个contextConfigLocation都指定了spring-mvc.xml。这个context文件里指定了component-scan包扫描路径。
上面定义的InitializingBean实现类就在这些package下面。所以,不难理解,这个类所覆写的afterPropertiesSet会被执行两次。
好,了解了上面的解释。那么,我们就知道该怎么改了。------>分离配置,解决扫描两遍的问题。
改造后的web.xml如下, 两处contextConfigLocation分别指定的是application-context.xml 和 spring-mvc.xml。两者各司其职 -----> application-context.xml是spring应用程序的上下文配置,不含springmvc配置; spring-mvc.xml中只有springmvc配置。
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:application-context.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <listener> <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class> </listener> <servlet> <servlet-name>SpringMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> <async-supported>true</async-supported> </servlet> <servlet-mapping> <servlet-name>SpringMVC</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>/index.jsp</welcome-file> </welcome-file-list> </web-app>
spring-mvc.xml
<?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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 扩充了注解驱动,可以将请求参数绑定到控制器参数 --> <mvc:annotation-driven/> <mvc:default-servlet-handler/> <!-- controller所在包--> <context:component-scan base-package="com.levy.rpcprovider.controller"/> </beans>
当看到一些不好的代码时,会发现我还算优秀;当看到优秀的代码时,也才意识到持续学习的重要!--buguge
本文来自博客园,转载请注明原文链接:https://www.cnblogs.com/buguge/p/16286630.html