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" >--> <!--<!– 线程池维护线程的最少数量 –>--> <!--<property name ="corePoolSize" value ="5" />--> <!--<!– 线程池维护线程所允许的空闲时间 –>--> <!--<property name ="keepAliveSeconds" value ="30000" />--> <!--<!– 线程池维护线程的最大数量 –>--> <!--<property name ="maxPoolSize" value ="10" />--> <!--<!– 线程池所使用的缓冲队列 –>--> <!--<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(); } }