我的Spring Boot应用程序实现了在ThreadLocalTargetSource
中存储数据的TenantStore
示例,详细信息请参见this link
@Bean(destroyMethod = "destroy")
public ThreadLocalTargetSource threadLocalTenantStore() {
ThreadLocalTargetSource result = new ThreadLocalTargetSource();
result.setTargetBeanName("tenantStore");
return result;
}
工作示例允许由Spring Framework设置和注入TenantStore
对象。我在那篇文章中描述的TenantFilter
类在发出Servlet请求时设置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
}
}
据我所知,出于某种原因,MyCacheService
中的TenantStore
被填充到了不同的线程中,尽管我不知道为什么。
发布于 2021-07-23 17:43:40
我注意到了类似的行为。我通过添加bean依赖项修复了这个问题。
@Service
@DependsOn("proxiedThreadLocalTargetSource") // asks Spring to first load proxy bean
public class MyCacheService {
其中proxiedThreadLocalTargetSource
bean的定义类似于OP的示例-
@Primary
@Bean(name = "proxiedThreadLocalTargetSource")
public ProxyFactoryBean proxiedThreadLocalTargetSource(ThreadLocalTargetSource threadLocalTargetSource) {
ProxyFactoryBean result = new ProxyFactoryBean();
result.setTargetSource(threadLocalTargetSource);
return result;
}
因此,通过添加依赖项,Spring知道它应该在proxiedThreadLocalTargetSource
之后加载MyCacheService
bean。在没有这种依赖性的情况下,我注意到注入的是TenantStore
而不是代理bean。
发布于 2020-05-23 18:39:22
从org.springframework.context.ApplicationContext获取TenantStore实例
首先实现ApplicationContextAware,如下所示
@Component
public class ApplicationContextUtil implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static ApplicationContext context() {
return context;
}
}
您的MyCacheService将如下所示:
public class MyCacheService {
public void myCacheMethod(String text) {
TenantStore tenantStore = ApplicationContextUtil.context().getBean(TenantStore.class);
System.out.println(tenantStore.getName());
}
}
https://stackoverflow.com/questions/60884958
复制