Автопроводной объект, заполненный с использованием ThreadLocalTargetSource, заполняется не для каждого класса - PullRequest
0 голосов
/ 27 марта 2020

В приложении My Spring Boot реализован пример TenantStore для хранения данных в ThreadLocalTargetSource, подробно описано в по этой ссылке

@Bean(destroyMethod = "destroy")
public ThreadLocalTargetSource threadLocalTenantStore() {
    ThreadLocalTargetSource result = new ThreadLocalTargetSource();
    result.setTargetBeanName("tenantStore");
    return result;
}

Рабочий пример позволяет объекту TenantStore быть установленным и введенным Spring Framework. Моя версия класса TenantFilter, описанная в этой статье, устанавливает свойства объекта TenantStore всякий раз, когда выполняется запрос сервлета

@Autowired
private TenantStore tenantStore;

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
    try {

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

        if (authentication != null) {
            String token = (String) request.getAttribute(ACCESS_TOKEN_VALUE);

            if (token != null) {
                OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(token);

                if (oAuth2AccessToken.getAdditionalInformation() != null) {
                    String tenantName = (String) oAuth2AccessToken.getAdditionalInformation().get("tenant");
                    storeTenantInThread(tenantName);
                }
            }
        }

        chain.doFilter(request, response);

    } catch (ResourceNotFoundException e) {
        log.error(e.getMessage());
    } finally {
        clearTenant();
    }
}

private void storeTenantInThread(String tenantName) {
    tenantStore.setName(tenantName);
}

private void clearTenant() {
    tenantStore.clear();
}

У меня тогда есть ряд служб, в которых TenantStore автоматически подключен и в каждой из этих служб TenantStore содержит информацию, которая была заполнена методом doFilter(). За исключением одного класса. По некоторым причинам свойства TenantStore в этом классе все еще нулевые. Имя затронутого класса - MyCacheService, а архитектура выглядит следующим образом:

@RestController
@RequestMapping("/here")
public class MyController {

    @Autowired
    private MyService myService

    @GetMapping
    public ResponseEntity myGetMethod(@RequestParam("text") String text) {
        myService.myMethod(text);
        return new ResponseEntity(Http.OK);
    }

}

@Service
public class MyService {

    @Autowired
    private TenantStore tenantStore;

    @Autowired
    private MyOtherService myOtherService;

    public void myMethod(String text) {
        System.out.println(tenantStore.getName()); //works - prints name
        myOtherService.myOtherMethod(text);
    }

}

@Service
public class MyOtherService {

    @Autowired
    private TenantStore tenantStore;

    @Autowired
    private Map<String, MyComponent> myComponents;

    public void myOtherMethod(String text) {
        System.out.println(tenantStore.getName()); //works - prints name
        MyComponent useThisComponent = myComponents.get("componentName");
        useThisComponent.myComponentMethod(text);
    }

}

@Component("componentName")
public class MyComponent {

    @Autowired
    private TenantStore tenantStore;

    @Autowired
    private MyCacheService myCacheService;

    public void myComponentMethod(String text) {
        System.out.println(tenantStore.getName()); //works - prints name
        entityAliasCacheService.myCacheMethod(String text);
    }

}

@Service
public class MyCacheService {

    @Autowired
    private TenantStore tenantStore;

    public void myCacheMethod(String text) {
        System.out.println(tenantStore.getName()); //DOES NOT WORK - tenantStore object is not null but the name property is
    }
}

Из того, что я могу догадаться, по какой-то причине TenantStore в MyCacheService заполняется в другом потоке хотя я понятия не имею почему.

...