我正在将Jpa存储库与我的具有多租户支持的项目集成。因此,每当有请求进入时,我们在本地线程中设置一个租户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"` />
当我部署开始扫描包并尝试将实体管理器和事务管理器注入JpaRepositoryFactoryBean但由于AccessFilter尚未调用(因为它将在创建会话时调用),因此在本地线程中没有设置租户ID它失败了。我的EntityManagerFactory代码是这样的 -
@Override
public EntityManagerFactory getEntityManagerFactory() {
return threadLocalHasFactory.get();
}
我已经通过了http://codecrafters.blogspot.sk/2013/03/multi-tenant-cloud-applications-with.html,但是这个人使用Apache Shiro框架,在我的情况下没有使用。 我不确定的是,如何将整个jpa存储库创建逻辑从启动时间移动到创建会话时。 我在Spring 3中使用Hibernate4。 如果有人需要更多信息,请告诉我。
答案 0 :(得分:0)
我找到了解决方案,可能是在这里分享工作。
我已经删除了我的存储库类的自动装配,并在方法调用时开始通过AoP注入它。所以我创建了我的方法的代理,这里是我的服务层中设置存储库接口代理的代码。对于以下类,您需要进行一些配置,以便可以围绕您的服务调用它。
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;
}
我希望它有所帮助。