异步无法正常工作

时间:2015-09-23 09:21:06

标签: java spring spring-mvc asynchronous

您好我在异步发送电子邮件时遇到问题。我按照this tutorial.

中的说明设置了所有内容

我已使用@Service注释了我的电子邮件服务,将其设置为bean,并使用@Async注释该方法。

然后我将@Autowired服务到控制器并使用该方法。虽然它不会异步执行,但需要两秒钟才能超过emailSerivce.sendMail();

任何想法我做错了什么?

我的电子邮件服务设置如下。

 @Service
    public class EmailService {

    //get log4j handler
    private static final Logger logger = Logger.getLogger(EmailService.class);

    // Sends an email with the following parameters
    @Async
    public Future<Page> sendEmail(CustomPropertiesForm cpf, String [] recipients, MimeBodyPart attachment, String subject, String content){

        // Initialise local variables
        Boolean success = false;
        Boolean isAuthenticationRequired = false;
        String smtpAuthUsername = null;
        String smtpAuthPassword = null;

        try{
             Thread.sleep(5000);
            logger.info("Sending Email");

            // Build properties
            Properties props = new Properties();

            if(cpf.getSmtpAuthenticationRequired().equals("YES")){
                isAuthenticationRequired = true;
                props.put("mail.smtp.auth", "true");
                smtpAuthUsername = cpf.getSmtpAuthUsername();
                smtpAuthPassword = cpf.getSmtpAuthPassword();
            } else {
                props.put("mail.smtp.auth", "false");
            }

            if (cpf.getSmtpSSLRequired().equalsIgnoreCase("YES")) {
                //- See more at: http://www.jvmhost.com/articles/how-to-send-mail-with-javamail-and-tomcat#sthash.3IN3wreU.dpuf
                props.put("mail.smtp.ssl.enable", "true");     
                props.put("mail.transport.protocol", cpf.getSmtpProtocol());
                props.put("mail.smtps.port", cpf.getSmtpHostPort());
                props.put("mail.smtps.ssl.trust", cpf.getSmtpHostName()); 
            } else {
                props.put("mail.smtp.ssl.enable", "false");                
            }


            props.put("mail.smtp.host", cpf.getSmtpHostName());
            props.put("mail.smtp.port", cpf.getSmtpHostPort());
            props.put("mail.transport.protocol", cpf.getSmtpProtocol());

            // Create mail Session
            Session mailSession = Session.getDefaultInstance(props);
            mailSession.setDebug(false);    
            Transport transport = mailSession.getTransport();

            // Create Message
            MimeMessage message = new MimeMessage(mailSession);

            // Add recipients
            for(String string : recipients){
                message.addRecipient(Message.RecipientType.TO,new InternetAddress(string));
            }

            // Set From Address
            message.setFrom(new InternetAddress(cpf.getDefaultApplicationEmailAddress()));

            // Set subject
            message.setSubject(subject);            
            // Set content
            MimeBodyPart mbpText = new MimeBodyPart();
            mbpText.setText(content);

            MimeMultipart mp = new MimeMultipart();
            mp.addBodyPart(mbpText);        

            message.setContent(mp);            

            // Add attachment
            if(attachment != null){    
                mp.addBodyPart(attachment);
            }

            // Connect to mail server and send email
            if(isAuthenticationRequired){
                transport.connect(cpf.getSmtpHostName(), Integer.parseInt(cpf.getSmtpHostPort()), smtpAuthUsername, smtpAuthPassword);
                transport.sendMessage(message, message.getRecipients(Message.RecipientType.TO));
                transport.close();                   
            } else {
                transport.connect();
                transport.sendMessage(message, message.getRecipients(Message.RecipientType.TO));
                transport.close();  
            }

            success = true;
            logger.info("Email Sent");

        } catch (Exception e){
            logger.error(e.getMessage() + " " + e.getCause() + " " + e.fillInStackTrace());    
            System.out.println(e.getMessage() + " " + e.getCause() + " " + e.fillInStackTrace());
        }
    }    
    Page result = new Page();
    result.setName("name");
    result.setWebsite("website.com");
    return new AsyncResult<Page>(result);   
}

在我的调度程序servlet中,我将其设置为bean,

<bean id="emailService"
      class="ie.premiumpower.services.EmailService">
</bean>   

然后我从我的控制器中使用这个电子邮件服务,

