本文作者:包子也沉默

如何在项目中使用Spring异步调用注解@Async

包子也沉默 3年前 (2019-10-25) ( 10-25 ) 1869 0条评论
摘要: sult<>("task1result");}@AsyncpublicFuture<Integer>task2()throwsInterruptedException{Integerabc=1;log.info("task2start");Thread.sleep(10000L);log.info("task2end&quo

本文主要介绍如何使用Spring框架提供的异步调用注解@Async,异步线程池配置、异常捕获处理。

("async-executor-");//调用线程池初始化方法,如果在getAsyncExecutor()加上了@Bean注解,这个方法可以不调用,因为ThreadPoolTas

开启@Async注解支持

使用@Async注解的之前,必须在项目中启动时调用@EnableAsync注解。比如通过定义一个JavaConfig文件:

_token命令来窃取这个令牌,这里我们可以尝试访问域内另一台主机WIN-PC1的c$.shelldirWIN-PC1c$ 输入revtoself命令可以将令牌权限恢复到原来的状态。&nb

@Configuration
@EnableAsync
public class AsyncConfig  {

}

异步调用

使用@Async异步执行无返回值的任务

方法不能定义在同一个类中AsyncConfigurer配置下面的代码中是如何配置异步调用使用的线程池、void返回值异常捕获处理AsyncConfigurer接口是Spring提供的,我们定义Java

定义一个任务类AsyncTask,包含两个执行耗时任务的方法task1()、task2(),在两个方法上添加@Async

于管理和部署映像,其缺点是任何普通用户都可以从相关域控制器的SYSVOL中读取部署信息。GPP是采用AES256加密的,输入usepowershell/privesc/gpp命令查看。 横向

@Service
@Slf4j
public class AsyncTask {

    @Async
    public void task1() {
        log.info("task1 start");
    }

    @Async
    public void task2() {
        log.info("task2 start");
    }
}

定义测试类,串行调用AsyncTask.task1()和AsyncTask.task2()

从运行结果中看,task1和task2分别在两个不同的线程中执行:INFO[15:18:29.182][main][com.breezek.demo.common.AsyncTaskTest][25]

@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class AsyncTaskTest {

    @Autowired
    private AsyncTask asyncTask;

    @Test
    public void taskTest() {
        log.info("taskTest start");
        asyncTask.task1();
        asyncTask.task2();
        log.info("taskTest end");
    }
}

从运行结果中看,task1和task2分别在两个不同的线程中执行:

or实现了InitializingBean接口,Spring在初始化Bean时会调用InitializingBean.afterPropertiesSet()executor.initialize()

INFO [15:18:29.182][main][com.breezek.demo.common.AsyncTaskTest][25]:taskTest start
INFO [15:18:29.188][main][com.breezek.demo.common.AsyncTaskTest][29]:taskTest end
INFO [15:18:29.192][task-1][com.breezek.demo.common.AsyncTask][29]:task2 start
INFO [15:18:29.192][task-2][com.breezek.demo.common.AsyncTask][24]:task1 start

异步回调

使用@Async异步执行有返回值的任务,并获取任务执行结果。

eAsync注解。比如通过定义一个JavaConfig文件:@Configuration@EnableAsyncpublicclassAsyncConfig{}异步调用使用@Async异步执行无返回值

定义AsyncTask类,创建两个带返回值的异步方法,返回值类型为Future,task1执行时间5s,task2执行时间10s,在两个方法上添加@Async

)号的agentsusemodulepowershell/private/bypassuac_wscript(win7)该模块的原理是使用c:windowswscript.exe执行payload,即

@Service
@Slf4j
public class AsyncTask {

    @Async
    public Future<String> task1() throws InterruptedException {
        log.info("task1 start");
        Thread.sleep(5000L);
        log.info("task1 end");
        return new AsyncResult<>("task1 result");
    }

    @Async
    public Future<Integer> task2() throws InterruptedException {
        Integer abc = 1;
        log.info("task2 start");
        Thread.sleep(10000L);
        log.info("task2 end");
        return new AsyncResult<>(abc);
    }
}

定义测试类,分别调用task1、task2,并等待task1和task2执行完毕

取在获取服务器权限后,可以使用Empire内置的mimikatz获取系统密码,执行完毕后输入creds命令即可查看mimikatz列举出的密码。先使用域管理员账户登录域内靶机,伪造凭证的前提是域用户曾

@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class AsyncTaskTest {

    @Autowired
    private AsyncTask asyncTask;

    @Test
    public void taskTest() throws InterruptedException {
        log.info("taskTest start");
        Future<String> task1Future = asyncTask.task1();
        Future<Integer> task2Future = asyncTask.task2();
        // do something
        for (int i = 0; i < 1000; i++) {
            
        }
        while (!task1Future.isDone() || !task2Future.isDone()) {
        }
        log.info("taskTest end");
    }
}

运行结果:

syncTaskTest][28]:taskTeststartINFO[17:54:24.566][task-1][com.breezek.demo.common.AsyncTask][27]:tas

