복붙노트

[SPRING] 비동기 메서드를 실행하는 사용자 가져 오기

SPRING

비동기 메서드를 실행하는 사용자 가져 오기

다음과 같이 Spring을 사용하는 스프링에서 사용자를 얻으려고합니다.

Authentication auth = SecurityContextHolder.getContext().getAuthentication();

문제는 메서드가 비동기이며 주석 @Async가있는 것입니다.

@Service
@Transactional
public class FooServiceImpl implements FooService {

    @Async("asyncExecutor")
    public void fooMethod(String bar) {
        System.out.println("Foo: " + bar);
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    }
}

문제는 비동기 메서드가 다른 컨텍스트의 다른 스레드에서 실행된다는 점입니다. 나는 SecurityContextDelegationAsyncTaskExecutor를 사용하여 시도했다. 사용자가 비동기 메서드로 전파되지만 내가 로그 아웃하면 비동기 메서드의 사용자가 null입니다. 이것은 내 코드입니다.

@Configuration
@EnableAsync
public class SpringAsyncConfig implements AsyncConfigurer {

    @Override
    @Bean(name = "asyncExecutor")
    public Executor getAsyncExecutor() {

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

        executor.setMaxPoolSize(1);
        executor.setThreadGroupName("MyCustomExecutor");
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setBeanName("asyncExecutor");
        executor.initialize();

        return new DelegatingSecurityContextAsyncTaskExecutor(executor);
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new CustomAsyncExceptionHandler();
    }
}

또한 ThreadPoolTaskExecutor를 사용하고 "MODE_INHERITABLETHREADLOCAL"을 사용하여 스프링 보안 컨텍스트를 설정했습니다. 그러나 결과는 같습니다. 응용 프로그램에 로그인 한 경우 사용자가 null이 아닙니다. 로그인하지 않으면 사용자는 null입니다. 나는 현재 로그인 한 사용자가 아니라 메소드를 실행하는 사용자를 정말로 원합니다. 내 코드 :

@Configuration
@EnableAsync
public class SpringAsyncConfig implements AsyncConfigurer {

    @Override
    @Bean(name = "asyncExecutor")
    public Executor getAsyncExecutor() {

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

        executor.setMaxPoolSize(1);
        executor.setThreadGroupName("MyCustomExecutor");
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setBeanName("asyncExecutor");
        executor.initialize();

        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new CustomAsyncExceptionHandler();
    }

}

@Configuration
@ComponentScan(basePackageClasses = Application.class, includeFilters = @Filter({Controller.class}), useDefaultFilters = true)
public class MvcConfiguration extends WebMvcConfigurationSupport {

    //others beans

    @Bean
    public MethodInvokingFactoryBean methodInvokingFactoryBean() {
        MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
        methodInvokingFactoryBean.setTargetClass(SecurityContextHolder.class);
        methodInvokingFactoryBean.setTargetMethod("setStrategyName");
        methodInvokingFactoryBean.setArguments(new String[]{SecurityContextHolder.MODE_INHERITABLETHREADLOCAL});
        return methodInvokingFactoryBean;
    }
}

마지막으로, 나는이 게시물 인 Spring Security와 @Async를 발견했다. CustomThreadPoolTaskExecutor가 execute 메소드를 오버 라이딩하려고 시도합니다. 그러나이 방법은 절대 실행되지 않습니다. 실행되는 ThreadPoolTaskExecutor의 메소드는 다음과 같습니다.

<T> Future<T> submit(Callable<T> task)

내 코드 :

@Configuration
@EnableAsync
public class SpringAsyncConfig implements AsyncConfigurer {

    @Override
    @Bean(name = "asyncExecutor")
    public Executor getAsyncExecutor() {

        CustomThreadPoolTaskExecutor executor = new CustomThreadPoolTaskExecutor();

        executor.setMaxPoolSize(1);
        executor.setThreadGroupName("MyCustomExecutor");
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setBeanName("asyncExecutor");
        executor.initialize();

        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new CustomAsyncExceptionHandler();
    }

}

public class CustomThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {

    private static final long serialVersionUID = 1L;

    @Override
    public void execute(final Runnable r) {
        final Authentication a = SecurityContextHolder.getContext().getAuthentication();

        super.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    SecurityContext ctx = SecurityContextHolder.createEmptyContext();
                    ctx.setAuthentication(a);
                    SecurityContextHolder.setContext(ctx);
                    r.run();
                } finally {
                    SecurityContextHolder.clearContext();
                }
            }
        });
    }
}

내 사용자 정의 실행 메소드가 실행되지 않습니다. 커스텀 ThreadPoolTaskExecutor에서 내가 뭘 잘못하고 있니? 다른 방법은 비동기 메서드를 실행하는 사용자를 얻는 것입니다. 컨텍스트의 현재 사용자가 없습니다.

해결법

  1. ==============================

    1.아마 이것은 execute-method를 호출하는 것을 돕는다.

    아마 이것은 execute-method를 호출하는 것을 돕는다.

    @Override
    @Bean(name = "asyncExecutor")
    public Executor getAsyncExecutor() {
    
        CustomThreadPoolTaskExecutor executor = new CustomThreadPoolTaskExecutor();
    
        executor.setMaxPoolSize(1);
        executor.setThreadGroupName("MyCustomExecutor");
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setBeanName("asyncExecutor");
        executor.initialize();
    
        return new DelegatingSecurityContextAsyncTaskExecutor(executor);
    }
    
  2. from https://stackoverflow.com/questions/37214386/get-user-that-runs-an-asynchronous-method by cc-by-sa and MIT license