同じクラス内から@Cacheable
メソッドを呼び出そうとしています:
@Cacheable(value = "defaultCache", key = "#id")
public Person findPerson(int id) {
return getSession().getPerson(id);
}
public List<Person> findPersons(int[] ids) {
List<Person> list = new ArrayList<Person>();
for (int id : ids) {
list.add(findPerson(id));
}
return list;
}
findPersons
からの結果もキャッシュされることを期待していますが、@Cacheable
アノテーションは無視され、findPerson
メソッドは毎回実行されます。
私はここで何か悪いことをしていますか、これは意図されていますか?
これは、Springでキャッシング、トランザクション関連の機能を処理するためにプロキシが作成される方法が原因です。これは、Springがそれを処理する方法の非常に優れたリファレンスです- トランザクション、キャッシュ、およびAOP:Springでのプロキシの使用法を理解する
つまり、セルフコールは動的プロキシをバイパスし、動的プロキシロジックの一部であるキャッシング、トランザクションなどの横断的な懸念もバイパスされます。
修正は、AspectJコンパイル時間またはロード時間ウィービングを使用することです。
これは、同じクラス内でメソッド呼び出しをほとんど使用しない小規模なプロジェクトで私が行うことです。コード内のドキュメントは、同僚にとっては苦痛に見えるかもしれないので、強く提供されています。しかし、そのテストは簡単で、簡単で、すぐに達成でき、本格的なAspectJインストゥルメンテーションを節約できます。ただし、より頻繁に使用する場合は、AspectJソリューションをお勧めします。
@Service
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
class PersonDao {
private final PersonDao _personDao;
@Autowired
public PersonDao(PersonDao personDao) {
_personDao = personDao;
}
@Cacheable(value = "defaultCache", key = "#id")
public Person findPerson(int id) {
return getSession().getPerson(id);
}
public List<Person> findPersons(int[] ids) {
List<Person> list = new ArrayList<Person>();
for (int id : ids) {
list.add(_personDao.findPerson(id));
}
return list;
}
}
Grails Spring Cacheプラグインを使用している人は、 回避策はドキュメントに記載されています 。 Grailsアプリでこの問題が発生しましたが、残念ながら、受け入れられた回答はGrailsでは使用できないようです。解決策は醜いですが、私見ですが、うまくいきます。
サンプルコードはそれをうまく示しています:
class ExampleService {
def grailsApplication
def nonCachedMethod() {
grailsApplication.mainContext.exampleService.cachedMethod()
}
@Cacheable('cachedMethodCache')
def cachedMethod() {
// do some expensive stuff
}
}
exampleService.cachedMethod()を独自のサービスとメソッドに置き換えるだけです。