2012-11-29 30 views
2

幾個月前,我發明了一個簡單的應用程序,只是爲了每天晚上發送郵件給我的用戶,如果發現數據庫中的某些標準。我使用Spring 3.1.0和Quartz 1.8.5來完成這個任務;到現在爲止還挺好。爲什麼每次訪問servlet時,我的Spring應用程序上下文都會重新加載?

該應用程序部署在weblogic服務器中。

上週,我被要求修改應用程序以允許手動命令它通過URL運行。

我向它添加了一個servlet,它工作正常:每次有人調用URL時,應用程序都會運行。

但是出現了一個副作用 - 每個servlet調用也會引發重新加載spring上下文,並創建另一個Quartz實例。所以,如果所說的servlet被調用了n次,我的應用程序會在Quartz激發我的工作時發送n + 1個重複的電子郵件,而不是隻有1個。

我想了解爲什麼會發生這種情況以及如何解決此問題。請問你能幫幫我嗎?

以下是我的問題的相關文件。

日誌文件摘錄,包括應用程序的啓動:發生每次該servlet稱爲

28/11/2012 16:37:48 org.springframework.web.context.ContextLoader initWebApplicationContext 
INFO: Root WebApplicationContext: initialization started 
28/11/2012 16:37:48 org.springframework.context.support.AbstractApplicationContext prepareRefresh 
INFO: Refreshing Root WebApplicationContext: startup date [Wed Nov 28 16:37:48 BRST 2012]; root of context hierarchy 
28/11/2012 16:37:48 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 
INFO: Loading XML bean definitions from URL [file:/C:/bea/user_projects/workspaces/app/target/app-1.0.0/WEB-INF/classes/app-context.xml] 
28/11/2012 16:37:48 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 
INFO: Loading XML bean definitions from class path resource [app-data-context.xml] 
28/11/2012 16:37:48 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 
INFO: Loading XML bean definitions from class path resource [app-scheduler.xml] 
28/11/2012 16:37:48 org.springframework.core.io.support.PropertiesLoaderSupport loadProperties 
INFO: Loading properties file from class path resource [app.properties] 
28/11/2012 16:37:48 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons 
INFO: Pre-instantiating singletons in org.s[email protected]599bcd: defining beans [org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#0,appDS,job,cronTrigger,org.springframework.scheduling.quartz.SchedulerFactoryBean#0,appDAO,appService,mailerService,appTask, (...)]; root of factory hierarchy 
28/11/2012 16:37:50 org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup start 
INFO: Starting beans in phase 2147483647 

**28/11/2012 16:37:50 org.springframework.scheduling.quartz.SchedulerFactoryBean startScheduler 
INFO: Starting Quartz Scheduler now** 

28/11/2012 16:37:50 org.springframework.web.context.ContextLoader initWebApplicationContext 
INFO: Root WebApplicationContext: initialization completed in 2109 ms 

日誌文件摘錄:

<28/11/2012 16h37min50s BRST> <Notice> <WebLogicServer> <BEA-000360> <Server started in RUNNING mode> 
28/11/2012 16:39:06 org.springframework.context.support.AbstractApplicationContext prepareRefresh 
INFO: Refreshing org[email protected]11f7458: startup date [Wed Nov 28 16:39:06 BRST 2012]; root of context hierarchy 
28/11/2012 16:39:06 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 
INFO: Loading XML bean definitions from class path resource [app-context.xml] 
28/11/2012 16:39:06 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 
INFO: Loading XML bean definitions from class path resource [app-data-context.xml] 
28/11/2012 16:39:06 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 
INFO: Loading XML bean definitions from class path resource [app-scheduler.xml] 
28/11/2012 16:39:06 org.springframework.core.io.support.PropertiesLoaderSupport loadProperties 
INFO: Loading properties file from class path resource [app.properties] 
28/11/2012 16:39:06 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons 
INFO: Pre-instantiating singletons in org.s[email protected]10ca001: defining beans [(...)]; root of factory hierarchy 
28/11/2012 16:39:06 org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup start 
INFO: Starting beans in phase 2147483647 
**28/11/2012 16:39:06 org.springframework.scheduling.quartz.SchedulerFactoryBean startScheduler 
INFO: Starting Quartz Scheduler now** 

web.xml中:

<?xml version="1.0" encoding="UTF-8"?> 
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
    version="2.5"> 

    <description>generic web.xml</description> 

    <!-- ====================================== --> 
    <!--    SPRING     --> 
    <!-- ====================================== --> 
    <!-- Loading Application Bean's. --> 
    <context-param> 
     <param-name>contextConfigLocation</param-name> 
     <param-value>classpath*:app-context.xml</param-value> 
    </context-param> 

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

    <servlet> 
     <display-name>appServlet</display-name> 
     <servlet-name>appServlet</servlet-name> 
     <servlet-class>br.com.app.publicInterface.appServlet</servlet-class> 
    </servlet> 
    <servlet-mapping> 
     <servlet-name>appServlet</servlet-name> 
     <url-pattern>/appServlet</url-pattern> 
    </servlet-mapping> 

</web-app> 

app-context.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:context="http://www.springframework.org/schema/context" 
    xsi:schemaLocation=" 
     http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
     http://www.springframework.org/schema/context 
     http://www.springframework.org/schema/context/spring-context-3.0.xsd"> 

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
     <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" /> 
     <property name="locations"> 
      <list> 
       <value>classpath:app.properties</value> 
      </list> 
     </property> 
    </bean> 

    <import resource="classpath:app-data-context.xml"/> 
    <import resource="classpath:app-scheduler.xml"/> 

    <!-- DAOs --> 
    <!-- Services --> 
    <!-- tasks --> 

</beans> 

APP-scheduler.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" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> 

    <bean name="job" class="org.springframework.scheduling.quartz.JobDetailBean"> 
     <property name="jobClass" value="br.com.app.job.QuartzJob" /> 
     <property name="jobDataAsMap"> 
      <map> 
       <entry key="gerenciadorTasks"> 
        <ref bean="gerenciadorTasks" /> 
       </entry> 
      </map> 
     </property> 
    </bean> 

    <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> 
     <property name="jobDetail" ref="job" /> 
     <property name="cronExpression" value="${quartz.cronExpression}" /> 
    </bean> 

    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> 
     <property name="quartzProperties"> 
      <props> 
       <prop key="org.quartz.scheduler.skipUpdateCheck">true</prop> 
       <prop key="org.quartz.jobStore.isClustered">true</prop> 
       <prop key="org.quartz.scheduler.instanceName">NotificadorQuartzScheduler</prop> 
       <prop key="org.quartz.scheduler.instanceId">AUTO</prop> 
      </props> 
     </property> 
     <property name="triggers"> 
      <list> 
       <ref bean="cronTrigger" /> 
      </list> 
     </property> 
    </bean> 

</beans> 

AppServlet源代碼:

public class AppServlet extends HttpServlet { 

    private static final long serialVersionUID = 7213474106234238692L; 

    @Override 
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 

     PrintWriter out = resp.getWriter(); 

     out.println("execução iniciada em: " + new Date()); 
     ApplicationContext context = new ClassPathXmlApplicationContext("classpath:app-context.xml"); 
     GerenciadorTasks gt = (GerenciadorTasks) context.getBean(SpringNameBeans.GERENCIADOR_TASKS); 
     gt.init(); 
     out.println("execução terminada em: " + new Date()); 

    } 

} 

