Spring @Async

spring 的 @Async注解,通过AsyncExecutionInterceptor实现。

/*
 * Copyright 2002-2013 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.aop.interceptor;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.AopUtils;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.Ordered;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
 * AOP Alliance {@code MethodInterceptor} that processes method invocations
 * asynchronously, using a given {@link org.springframework.core.task.AsyncTaskExecutor}.
 * Typically used with the {@link org.springframework.scheduling.annotation.Async} annotation.
 *
 * <p>In terms of target method signatures, any parameter types are supported.
 * However, the return type is constrained to either {@code void} or
 * {@code java.util.concurrent.Future}. In the latter case, the Future handle
 * returned from the proxy will be an actual asynchronous Future that can be used
 * to track the result of the asynchronous method execution. However, since the
 * target method needs to implement the same signature, it will have to return
 * a temporary Future handle that just passes the return value through
 * (like Spring's {@link org.springframework.scheduling.annotation.AsyncResult}
 * or EJB 3.1's {@code javax.ejb.AsyncResult}).
 *
 * <p>As of Spring 3.1.2 the {@code AnnotationAsyncExecutionInterceptor} subclass is
 * preferred for use due to its support for executor qualification in conjunction with
 * Spring's {@code @Async} annotation.
 *
 * @author Juergen Hoeller
 * @author Chris Beams
 * @since 3.0
 * @see org.springframework.scheduling.annotation.Async
 * @see org.springframework.scheduling.annotation.AsyncAnnotationAdvisor
 * @see org.springframework.scheduling.annotation.AnnotationAsyncExecutionInterceptor
 */
public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport
  implements MethodInterceptor, Ordered {
 /**
  * Create a new {@code AsyncExecutionInterceptor}.
  * @param executor the {@link Executor} (typically a Spring {@link AsyncTaskExecutor}
  * or {@link java.util.concurrent.ExecutorService}) to delegate to.
  */
 public AsyncExecutionInterceptor(Executor executor) {
  super(executor);
 }
 /**
  * Intercept the given method invocation, submit the actual calling of the method to
  * the correct task executor and return immediately to the caller.
  * @param invocation the method to intercept and make asynchronous
  * @return {@link Future} if the original method returns {@code Future}; {@code null}
  * otherwise.
  */
 public Object invoke(final MethodInvocation invocation) throws Throwable {
  Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
  Method specificMethod = ClassUtils.getMostSpecificMethod(invocation.getMethod(), targetClass);
  specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
  AsyncTaskExecutor executor = determineAsyncExecutor(specificMethod);
  if (executor == null) {
   throw new IllegalStateException(
     "No executor specified and no default executor set on AsyncExecutionInterceptor either");
  }
  Future<?> result = executor.submit(
    new Callable<Object>() {
     public Object call() throws Exception {
      try {
       Object result = invocation.proceed();
       if (result instanceof Future) {
        return ((Future<?>) result).get();
       }
      }
      catch (Throwable ex) {
       ReflectionUtils.rethrowException(ex);
      }
      return null;
     }
    });
  if (Future.class.isAssignableFrom(invocation.getMethod().getReturnType())) {
   return result;
  }
  else {
   return null;
  }
 }
 /**
  * This implementation is a no-op for compatibility in Spring 3.1.2.
  * Subclasses may override to provide support for extracting qualifier information,
  * e.g. via an annotation on the given method.
  * @return always {@code null}
  * @see #determineAsyncExecutor(Method)
  * @since 3.1.2
  */
 @Override
 protected String getExecutorQualifier(Method method) {
  return null;
 }
 public int getOrder() {
  return Ordered.HIGHEST_PRECEDENCE;
 }
}

 

   配置task

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

    <!-- 启动async注解,仅仅为了测试-->
    <!--<task:annotation-driven/>-->
    <task:annotation-driven executor="myExecutor"/>
    <task:executor id="myExecutor" pool-size="5"/>
    <!--<bean id="simpleAsyncTaskExecutor"-->
    <!--class="org.springframework.core.task.SimpleAsyncTaskExecutor">-->
    <!--<property name="daemon" value="true" />-->
    <!--<property name="concurrencyLimit" value="2" />-->
    <!--<property name="threadNamePrefix" value="simpleAsyncTaskExecutor" />-->
    <!--</bean>-->
    <!--<task:annotation-driven executor="simpleAsyncTaskExecutor" />-->
    <!-- 配置线程池 -->
    <!--<bean id ="threadPoolTaskExecutor"  class ="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor" >-->
    <!--&lt;!&ndash; 线程池维护线程的最少数量 &ndash;&gt;-->
    <!--<property name ="corePoolSize" value ="5" />-->
    <!--&lt;!&ndash; 线程池维护线程所允许的空闲时间 &ndash;&gt;-->
    <!--<property name ="keepAliveSeconds" value ="30000" />-->
    <!--&lt;!&ndash; 线程池维护线程的最大数量 &ndash;&gt;-->
    <!--<property name ="maxPoolSize" value ="10" />-->
    <!--&lt;!&ndash; 线程池所使用的缓冲队列 &ndash;&gt;-->
    <!--<property name ="queueCapacity" value ="200" />-->
    <!--</bean>-->
    <!--<task:annotation-driven executor="threadPoolTaskExecutor" />-->
</beans>

 

  在web.xml配置

 <!--root context, Creates the Spring Container shared by all Servlets and Filters -->
    <!--Beans in a parent context are accessible through and by the child context, but the reverse isn't true.-->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:applicationContext-mybatis.xml,classpath*:applicationContext-task.xml</param-value>
    </context-param>
    <!--child context of root context, for dispatch servlet, Processes application requests -->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath*:applicationContext-web.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <async-supported>true</async-supported>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

   如果出现async失效,则应该注意下task是否放到子context里面去了,应该放到root context声明。

 

1、controller

 @RequestMapping("/async")
    @ResponseBody
    public String testAsync(){
        for(int i=0;i<10;i++){
            asyncService.testAsync();
//            asyncService.rightAsync();
//            asyncService.poolAsync();
        }
        logger.info("main end");
        return "ok";
    }

2、service

package com.yami.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
 * async示例
 * @author scipio
 * @created 2014-03-08
 */
@Service
public class AsyncService {
    private static Logger logger = LoggerFactory.getLogger(AsyncService.class);
    @Resource
    private ProductService productService;
    private ExecutorService executor = Executors.newFixedThreadPool(5);
    public void poolAsync(){
       for(int i=0;i<10;i++){
           executor.submit(new Runnable() {
               @Override
               public void run() {
                   oneExecute();
               }
           });
       }
    }
    private int oneExecute(){
        logger.info("I Will be formatting html mail and sending it");
        try {
            Thread.sleep(5*1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        productService.getProduct("abcd");
        logger.info("Asynchronous method call of send email — Complete");
        return 1;
    }

    @Async
    public void testAsync(){
        oneExecute();
    }
}

你可能感兴趣的:(Spring @Async)