成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

聊聊spring的async注解

Steve_Wang_ / 630人閱讀

摘要:序本文主要聊聊中的注解。這里從獲取注解有個(gè)可以標(biāo)注使用哪個(gè),這里的就是尋找這個(gè)標(biāo)識(shí)。推薦注解指定,然后的返回,讓它去尋找默認(rèn)的自己應(yīng)用里頭都默認(rèn)定義一個(gè)給托管

本文主要聊聊spring中的async注解。

AsyncConfigurer
@EnableAsync(proxyTargetClass = true)
@Configuration
public class AsyncConfig implements AsyncConfigurer{

    private static final Logger LOGGER = LoggerFactory.getLogger(AsyncConfig.class);

    @Override
    public Executor getAsyncExecutor() {
        return null;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new AsyncUncaughtExceptionHandler() {
            @Override
            public void handleUncaughtException(Throwable throwable, Method method, Object... params) {
                LOGGER.error(throwable);
            }
        };
    }
}
getAsyncExecutor

這里討論一下getAsyncExecutor這里定義null的情況。
spring-context-4.3.9.RELEASE-sources.jar!/org/springframework/scheduling/annotation/AbstractAsyncConfiguration.java

@Configuration
public abstract class AbstractAsyncConfiguration implements ImportAware {

    protected AnnotationAttributes enableAsync;

    protected Executor executor;

    protected AsyncUncaughtExceptionHandler exceptionHandler;


    @Override
    public void setImportMetadata(AnnotationMetadata importMetadata) {
        this.enableAsync = AnnotationAttributes.fromMap(
                importMetadata.getAnnotationAttributes(EnableAsync.class.getName(), false));
        if (this.enableAsync == null) {
            throw new IllegalArgumentException(
                    "@EnableAsync is not present on importing class " + importMetadata.getClassName());
        }
    }

    /**
     * Collect any {@link AsyncConfigurer} beans through autowiring.
     */
    @Autowired(required = false)
    void setConfigurers(Collection configurers) {
        if (CollectionUtils.isEmpty(configurers)) {
            return;
        }
        if (configurers.size() > 1) {
            throw new IllegalStateException("Only one AsyncConfigurer may exist");
        }
        AsyncConfigurer configurer = configurers.iterator().next();
        this.executor = configurer.getAsyncExecutor();
        this.exceptionHandler = configurer.getAsyncUncaughtExceptionHandler();
    }

}

這里從AsyncConfigurer獲取executor

AsyncExecutionInterceptor

spring-aop-4.3.9.RELEASE-sources.jar!/org/springframework/aop/interceptor/AsyncExecutionInterceptor.java

/**
     * 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.
     */
    @Override
    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);
        final Method userDeclaredMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);

        AsyncTaskExecutor executor = determineAsyncExecutor(userDeclaredMethod);
        if (executor == null) {
            throw new IllegalStateException(
                    "No executor specified and no default executor set on AsyncExecutionInterceptor either");
        }

        Callable task = new Callable() {
            @Override
            public Object call() throws Exception {
                try {
                    Object result = invocation.proceed();
                    if (result instanceof Future) {
                        return ((Future) result).get();
                    }
                }
                catch (ExecutionException ex) {
                    handleError(ex.getCause(), userDeclaredMethod, invocation.getArguments());
                }
                catch (Throwable ex) {
                    handleError(ex, userDeclaredMethod, invocation.getArguments());
                }
                return null;
            }
        };

        return doSubmit(task, executor, invocation.getMethod().getReturnType());
    }
AsyncExecutionAspectSupport.determineAsyncExecutor

spring-aop-4.3.9.RELEASE-sources.jar!/org/springframework/aop/interceptor/AsyncExecutionAspectSupport.java

