@PostContruct注释方法是否执行两次

时间:2014-11-26 15:28:55

标签: spring annotations

我想在启动时执行一个方法,因为我使用了@PostConstruct注释。完成方法执行后,我在控制台上打印一些文本(以****开头)。现在,当我启动服务器时,它向我显示该文本两次。让我知道这是什么问题。

Web.xml中

<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <welcome-file-list>
        <welcome-file>login.jsp</welcome-file>
    </welcome-file-list>
    <display-name>Spring MVC Application</display-name>

    <!-- Spring MVC -->
    <servlet>
        <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
    </listener>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/mvc-dispatcher-servlet.xml,
            /WEB-INF/spring-security.xml,
        </param-value>
    </context-param>

    <!-- Spring Security -->
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <context-param>
        <param-name>avoidURL</param-name>
        <param-value>/login,/logout</param-value>
    </context-param>

    <session-config>
    <session-timeout>2</session-timeout>
    </session-config>

</web-app>

Spring配置文件:

<beans:beans 
    xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-3.0.3.xsd">

    <beans:bean id="sessionExpirationFilter"
        class="com.springSecurity.common.utils.SessionExpirationFilter">
        <beans:constructor-arg ref="httpSessionSecurityContextRepository" />
        <beans:property name="invalidSessionUrl" value="/login" />
        <beans:property name="sessionExpiredUrl" value="/login" />
    </beans:bean>

    <beans:bean id="httpSessionSecurityContextRepository"
        class="org.springframework.security.web.context.HttpSessionSecurityContextRepository" />


     <http auto-config="false" use-expressions="true">
        <intercept-url pattern="/admin**" access="hasAnyRole('SuperAdmin')" />

        <access-denied-handler error-page="/403" />
        <form-login 
            login-page="/login" 
            default-target-url="/innerOne" 
            authentication-failure-url="/loginfailed"  />
            <!-- username-parameter="username"
            password-parameter="password" -->
        <custom-filter ref="sessionExpirationFilter" after="FILTER_SECURITY_INTERCEPTOR" />
        <session-management invalid-session-url="/login" />
        <logout logout-success-url="/logout"  />
        <!-- <csrf/> -->
    </http>

    <authentication-manager>
        <authentication-provider>
            <password-encoder ref="passwordEncoder" />
            <jdbc-user-service data-source-ref="dataSource"
                users-by-username-query=
                    "select username,password, enabled from user where username=?"
                authorities-by-username-query=
                    "select username, role from user where username=?" />
        </authentication-provider>
    </authentication-manager> 

    <beans:bean
        id="passwordEncoder"
        class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" />  

</beans:beans>

日志:

Nov 26, 2014 8:47:20 PM org.apache.catalina.loader.WebappClassLoader validateJarFile
INFO: validateJarFile(D:\_workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp1\wtpwebapps\SpringSecurityApp\WEB-INF\lib\javax.servlet-api.jar) - jar not loaded. See Servlet Spec 3.0, section 10.7.2. Offending class: javax/servlet/Servlet.class
Nov 26, 2014 8:47:22 PM org.apache.catalina.core.ApplicationContext log
INFO: No Spring WebApplicationInitializer types detected on classpath
Nov 26, 2014 8:47:22 PM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring root WebApplicationContext
log4j:WARN No appenders could be found for logger (org.springframework.web.context.ContextLoader).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
************Run:LRUCache [cacheMap={}]
Nov 26, 2014 8:47:36 PM org.apache.catalina.core.ApplicationContext log
INFO: Set web app root system property: 'webapp.root' = [D:\_workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp1\wtpwebapps\SpringSecurityApp\]
Nov 26, 2014 8:47:36 PM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring FrameworkServlet 'mvc-dispatcher'
************Run:LRUCache [cacheMap={}]
Nov 26, 2014 8:47:49 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-bio-8084"]
Nov 26, 2014 8:47:49 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["ajp-bio-8009"]
Nov 26, 2014 8:47:49 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in 29338 ms

2 个答案:

答案 0 :(得分:0)

这意味着您要创建此类的2个bean实例。

可能你通过XML创建了一个实例,而另一个实例通过@ComponentScan - 这是一个常见的错误,但不一定会发生在你的情况下。

答案 1 :(得分:0)

在Spring Web应用程序中有两种情况。 servlet上下文(或Web应用程序上下文)和根上下文。您在web.xml中配置的ContextLoaderListener是加载根上下文的ContextLoaderListener。 dispatcherServlet是加载servlet上下文的那个。

  • 默认情况下, dispatcherServlet从中加载servlet上下文 由servlet名称命名的文件,后跟&#34; -servlet.xml&#34;。在你的 case servlet的名称是&#34; mvc-dispatcher&#34;因此 servlet上下文将从 mvc-dispatcher-servlet.xml 加载。

  • 默认情况下, ContextLoaderListener从中加载根上下文 文件名为&#34; applicationContext。 XML&#34 ;.但是,在你的情况下,使用 您已指定根上下文的<context-param>属性 从文件中加载&#34; mvc-dispatcher-servlet.xml &#34;和&#34; spring-security.xml &#34;。

以上两点的结果是,mvc-dispatcher-servlet.xml的内容包含在root和servlet上下文中,因此该文件中的每个bean都被创建了两次。

要做的恰当是将spring安全bean放在root上下文中,然后根据它们是否与servlet特定相关而将所有其他bean分开。例如,应该在servlet上下文中定义任何控制器bean。后端bean如服务和daos,虽然它们也可以在servlet上下文中定义,但它们更适合在根上下文中(你可以创建一个applicationContext.xml并将它们放在那里。然后使用ContextLoaderListener而不是mvc) -dispatcher-servlet.xml中)。这样,如果你有一天创建第二个servlet,它也将访问这些bean,因为根上下文中的每个bean都可以从servlet上下文访问。反过来说不起作用,即无法从根上下文访问servlet上下文中的bean。

您还可以查看此帖子,其中介绍了上下文差异What is the difference between ApplicationContext and WebApplicationContext in Spring MVC?