我正在将 Jpa 存储库与我的具有 Multi-Tenancy 支持的项目集成。因此,每当请求到来时,我们都会在本地线程中设置一个租户 ID,如下所示 -
public class AccessFilter implements Filter{
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
//
UserContext userContext = (UserContext) session.getAttribute(USER_CONTEXT);
TenantContext.set(userContext.getTenantId());
//
}
}
我的jpa配置是这样的
`<jpa:repositories base-package="com.adnan" factory-class="com.spmsoftware.appframework.repository.MyRepositoryFactoryBean"` />
当我部署开始扫描包并尝试将实体管理器和事务管理器注入(inject) JpaRepositoryFactoryBean 时,但由于 AccessFilter 尚未调用(因为它将在创建 session 时调用),因此在线程本地中未设置租户 Id 并且失败。我的 EntityManagerFactory 代码是这样的 -
@Override
public EntityManagerFactory getEntityManagerFactory() {
return threadLocalHasFactory.get();
}
我已经浏览过http://codecrafters.blogspot.sk/2013/03/multi-tenant-cloud-applications-with.html但这家伙使用 Apache Shiro 框架,但在我的例子中没有使用。 我不确定的是,如何将整个 jpa 存储库创建逻辑从启动时间移动到创建 session 时。 我正在使用 Hibernate4 和 Spring 3。 如果有人需要更多信息,请告诉我。
最佳答案
我找到了解决方案,可能是这里的工作共享。
我已经删除了存储库类的 Autowiring ,并开始在方法调用时通过 AoP 注入(inject)它。因此,我围绕我的方法的代理创建了,这是为在我的服务层中设置存储库接口(interface)代理而编写的代码。对于下面的类,您需要进行一些配置,以便可以在您的服务周围调用它。
public class RepositoryCapableInterceptor implements MethodInterceptor, ApplicationContextAware{
private ApplicationContext applicationContext;
/**
*
* @param methodInvocation method invocation passed by Spring
* @return return value of target method.
* @throws Throwable
*/
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
Object currentObj = methodInvocation.getThis();
List<Field> toInitializeFields = fetchAllOptymyzeRepositoryChildes(currentObj);
if (! toInitializeFields.isEmpty()) {
RepositoryFactorySupport factory = applicationContext.getBean(RepositoryCreator.class).getRepositoryFactorySupport();
for (Field f : toInitializeFields) {
Object bean = factory.getRepository(f.getType());
f.set(currentObj, bean);
f.setAccessible(false);
}
}
return methodInvocation.proceed();
}
private List<Field> fetchAllOptymyzeRepositoryChildes(Object currentObj) throws IllegalAccessException {
List<Field> toInitializeFields = newArrayList();
for (Field field : currentObj.getClass().getDeclaredFields()) {
if(OptymyzeRepository.class.isAssignableFrom(field.getType())){
field.setAccessible(true);
if (field.get(currentObj) == null){
toInitializeFields.add(field);
} else {
field.setAccessible(false);
}
}
}
return toInitializeFields;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
希望对您有所帮助。
关于java - 如何将 jpa 存储库初始化从启动时间移动到 Multi-Tenancy 环境的 session 创建时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28735837/