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