**
     * Determine the specific executor to use when executing the given method.
     * Should preferably return an {@link AsyncListenableTaskExecutor} implementation.
     * @return the executor to use (or {@code null}, but just if no default executor is available)
     */
    protected AsyncTaskExecutor determineAsyncExecutor(Method method) {
        AsyncTaskExecutor executor = this.executors.get(method);
        if (executor == null) {
            Executor targetExecutor;
            String qualifier = getExecutorQualifier(method);
            if (StringUtils.hasLength(qualifier)) {
                targetExecutor = findQualifiedExecutor(this.beanFactory, qualifier);
            }
            else {
                targetExecutor = this.defaultExecutor;
                if (targetExecutor == null) {
                    synchronized (this.executors) {
                        if (this.defaultExecutor == null) {
                            this.defaultExecutor = getDefaultExecutor(this.beanFactory);
                        }
                        targetExecutor = this.defaultExecutor;
                    }
                }
            }
            if (targetExecutor == null) {
                return null;
            }
            executor = (targetExecutor instanceof AsyncListenableTaskExecutor ?
                    (AsyncListenableTaskExecutor) targetExecutor : new TaskExecutorAdapter(targetExecutor));
            this.executors.put(method, executor);
        }
        return executor;
    }

@Aync注解有個(gè)value可以標(biāo)注使用哪個(gè)executor,這里的getExecutorQualifier就是尋找這個(gè)標(biāo)識(shí)。

這里如果defaultExecutor為null的話(huà),則獲取找默認(rèn)的executor

/**
     * Retrieve or build a default executor for this advice instance.
     * An executor returned from here will be cached for further use.
     * 

The default implementation searches for a unique {@link TaskExecutor} bean * in the context, or for an {@link Executor} bean named "taskExecutor" otherwise. * If neither of the two is resolvable, this implementation will return {@code null}. * @param beanFactory the BeanFactory to use for a default executor lookup * @return the default executor, or {@code null} if none available * @since 4.2.6 * @see #findQualifiedExecutor(BeanFactory, String) * @see #DEFAULT_TASK_EXECUTOR_BEAN_NAME */ protected Executor getDefaultExecutor(BeanFactory beanFactory) { if (beanFactory != null) { try { // Search for TaskExecutor bean... not plain Executor since that would // match with ScheduledExecutorService as well, which is unusable for // our purposes here. TaskExecutor is more clearly designed for it. return beanFactory.getBean(TaskExecutor.class); } catch (NoUniqueBeanDefinitionException ex) { logger.debug("Could not find unique TaskExecutor bean", ex); try { return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class); } catch (NoSuchBeanDefinitionException ex2) { if (logger.isInfoEnabled()) { logger.info("More than one TaskExecutor bean found within the context, and none is named " + ""taskExecutor". Mark one of them as primary or name it "taskExecutor" (possibly " + "as an alias) in order to use it for async processing: " + ex.getBeanNamesFound()); } } } catch (NoSuchBeanDefinitionException ex) { logger.debug("Could not find default TaskExecutor bean", ex); try { return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class); } catch (NoSuchBeanDefinitionException ex2) { logger.info("No task executor bean found for async processing: " + "no bean of type TaskExecutor and no bean named "taskExecutor" either"); } // Giving up -> either using local default executor or none at all... } } return null; }

如果工程里頭沒(méi)有定義默認(rèn)的task executor的話(huà),則獲取bean的時(shí)候會(huì)拋出NoSuchBeanDefinitionException

AsyncExecutionInterceptor.getDefaultExecutor

spring-aop-4.3.9.RELEASE-sources.jar!/org/springframework/aop/interceptor/AsyncExecutionInterceptor.java

protected Executor getDefaultExecutor(BeanFactory beanFactory) {
        Executor defaultExecutor = super.getDefaultExecutor(beanFactory);
        return (defaultExecutor != null ? defaultExecutor : new SimpleAsyncTaskExecutor());
    }

AsyncExecutionInterceptor重寫(xiě)了getDefaultExecutor方法,先調(diào)用AsyncExecutionAspectSupport的getDefaultExecutor,如果默認(rèn)的找不到,這里new一個(gè)SimpleAsyncTaskExecutor

Executor關(guān)閉問(wèn)題

如果是在AsyncConfigurer定義的executor,沒(méi)有受spring托管,貌似是不會(huì)在spring context關(guān)閉的時(shí)候主動(dòng)shutdown,這個(gè)可能是個(gè)問(wèn)題。

public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
        implements AsyncListenableTaskExecutor, SchedulingTaskExecutor {
        //...
}        

spring-context-4.3.9.RELEASE-sources.jar!/org/springframework/scheduling/concurrent/ExecutorConfigurationSupport.java

public abstract class ExecutorConfigurationSupport extends CustomizableThreadFactory
        implements BeanNameAware, InitializingBean, DisposableBean {

    //...
    /**
     * Perform a shutdown on the underlying ExecutorService.
     * @see java.util.concurrent.ExecutorService#shutdown()
     * @see java.util.concurrent.ExecutorService#shutdownNow()
     * @see #awaitTerminationIfNecessary()
     */
    public void shutdown() {
        if (logger.isInfoEnabled()) {
            logger.info("Shutting down ExecutorService" + (this.beanName != null ? " "" + this.beanName + """ : ""));
        }
        if (this.waitForTasksToCompleteOnShutdown) {
            this.executor.shutdown();
        }
        else {
            this.executor.shutdownNow();
        }
        awaitTerminationIfNecessary();
    }

    /**
     * Wait for the executor to terminate, according to the value of the
     * {@link #setAwaitTerminationSeconds "awaitTerminationSeconds"} property.
     */
    private void awaitTerminationIfNecessary() {
        if (this.awaitTerminationSeconds > 0) {
            try {
                if (!this.executor.awaitTermination(this.awaitTerminationSeconds, TimeUnit.SECONDS)) {
                    if (logger.isWarnEnabled()) {
                        logger.warn("Timed out while waiting for executor" +
                                (this.beanName != null ? " "" + this.beanName + """ : "") + " to terminate");
                    }
                }
            }
            catch (InterruptedException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Interrupted while waiting for executor" +
                            (this.beanName != null ? " "" + this.beanName + """ : "") + " to terminate");
                }
                Thread.currentThread().interrupt();
            }
        }
    }
}        

ExecutorConfigurationSupport實(shí)現(xiàn)了DisposableBean接口,重寫(xiě)了destory方法,在里頭調(diào)用shutdown

因此,最好將ThreadPoolTaskExecutor的定義托管給spring,這樣可以?xún)?yōu)化關(guān)閉。

