Почему добавление суперкласса ломает мои бобы Spring?

У меня есть веб-приложение Spring Boot, которое работает правильно. Я заметил, что два бина @Repository имеют много общего, поэтому я реорганизовал их с помощью абстрактного суперкласса, и теперь мое приложение не работает. Я дважды проверил, и это единственное изменение, которое я сделал между рабочим и нерабочим состояниями. Кто-нибудь может увидеть, что я сделал не так?

Вот мой рабочий код:

public class One { ... }
public class Two { ... }

@Repository
public class RepoOne {
    private final ISource<One> sourceOne;
    private ICache<One> cache;
    @Value("${com.example.lifetime.one}")
    private int lifetime;
    public RepoOne(ISource<One> sourceOne) {
       this.sourceOne = sourceOne;
    }
    @PostConstruct
    public void createCache() {
       Duration lifetime = Duration.ofMinutes(this.lifetime);
       this.cache = new Cache<>(lifetime, sourceOne);
    }
    public One get(String key) {
      return cache.get(key);
    }
}

@Repository
public class RepoTwo {
    private final ISource<Two> sourceTwo;
    private ICache<Two> cache;
    @Value("${com.example.lifetime.two}")
    private int lifetime;
    public RepoOne(ISource<Two> sourceTwo) {
        this.sourceTwo = sourceTwo;
    }
    @PostConstruct
    public void createCache() {
        Duration lifetime = Duration.ofMinutes(this.lifetime);
        this.cache = new Cache<>(lifetime, sourceTwo);
    }
    public Two get(String key) {
        return cache.get(key);
    }
}

@Service
public class RepoService {
    private final RepoOne repoOne;
    private final RepoTwo repoTwo;
    public RepoService(RepoOne repoOne, RepoTwo repoTwo) {
        this.repoOne = repoOne;
        this.repoTwo = repoTwo;
    }
    public void doSomething(String key) {
        One one = repoOne.get(key);
        ...
    }
}

Вот мой переработанный код, в котором я представил абстрактный универсальный суперкласс.

abstract class AbstractRepo<T> {
    private final ISource<T> source;
    private ICache<T> cache;
    AbstractRepo (ISource<T> source) {
       this.source = source;
    }
    @PostConstruct
    private void createCache() {
       Duration lifetime = Duration.ofMinutes(lifetime());
       this.cache = new Cache<>(lifetime, source);
    }
    protected abstract int lifetime();
    public final T get(String key) {
        return cache.get(key);
    }
}

@Repository
public class RepoOne extends AbstractRepo<One> {
    @Value("${com.example.lifetime.one}")
    private int lifetime;
    public RepoOne(ISource<One> sourceOne) {
       super(source);
    }
    protected int lifetime() { return lifetime; }
}

@Repository
public class RepoTwo extends AbstractRepo<Two> {
    @Value("${com.example.lifetime.two}")
    private int lifetime;
    public RepoTwo(ISource<Two> sourceTwo) {
       super(source);
    }
    protected int lifetime() { return lifetime; }
}

При использовании переработанного кода я получаю NullPointerException в AbstractRepo::get(). Через отладчик я подтвердил, что cache равно null (вместе с source). Однако я также подтвердил с помощью отладчика, что экземпляры RepoOne и RepoTwo созданы и вызван их метод createCache(). Как будто создается два экземпляра каждого и инициализируется только один. Есть мысли?

4 голоса | спросил dave 4 +03002018-10-04T07:43:32+03:00312018bEurope/MoscowThu, 04 Oct 2018 07:43:32 +0300 2018, 07:43:32

1 ответ


0
Дело не в том, что вы ввели родительский класс, а в том, что вы превратили метод ---- +: = 0 =: + ---- в ---- +: = 1 =: + -- метод.Класс, помеченный ---- +: = 2 =: + ---- , получит автоматический перевод исключений.Этот автоматический перевод исключений добавляется с помощью AOP.Механизм по умолчанию для применения AOP в Spring - это использование прокси, а в данном случае - прокси на основе классов.Что происходит, так это то, что CgLib создает прокси для ваших классов, создавая его подклассы, чтобы при вызове метода можно было добавить рекомендацию.Однако метод ---- +: = 3 =: + ---- нельзя переопределить в подклассе.Это приведет к тому, что метод ---- +: = 4 =: + ---- будет вызываться на прокси вместо фактического экземпляра.Есть 2 способа исправить этоУдалить ключевое слово ---- +: = 5 =: + ----Введите интерфейс, определяющий контракт для ваших репозиториев.Это приведет к созданию динамического прокси JDK.Динамические прокси JDK основаны на интерфейсе и не требуют подкласса вашего фактического класса (то есть только для прокси на основе классов).
ответил M. Deinum 4 +03002018-10-04T08:57:36+03:00312018bEurope/MoscowThu, 04 Oct 2018 08:57:36 +0300 2018, 08:57:36

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132