なぜスーパークラスを追加すると、私のSpring Beanを破るのですか?

デイブ:

私は正常に動作している春のブートWebアプリケーションを持っています。私は2つのことに気づいた@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()メソッドが呼び出さ。各2つのインスタンスが作成されている場合のみ1が初期化されるようです。何かご意見は?

その後、マーカス:

あなたが親クラスを導入しているという事実が、あなたがなっているという事実はないgetに方法をfinal方法。

注釈付きクラスには、@Repository自動例外翻訳を取得します。この自動例外翻訳は、AOPを使用して追加されます。春にAOPを適用するデフォルトのメカニズムは、クラスベースのプロキシをプロキシを使用して、この場合にすることです。

何が起こるかというとCGLIBは、メソッドが呼び出されたときにアドバイスを追加できるように、それをサブクラス化することで、あなたのクラスのプロキシを作成することです。しかし、finalこの方法は、サブクラスでオーバーライドすることはできません。どちらにつながるgetプロキシの代わりに、実際のインスタンスに呼び出されるメソッド。

これを固定する2つの方法があります。

  1. 削除するfinalキーワードを
  2. あなたのリポジトリの契約を定義するインタフェースを紹介します。これは、JDKの動的プロキシが作成されることにつながります。JDKダイナミックプロキシはインターフェイス基づいており、(唯一のクラスベースのプロキシのためである)あなたの実際のクラスをサブクラス化する必要はありません。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=190526&siteId=1