小結(jié) async注解沒(méi)有指定executor

如果AsyncConfigurer沒(méi)有定義executor,則會(huì)去尋找spring托管的名為taskExecutor的executor,如果沒(méi)有,則拋出NoSuchBeanDefinitionException,返回null,然后由AsyncExecutionInterceptor.getDefaultExecutor去new一個(gè)SimpleAsyncTaskExecutor,不過(guò)這個(gè)不是spring托管的

如果AsyncConfigurer定義了executor,則這個(gè)也不是spring托管的

不是spring托管的executor,需要自己額外去監(jiān)聽(tīng)事件,然后優(yōu)雅關(guān)閉

async注解指定executor

比如

@Async("myTaskExecutor")
public void xxxx(){
    
}

這個(gè)則使用指定的myTaskExecutor,而不是AsyncConfigurer中定義的executor。

推薦async注解指定task executor,然后AsyncConfigurer的getAsyncExecutor返回null,讓它去尋找默認(rèn)的taskExecutor(自己應(yīng)用里頭都默認(rèn)定義一個(gè)taskExecutor給spring托管)

doc

Task Execution and Scheduling

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/70551.html

相關(guān)文章

  • 聊聊Dubbo - Dubbo可擴(kuò)展機(jī)制實(shí)戰(zhàn)

    摘要:今天我想聊聊的另一個(gè)很棒的特性就是它的可擴(kuò)展性。的擴(kuò)展機(jī)制在的官網(wǎng)上,描述自己是一個(gè)高性能的框架。接下來(lái)的章節(jié)中我們會(huì)慢慢揭開(kāi)擴(kuò)展機(jī)制的神秘面紗。擴(kuò)展擴(kuò)展點(diǎn)的實(shí)現(xiàn)類(lèi)。的定義在配置文件中可以看到文件中定義了個(gè)的擴(kuò)展實(shí)現(xiàn)。 摘要: 在Dubbo的官網(wǎng)上,Dubbo描述自己是一個(gè)高性能的RPC框架。今天我想聊聊Dubbo的另一個(gè)很棒的特性, 就是它的可擴(kuò)展性。 Dubbo的擴(kuò)展機(jī)制 在Dub...

    techstay 評(píng)論0 收藏0
  • SpringCloud(第 047 篇)注解Async配置異步任務(wù)

    摘要:耗時(shí)毫秒耗時(shí)毫秒耗時(shí)毫秒添加異步任務(wù)控制器測(cè)試異步任務(wù)控制器。 SpringCloud(第 047 篇)注解式Async配置異步任務(wù) - 一、大致介紹 1、有時(shí)候我們?cè)谔幚硪恍┤蝿?wù)的時(shí)候,需要開(kāi)啟線(xiàn)程去異步去處理,原有邏輯繼續(xù)往下執(zhí)行; 2、當(dāng)遇到這種場(chǎng)景的時(shí)候,線(xiàn)程是可以將我們完成,然后在SpringCloud中也有這樣的注解來(lái)支撐異步任務(wù)處理; 二、實(shí)現(xiàn)步驟 2.1 添加 mave...

    StonePanda 評(píng)論0 收藏0
  • Spring定時(shí)任務(wù)@scheduled多線(xiàn)程使用(@Async注解

    摘要:下面我們稍稍改下代碼來(lái)證實(shí)一下這次我讓任務(wù)執(zhí)行的時(shí)間等于,大于條線(xiàn)程總間隔時(shí)間來(lái)耗盡線(xiàn)程池中的線(xiàn)程。 1.開(kāi)篇 在Spring定時(shí)任務(wù)@Scheduled注解使用方式淺窺這篇文章里面提及過(guò),spring的定時(shí)任務(wù)默認(rèn)是單線(xiàn)程的,他在某些場(chǎng)景下會(huì)造成堵塞,那么如果我們想讓每一個(gè)任務(wù)都起一條線(xiàn)程去執(zhí)行呢? 2.使用@Async 我們可以使用Spring的@Async注解十分容易的實(shí)現(xiàn)多線(xiàn)程...

    klivitamJ 評(píng)論0 收藏0
  • 又被面試官問(wèn)設(shè)計(jì)模式了,我真

    摘要:面試官要不你來(lái)手寫(xiě)下單例模式唄候選者單例模式一般會(huì)有好幾種寫(xiě)法候選者餓漢式簡(jiǎn)單懶漢式在方法聲明時(shí)加鎖雙重檢驗(yàn)加鎖進(jìn)階懶漢式靜態(tài)內(nèi)部類(lèi)優(yōu)雅懶漢式枚舉候選者所謂餓漢式指的就是還沒(méi)被用到,就直接初始化了對(duì)象。面試官:我看你的簡(jiǎn)歷寫(xiě)著熟悉常見(jiàn)的設(shè)計(jì)模式,要不你來(lái)簡(jiǎn)單聊聊你熟悉哪幾個(gè)吧?候選者:常見(jiàn)的工廠模式、代理模式、模板方法模式、責(zé)任鏈模式、單例模式、包裝設(shè)計(jì)模式、策略模式等都是有所了解的候選者:...

    不知名網(wǎng)友 評(píng)論0 收藏0
  • Spring Boot 異步執(zhí)行方法

    摘要:最近遇到一個(gè)需求,就是當(dāng)服務(wù)器接到請(qǐng)求并不需要任務(wù)執(zhí)行完成才返回結(jié)果,可以立即返回結(jié)果,讓任務(wù)異步的去執(zhí)行。指定從上面執(zhí)行的日志可以猜測(cè)到默認(rèn)使用來(lái)異步執(zhí)行任務(wù)的,可以搜索到這個(gè)類(lèi)。 最近遇到一個(gè)需求,就是當(dāng)服務(wù)器接到請(qǐng)求并不需要任務(wù)執(zhí)行完成才返回結(jié)果,可以立即返回結(jié)果,讓任務(wù)異步的去執(zhí)行。開(kāi)始考慮是直接啟一個(gè)新的線(xiàn)程去執(zhí)行任務(wù)或者把任務(wù)提交到一個(gè)線(xiàn)程池去執(zhí)行,這兩種方法都是可以的。但...

    jiekechoo 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<