非常感謝您的寶貴時間。

解決方案

---以下@Boris信息,我改變了我的servlet一點。已經加載,我只需要我的情況下對其進行訪問:

public class AppServlet extends HttpServlet { 

    private static final long serialVersionUID = 7213474106234238692L; 

    ApplicationContext applicationContext = null; 

    @Override 
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 

     PrintWriter out = resp.getWriter(); 

     out.println("execução iniciada em: " + new Date()); 
     if (applicationContext == null){ 
       applicationContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext()); 
     } 
     GerenciadorTasks gt = (GerenciadorTasks) applicationContext.getBean(SpringNameBeans.GERENCIADOR_TASKS); 
     gt.init(); 
     out.println("execução terminada em: " + new Date()); 

    } 

} 
+0

br.com.app.publicInterface.appServlet的來源是什麼?它如何與彈簧結合? servlet生命週期方法等? –

+0

@BorisTreukhov,我會在問題中添加appServlet源代碼。感謝您的關注。 –

回答

2

在你的代碼,你在每創建一個新的應用程序上下文GET方法,您應在servlet初始化創建上下文()mehod,或者使用Web應用程序根目錄contet代替:

public class AppServlet extends HttpServlet { 

@Autowired 
ApplicationContext applicationContext; 

@Override 
public void init(ServletConfig arg0) throws ServletException { 
    WebApplicationContextUtils.getWebApplicationContext(arg0.getServletContext()) 
     .getAutowireCapableBeanFactory().autowireBean(this); 
} 

@Override 
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 

     PrintWriter out = resp.getWriter(); 

     out.println("execução iniciada em: " + new Date()); 

     GerenciadorTasks gt = (GerenciadorTasks) this.applicationContext.getBean(SpringNameBeans.GERENCIADOR_TASKS); 
     gt.init(); 
     out.println("execução terminada em: " + new Date()); 

    } 
} 

目前尚不清楚,如果你的GerenciadorTasks是單身或不那麼我的回答我用getBean()方法,而不是自動連接。 在每個GET請求上調用init()是不太可能的,你想要做的事情是。 還請注意root web app context您的配置中已創建了

<context-param> 
     <param-name>contextConfigLocation</param-name> 
     <param-value>classpath*:app-context.xml</param-value> 
    </context-param> 

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

如果你想使用調度春季考慮使用the respective API

因此,我認爲僅使用根網絡應用程序上下文僅適用於調度api即可。也請看Spring lifecyle beans

+0

感謝您的真棒和完整的答覆 - 它顯示我的錯誤。此外,感謝這些鏈接,它們包含有價值的信息。我以類似於你的主張的方式解決了這個問題。我將把我的問題中的新servlet代碼放在其他人的利益之下並關閉問題。 –

+0

注意:GerenciadorTasks的初始化方法是我的一種方法,不是某個API的一種,像Servlet的那種 - 只是在應用程序環境之外引起誤解的名稱:) –

相關問題