@Controller
public class NotSecureController extends AbstractController {

@Autowired
private EmailService emailService;

@RequestMapping("notsecure/taskSummary/shareTaskSummary.json")
public String getQuestions(
        @RequestParam("taskInstanceId") int taskInstanceId,
        @RequestParam("emailAdresses[]") String emailAddresses[]) {


try {
        long currTime = System.currentTimeMillis();
        System.out.println("Email being sent at time: " + currTime);

        Future<Page> sendEmail = emailService.sendEmail(cpf, emailAddresses, null, subject, content);
        while (!(sendEmail.isDone())) {
            Thread.sleep(10);
        }
        long aftTime = System.currentTimeMillis();
        aftTime = aftTime - currTime;
        System.out.println("Email finished being sent in time: " + aftTime);
        System.out.println(": " + sendEmail.get());
    } catch (Exception e) {
        System.out.println("Exception: " + e.getMessage());
        e.printStackTrace();
    }

即使我改变它以返回未来,它仍然需要7秒(带睡眠)。

我的web.xml

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

<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>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml
        /WEB-INF/spring-security.xml  
    </param-value>
</context-param>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
    <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>           
<resource-ref>
    <description>ArcFlashMap DB Connection</description>
    <res-ref-name>jdbc/AFM_DB</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref>    
<servlet>
    <servlet-name>LoadResourcesServlet</servlet-name>
    <servlet-class>ie.premiumpower.services.reports.common.LoadResourcesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>2</load-on-startup>
</servlet>
<servlet>
    <servlet-name>rest</servlet-name>            
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>rest</servlet-name>
    <url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>*.do</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>*.json</url-pattern>
</servlet-mapping>
<session-config>
    <session-timeout>
        -1
    </session-timeout>
</session-config>

我的applicationContext.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:task="http://www.springframework.org/schema/task"
   xmlns:p="http://www.springframework.org/schema/p"
   xmlns:aop="http://www.springframework.org/schema/aop"
   xmlns:context="http://www.springframework.org/schema/context"
   xmlns:tx="http://www.springframework.org/schema/tx"
   xmlns:mvc="http://www.springframework.org/schema/mvc"
   xmlns:util="http://www.springframework.org/schema/util"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
   http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 
   http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
   http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd 
   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">


<context:annotation-config />    
<mvc:annotation-driven /> 
<mvc:interceptors>
    <bean id="webContentInterceptor" 
          class="org.springframework.web.servlet.mvc.WebContentInterceptor">
        <property name="cacheSeconds" value="0"/>
        <property name="useExpiresHeader" value="true"/>
        <property name="useCacheControlHeader" value="true"/>
        <property name="useCacheControlNoStore" value="true"/>
    </bean>
</mvc:interceptors>

<task:annotation-driven executor="executor" />
<task:executor id="executor" pool-size="7"/>

我的dispatcher-servlet.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:p="http://www.springframework.org/schema/p"
   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">



<context:component-scan base-package="ie.premiumpower.controllers" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
    <property name="prefix" value="/WEB-INF/jsp/" />
    <property name="suffix" value=".jsp" />
</bean>

<bean id="jsonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
        <list>
            <ref bean="jsonHttpMessageConverter"/>
        </list>
    </property>
</bean>

<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <property name="mediaTypes">
        <map>
            <entry key="json" value="application/json"/>
        </map>
    </property>
    <property name="defaultViews">
        <list>
            <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
                <property name="prefixJson" value="false"/>
            </bean>
        </list>
    </property>
</bean>

<bean id="messageSource"
      class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basename" value="classpath:messages" />
    <property name="defaultEncoding" value="UTF-8"/>
</bean>

<bean id="localeChangeInterceptor"
      class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
    <property name="paramName" value="lang" />
</bean>

<bean id="localeResolver"
      class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
    <property name="defaultLocale" value="en"/>
</bean>

<bean id="handlerMapping"
      class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
    <property name="interceptors">
        <ref bean="localeChangeInterceptor" />
    </property>
</bean>

<bean id="multipartResolver"
      class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!-- one of the properties available; the maximum file size in bytes -->
    <property name="maxUploadSize" value="10000000"/>
</bean>    
<bean id="emailService"
      class="ie.premiumpower.services.EmailService">
</bean>   

尝试使用component-scan pointent将程序运行到ie.premiumpower时出现异常。

        Sep 23, 2015 11:20:02 AM org.apache.catalina.core.StandardContext loadOnStartup
    SEVERE: Servlet /SafeSiteLive threw load() exception
    java.lang.IllegalStateException: Annotation-specified bean name 'emailService' for bean class [ie.premiumpower.services.scheduledTaskServices.EmailService] conflicts with existing, non-compatible bean definition of same name and class [ie.premiumpower.services.EmailService]
        at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.checkCandidate(ClassPathBeanDefinitionScanner.java:274)
        at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(ClassPathBeanDefinitionScanner.java:215)
        at org.springframework.context.annotation.ComponentScanBeanDefinitionParser.parse(ComponentScanBeanDefinitionParser.java:84)
        at org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse(NamespaceHandlerSupport.java:73)
        at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1335)
        at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1325)
        at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:135)
        at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:93)
        at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:493)
        at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:390)
        at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:334)
        at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:302)
        at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:143)
        at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:178)
        at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:149)
        at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:124)
        at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:93)
        at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:130)
        at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:467)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:397)
        at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:442)
        at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:458)
        at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:339)
        at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:306)
        at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:127)
        at javax.servlet.GenericServlet.init(GenericServlet.java:158)
        at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1284)
        at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1197)
        at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1087)
        at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5229)
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5516)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
        at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
        at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
        at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:649)
        at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:672)
        at org.apache.catalina.startup.HostConfig$DeployDescriptor.run(HostConfig.java:1862)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
        at java.util.concurrent.FutureTask.run(FutureTask.java:262)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:745)

