InitializingBean is executed 2 times in the springmvc project

In order to repair the production data, a one-time piece of code needs to be executed. Since it is an old spring project, I thought of InitializingBean.

code show as below. After the service started, two “one-time task started” entries were found in the log. Fortunately, the logic inside has been controlled to prevent duplication, and it has not been affected.

@Slf4j
@Component
public class TransToBankBean implements InitializingBean {
    @Autowired
    private FixedLdysZhOrdersService xxxService;

    @Override
    public synchronized void afterPropertiesSet() {
        log.info("One-time task starts");
        ....
    }
}

I checked out the program configuration today. Found a problem with web.xml configuration.

<?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><em><strong>contextConfigLocation</strong></em></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><em><strong>contextConfigLocation</strong></em></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>

Notice that there are two contextConfigLocations in the web.xml above, one is located in the context-param parameter, and the other is located in the init-param parameter of servelt.

The problem occurs in this contextConfigLocation.

contextConfigLocation, as its name implies, refers to the location of the context configuration (file).
The contextConfig of servelt/init-param is for loading DispatcherServlet, and the contextConfig of context-param is for loading the database and other configurations that the web program needs to load.

Let’s talk about servlet node configuration:
Servlet has several attributes: servlet-name, servlet-class, init-param. Among them, servlet-class is usually what we know as DispatcherServlet. contextConfigLocation can be specified in init-param.
1) If contextConfigLocation is not configured in init-param, the program is required to have a configuration file named [servlet-name]-servlet.xml in WEB-INF. Otherwise, an exception will be reported when the program starts: java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/SpringMVC-servlet.xml]. (Note: The value of my servlet-name here is SpringMVC, so the file name will be SpringMVC-servlet.xml)
2) If there is contextConfigLocation configuration in init-param, DispatcherServlet will use this specified configuration file as the configuration. For example, the parameter value I specified is classpath:spring-mvc.xml. This file is defined under main/resources and exists in the classes directory of the package after compilation.

Obviously, both contextConfigLocation in the above web.xml specify spring-mvc.xml. The component-scan package scan path is specified in this context file.
The InitializingBean implementation class defined above is under these packages. Therefore, it is not difficult to understand that the afterPropertiesSet overridden by this class will be executed twice.

Okay, I understand the above explanation. Then, we know how to change it. ——>Separate configuration to solve the problem of scanning twice.
The modified web.xml is as follows. The two contextConfigLocations specify application-context.xml and spring-mvc.xml respectively. Both perform their own duties —–> application-context.xml is the context configuration of the spring application and does not contain springmvc configuration; spring-mvc.xml only has springmvc configuration.

<?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">

    <!-- The annotation driver has been expanded to bind request parameters to controller parameters -->
    <mvc:annotation-driven/>

    <mvc:default-servlet-handler/>

    <!-- The package where the controller is located -->
    <context:component-scan base-package="com.levy.rpcprovider.controller"/>

</beans>