へい。
永続化レイヤーのロギング用に @Aspect を作成しています。
最初に、経験豊富な開発者にエラーを表示する可能性のあるコード ;)
/** Interface of the class to observe. */
public interface PersistenceService {
public Serializable save(Serializable serializable);
public List<Serializable> save(List<Serializable> list)
}
/** Actual class to observe. */
@Service
public class PersistenceService {
@Autowired
private SomeJpaRepository rep;
public Serializable save(Serializable serializable) {
return rep.save(serializable);
}
public List<Serializable> save(List<Serializable> list) {
return rep.save(list);
}
}
そしてここにアスペクト:
/** The Aspect. */
@Aspect
@Component
public class PersistenceService {
/** A org.slf4j.Logger (using logback). */
private final Logger logger = LoggerFactory.getLogger(getClass());
/** Pointcut to define the classes to observe. */
@Pointcut("within(de.mypckg.myproject.persistence.*.*)")
public void inPersistanceLayer() {}
/** Pointcut for the first save-method. */
@Pointcut("execution(public * save(..)) && args(serializable)")
public void saveOperation(Serializable serializable) {}
/** Pointcut for the first save-method. */
@Pointcut("execution(public * save(..)) && args(list)")
public void saveOperation(List<Serializable> list) {}
/** Method for the first save-method. */
@Around("inPersistanceLayer() && saveOperation(serializable)")
public List<Serializable> logSave(ProceedingJoinPoint joinPoint, Serializable serializable) throws Throwable {
// log some stuff
Object saved = joinPoint.proceed();
// log somemore stuff
}
/** Method for the second save-method. */
@Around("inPersistanceLayer() && saveOperation(list)")
public List<Serializable> logSave(ProceedingJoinPoint joinPoint, List<Serializable> list) throws Throwable {
// log some stuff
Object saved = joinPoint.proceed();
// log somemore stuff
}
}
ポイントカット (およびそのメソッド) が 1 つしかない場合は機能しますが、2 つ目を追加すると、次の例外が発生します。
java.lang.IllegalArgumentException: warning no match for this type name: list [Xlint:invalidAbsoluteTypeName]
ポイントカットの順序を変更しました。常に 2 番目です。これを解決する方法についてのアイデアはありますか?
更新
質問を投稿したら、アイデアがありました。ポイントカットを次のように変更しました。
/** The Aspect. */
@Aspect
@Component
public class PersistenceService {
/** A org.slf4j.Logger (using logback). */
private final Logger logger = LoggerFactory.getLogger(getClass());
/** Pointcut to define the classes to observe. */
@Pointcut("within(de.mypckg.myproject.persistence.*.*)")
public void inPersistanceLayer() {}
/** Pointcut for the save-method. */
@Pointcut("execution(public * save(..))")
public void saveOperation() {}
/** Pointcut for the serializable argument. */
@Pointcut("args(serializable)")
public void serializableArgument(Serializable serializable) {}
/** Pointcut for the list argument. */
@Pointcut("args(list)")
public void listArgument(List<Serializable> list) {}
/** Method for the first save-method. */
@Around("inPersistanceLayer() && saveOperation() && serializableArgument(serializable)")
public Object logSave(ProceedingJoinPoint joinPoint, Serializable serializable) throws Throwable {
// log some stuff
Object saved = joinPoint.proceed();
// log somemore stuff
return saved;
}
/** Method for the second save-method. */
@Around("inPersistanceLayer() && saveOperation(list) && listArgument(list)")
public Object logSave(ProceedingJoinPoint joinPoint, List<Serializable> list) throws Throwable {
// log some stuff
Object saved = joinPoint.proceed();
// log somemore stuff
return saved;
}
}
例外はなくなりましたが、まだ小さな問題があります (解決するのははるかに簡単だと思います): ArrayList は Serializable を実装しているため、少なくとも ArrayList を使用する私のテスト ケースでは、両方のポイントカットが実行されます。
私はそれを調べて、見つけたものを投稿しますが、助けも大歓迎です;)
更新 2
kriegaex が指摘したコピペエラーを修正。ありがとう!
メソッド logSave(..) の戻り値の型は Object です。
アップデート 3
コードを 1 つのポイントカットと 1 つのメソッドだけを使用するように変更し、kriegaex が提案したように instanceof で確認しました。
/** The Aspect. */
@Aspect
@Component
public class PersistenceService {
/** A org.slf4j.Logger (using logback). */
private final Logger logger = LoggerFactory.getLogger(getClass());
/** Pointcut to define the classes to observe. */
@Pointcut("within(de.mypckg.myproject.persistence.*.*)")
public void inPersistanceLayer() {}
/** Pointcut for the save-method. */
@Pointcut("execution(public * save(*)) && args(serializable)")
public void saveOperation(Serializable serializable) {}
/** Method for the first save-method. */
@Around("inPersistanceLayer() && saveOperation() && serializableArgument(serializable)")
public Serializable logSave(ProceedingJoinPoint joinPoint, Serializable serializable) throws Throwable {
// log some stuff
Serializable saved = (Serializable) joinPoint.proceed();
if (saved instanceof List<?>) {
List<?> savedList = (List<?>) saved;
// log somemore stuff with a List
} else {
// log somemore stuff
}
return saved;
}
}
なぜ他の方法でうまくいかなかったのか、今でも疑問に思っています。