Метод Spring @Cachable в том же классе (самовызов, проблема с прокси) - Как лучше всего решить эту проблему? - PullRequest
1 голос
/ 13 июля 2020

Я пытаюсь вызвать метод @Cacheable из того же класса.

И это не сработало. Из-за:

В режиме прокси (по умолчанию) перехватываются только вызовы внешних методов, поступающие через прокси. Это означает, что самовызов (фактически, метод в целевом объекте, который вызывает другой метод целевого объекта) не приводит к фактическому кэшированию во время выполнения, даже если вызванный метод отмечен @Cacheable. В этом случае рассмотрите возможность использования режима aspectj. Кроме того, прокси-сервер должен быть полностью инициализирован для обеспечения ожидаемого поведения, поэтому вы не должны полагаться на эту функцию в своем коде инициализации (то есть @PostConstruct).

Это означает, что @Cachable (также @Transactional) работает с прокси-классами, которые являются Spring AOP. Внутренний вызов в том же классе делает вызов с помощью 'this' вместо прокси-классов.

Чтобы решить проблему, я должен вызвать метод через прокси или с использованием AspectJ (другой АОП). Итак, я нашел 4 решения.

Какой ваш выбор? а почему другие не рекомендуются?

Пожалуйста, поделитесь своим мнением!

  1. с использованием AspectJ (другой АОП)
  2. получить Bean из ApplicationContext и использовать его
@Service
public class UserService implements Service {

    @Autowired
    private ApplicationContext applicationContext;

    private Service self;

    @PostConstruct
    private void init() {
        self = applicationContext.getBean(UserService.class);
    }
}
самоавтоматизация с использованием @Resource // начиная с Spring 4.3
@Component
@CacheConfig(cacheNames = "SphereClientFactoryCache")
public class CacheableSphereClientFactoryImpl implements SphereClientFactory {

    /**
     * 1. Self-autowired reference to proxified bean of this class.
     */
    @Resource
    private SphereClientFactory self;

    @Override
    @Cacheable(sync = true)
    public SphereClient createSphereClient(@Nonnull TenantConfig tenantConfig) {
        // 2. call cached method using self-bean
        return self.createSphereClient(tenantConfig.getSphereClientConfig());
    }

    @Override
    @Cacheable(sync = true)
    public SphereClient createSphereClient(@Nonnull SphereClientConfig clientConfig) {
        return CtpClientConfigurationUtils.createSphereClient(clientConfig);
    }
}
сделать Bean-область класса как «прототип» вместо «singleton»
@Service
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
class AService {

    private final AService _aService;

    @Autowired
    public AService(AService aService) {
        _aService = aService;
    }

    @Cacheable("employeeData")
    public List<EmployeeData> getEmployeeData(Date date){
        ..println("Cache is not being used");
        ...
    }

    public List<EmployeeEnrichedData> getEmployeeEnrichedData(Date date){
        List<EmployeeData> employeeData = _aService.getEmployeeData(date);
        ...
    }
}

Я новичок ie весной :)

На самом деле , Я выбрал 4-е решение, но мне показалось, что это не лучший способ. потому что мне просто нужно вызвать метод кеширования через прокси, и для этого нужно сделать несколько bean-компонентов.

После прочтения статей я думаю, что AspectJ - лучший выбор. Это выглядит круто, Spring рекомендует это, и многие люди тоже рекомендуют.

Но я не понимаю, как работает AspectJ (буду изучать), и я также не знаю, почему другие не рекомендуются.

ссылок

...