如何将jpa存储库初始化从启动移动到多租户环境的会话创建时间

时间:2015-02-26 06:25:25

标签: java spring hibernate spring-data multi-tenant

我正在将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。 如果有人需要更多信息,请告诉我。

1 个答案:

答案 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;
    }

我希望它有所帮助。