4 个答案:

答案 0 :(得分:1)

试试这个:

好的,你可以尝试一件事,通过调用Thread.sleep(5000)让异步线程休眠5秒钟。这样,您就会知道,这不仅仅是创建异步任务需要2秒。如果这没有帮助,那么删除Thread.sleep,并执行以下操作。

如果您想要获得结果,请使用Future标记,如下所述:

    @Async
    public Future<Page> sendEmail(params) throws InterruptedException{
   return new AsyncResult<Page>(your_result);
}

在您的控制器中:

    Future<Page> sendEmail = sendEmail(params);

并检查这种方式,如果他们完成了:

 while (!(sendEmail.isDone() ) {
            Thread.sleep(10);
        }

Lemme知道。

答案 1 :(得分:0)

看看片段,似乎缺少异步设置。我想添加@EnableAsync注释可能会解决问题。

@EnableAsync
@Service
public class EmailService 

答案 2 :(得分:0)

似乎问题是因为您没有指定使用Future类型的返回类型。

查看您提供的网址,有一句话说

  

方法的返回类型是Future而不是Page,这是对任何异步服务的要求。此代码使用AsyncResult的具体实现来包装Facebook查询的结果。

因此,请尝试更改您的退货方式,然后重试。

答案 3 :(得分:0)

好的我知道了。

我将applicationContext更改为此

<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:task="http://www.springframework.org/schema/task"
   xmlns:p="http://www.springframework.org/schema/p"
   xmlns:aop="http://www.springframework.org/schema/aop"
   xmlns:context="http://www.springframework.org/schema/context"
   xmlns:tx="http://www.springframework.org/schema/tx"
   xmlns:mvc="http://www.springframework.org/schema/mvc"
   xmlns:util="http://www.springframework.org/schema/util"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
   http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 
   http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
   http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd 
   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">


<context:annotation-config />
<context:component-scan base-package="ie.premiumpower.services" />      
<mvc:annotation-driven /> 
<mvc:interceptors>
    <bean id="webContentInterceptor" 
              class="org.springframework.web.servlet.mvc.WebContentInterceptor">
        <property name="cacheSeconds" value="0"/>
        <property name="useExpiresHeader" value="true"/>
        <property name="useCacheControlHeader" value="true"/>
        <property name="useCacheControlNoStore" value="true"/>
    </bean>
</mvc:interceptors>

<task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
<task:executor id="myExecutor" pool-size="10" queue-capacity="10"/>
<task:scheduler id="myScheduler" pool-size="10"/>          
<bean id="emailService"
   class="ie.premiumpower.services.EmailService">
</bean>   

将bean放在此处并对打包的服务进行扫描,

我使用@Service注释了我的服务,使用@Async注释了方法。

我公开了@Autowired EmailService(不知道这是否重要)。

最后我获得了Asm库(clib需要)。

(我从dispatcher-servlet中删除了EmailService bean。)