【问题标题】:Async not working异步不工作
【发布时间】:2015-09-23 09:21:05
【问题描述】:

您好,我在异步发送电子邮件时遇到问题。我已经按照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();
    }

即使我将其更改为返回 Future,它仍然需要 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>   

尝试使用指向 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)

【问题讨论】:

  • 你是怎么想到延迟 2 秒的?
  • 在我的控制器中查看系统输出。
  • 您指定了哪个TaskExecutor?您是否将 @EnableAsync 添加到您的配置中?
  • 由于 while 循环 (while (!(sendEmail.isDone()))) 需要 2 秒。

标签: java spring spring-mvc asynchronous


【解决方案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);
        }

让我知道。

【讨论】:

  • 好的,所以 5 秒睡眠需要 7 秒。然后我更改为返回一个页面并添加了 while 循环,但仍然需要 7 秒(更新了问题)。
  • 哦,对不起,这就是我这个问题的意思。
  • 好的,然后在主帖中发布您的配置和 web.xml。
  • 好的,首先,将帖子的主题更改为“异步不工作”。其次,在您的 web.xml 中,您必须为所有过滤器声明 true。最后,您已经声明了一个任务池。在您的异步方法中,请参阅任务执行器。
【解决方案2】:

在我的例子中,我在同一个服务中调用异步方法,它没有机会在 spring 之前在同一个类中添加代理类。

Spring Async 的必需配置

  1. @EnableAsync 与 @Configuration
  2. @Async 在公共方法上
  3. 不应在同一个班级内调用

【讨论】:

    【解决方案3】:

    看 sn-p 好像是缺少异步设置。我想添加 @EnableAsync 注释,可能会解决问题。

    @EnableAsync
    @Service
    public class EmailService 
    

    【讨论】:

    • 不,只有当你有@Configuration注解时才需要EnableAsync。
    • 尝试运行时不会抛出异常。
    • 你遇到了什么异常?我想这有助于解决您的问题
    • 不要在您的服务层类上使用该注释。
    【解决方案4】:

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

    看你给的网址,有一句话说

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

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

    【讨论】:

    • 但是 sendEmail 方法是无效的,肯定不需要 FUture 吗?
    • 好吧,如果你认为它不需要返回值。然后您可以使用java.lang.Void 类作为类型。我的意思是,像这样Future&lt;java.lang.Void&gt;
    【解决方案5】:

    好吧,我想通了。

    我把 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)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-07-13
      • 2018-05-20
      • 2023-03-31
      • 1970-01-01
      相关资源
      最近更新 更多