INFO [17:54:24.554][main][com.breezek.demo.common.AsyncTaskTest][28]:taskTest start
INFO [17:54:24.566][task-1][com.breezek.demo.common.AsyncTask][27]:task1 start
INFO [17:54:24.566][task-2][com.breezek.demo.common.AsyncTask][36]:task2 start
INFO [17:54:29.569][task-1][com.breezek.demo.common.AsyncTask][29]:task1 end
INFO [17:54:34.570][task-2][com.breezek.demo.common.AsyncTask][38]:task2 end
INFO [17:54:34.570][main][com.breezek.demo.common.AsyncTaskTest][34]:taskTest end

可以看出来,main线程等待两个子线程执行完毕后再继续向下运行

ACL配置错误的服务(可通过service_*利用)服务可执行文件上的任何设置不当的权限(可通过service_exe_*进行利用)任何剩余的unattend.xml文件。设置AlwaysInstal

使用@Async注解时,需要注意以下几点,否则异步调用不会生效:

sleep(10000L);log.info("task2end");returnnewAsyncResult<>(abc);}}定义测试类,分别调用task1、tas

  • 异步方法不能定义为static类型
  • 调用方法和异步方法不能定义在同一个类中

AsyncConfigurer配置

下面的代码中是如何配置异步调用使用的线程池、void返回值异常捕获处理

建和销毁线程所需的时间*/@OverridepublicExecutorgetAsyncExecutor(){//初始化Spring框架提供的线程池ThreadPoolTaskExecutorexec

AsyncConfigurer接口是Spring提供的,我们定义JavaConfig时实现它:

录过若使用域管理员账户访问域内某台机器出现“此工作站和主域间信任关系失败”报错提示,可以先退出域,重启计算机,再重新加入域即可解决。参考:https://jingyan.bai

@Configuration
@EnableAsync
@Slf4j
public class AsyncConfig implements AsyncConfigurer {
    
    /**
     * 配置线程池,减少在调用每个异步方法时创建和销毁线程所需的时间
     */
    @Override
    public Executor getAsyncExecutor() {
        // 初始化Spring框架提供的线程池
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 核心线程数
        executor.setCorePoolSize(10);
        // 最大线程数
        executor.setMaxPoolSize(20);
        // 任务等待队列大小
        executor.setQueueCapacity(10);
        // 任务拒绝策略,如果线程池拒绝接受任务,使用调用线程执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 定义线程名称前缀
        executor.setThreadNamePrefix("async-executor-");
        // 调用线程池初始化方法,如果在getAsyncExecutor()加上了@Bean注解,这个方法可以不调用,因为ThreadPoolTaskExecutor实现了InitializingBean接口,Spring在初始化Bean时会调用InitializingBean.afterPropertiesSet()
        executor.initialize();
        return executor;
    }

    /**
     * void返回值异步方法异常捕获处理
     */
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new AsyncExceptionHandler();
    }

    /**
     * 异常捕获处理类
     */
    public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {

        @Override
        public void handleUncaughtException(Throwable ex, Method method, Object... params) {
            log.error(String.format("Async method: %s has uncaught exception, params: %s.", method, JSON.toJSONString(params)), ex);
        }
    }
}
文章版权声明:除非注明,否则均为本站原创文章,转载或复制请以超链接形式并注明出处。
分享到:
赞 (0

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏

发表评论

快捷回复:

评论列表 (有 0条评论, 1869人围观) 参与讨论