Невозможно включить спящий фильтр в весеннем EntityManager с помощью Spring AOP - PullRequest
0 голосов
/ 04 апреля 2019

Я пытаюсь включить фильтр гибернации через пружину EntityManager, пытаясь навести указатель на метод реализации службы, аннотированный пользовательской аннотацией @TenantAware, и добавить @Around советовать этому методу.Я хочу включить пользовательский фильтр, который добавляет дифференциатор where tenant_id = :tenantId ко всем объектам, которые расширяют BaseEntity.Поэтому я создал пользовательскую аннотацию и использую ее для методов @Transactional там, где это требуется.Он успешно перехватывает метод, но значения переменных, когда я их регистрирую, отображаются пустыми, и фильтр не устанавливается.

Проект является приложением с начальной загрузкой 2, и я использую Spring AOP для созданияаспект.Я использую Hibernate 5 в качестве поставщика реализации JPA.

Плетение времени загрузки SimpleJpaRepository.class невозможно, поскольку оно не предоставляет конструктор noarg.

Это мой TenantFilterAdvisorclass.

package org.foo.bar.advisors;

@Aspect
@Slf4j
@Component
public class TenantFilterAdvisor {

    @PersistenceContext
    private EntityManager entityManager;

    public TenantFilterAdvisor() {
        log.debug("###########################################################################");
        log.debug("###################### Tenant Advisor Filter Started ######################");
        log.debug("###########################################################################");
    }

    @Pointcut(value = "@annotation(org.foo.bar.TenantAware)")
    public void methodAnnotatedWithTenantAware() {
    }

    @Pointcut(value = "execution(public * * (..))")
    public void allPublicMethods() {

    }

    @Around(value = "methodAnnotatedWithTenantAware() && allPublicMethods()")
    public Object enableTenantFilter(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

        log.debug("###########################################################################");
        log.debug("###################### Before enabling tenant filter ######################");
        log.debug("###########################################################################");

        if (null != entityManager) {

            log.debug("Tenant filter name: ", "tenantFilter");
            log.debug("Tenant filter property: ", "tenantId");
            log.debug("Setting tenant id to: ", new Long(10));

            Session session = entityManager.unwrap(Session.class);
            Filter filter = session.enableFilter("tenantFilter");
            filter.setParameter("tenantId", new Long(10));

        }


        Object result = proceedingJoinPoint.proceed();

        // Code to disable the hibernate filter goes here.
        log.debug("###########################################################################");
        log.debug("###################### After disabling tenant filter ######################");
        log.debug("###########################################################################");

        return result;

    }

}

Соответствующая часть интерфейса службы и класса реализации:

public interface InventoryService {
    Inventory getInventoryById(Long id);
}
@Service
public class InventoryServiceImpl implements InventoryService {

    @Autowired
    private InventoryRepository repo;

    @Override
    @Transactional
    @TenantAware
    public Inventory getInventoryById(Long id) {
       LOG.debug("getInventoryById() called  with: id = {}", id);
        final Optional<Inventory> inventoryOp = repo.findById(id);

        if (inventoryOp.isPresent()) {
            return inventoryOp.get();
        } else {
            throw new InventoryNotFoundException(String.format(MESSAGE_INVENTORY_NOT_FOUND_FOR_ID, id));
        }
    }
}

Интерфейс хранилища:

@Repository
@Transactional(readOnly = true)
public interface InventoryRepository extends BaseRepository<Inventory, Long> {  
}

Расширяется интерфейс BaseRepository.JpaRepository.

И класс конфигурации аспекта -

@Configuration
@ComponentScan(basePackages = {"org.foo.bar.advisors"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AOPConfig {
}

И, наконец, соответствующий MappedSuperClass, который наследуется другими классами, имеет фильтр, определенный как

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@MappedSuperclass
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@FilterDef(
        name = "tenantFilter",
        parameters = @ParamDef(name = "tenantId", type = "long")
)
@Filter(name = "tenantFilter", condition = "tenant_id = :tenantId")
public abstract class BaseTransactionalEntity extends BaseEntity {

    @Column(name = "tenant_id", nullable = false)
    private Long tenantId;

}

Здеськласс аннотаций cutom, если вам нужна деталь

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface TenantAware {
}

Мне нужно, чтобы фильтр гибернации был включен в сеансе и отключен после того, как исходящая точка соединения завершит выполнение.Но это не так.Чего мне не хватает?

1 Ответ

1 голос
/ 06 апреля 2019

Как описано в Справочном руководстве по Hibernate *, фильтры применяются только к запросам сущностей, а не к прямой выборке. В вашем коде вы делаете прямую выборку через findById, что переводится как entityManager.find и, таким образом, является прямой выборкой.

Чтобы обойти эту проблему, можно переопределить репозиторий Spring JPA и переопределить findById, чтобы он представлял собой запрос сущности вместо прямой выборки.

...