まず、アスペクトクラスには、@Aspect
アノテーションが必要です。第2に、Spring AOPを使用し、AspectJを完全に使用しない場合は、アスペクトおよびすべてのターゲットクラスもSpring @Component
である必要があります。
と言えば、ここでは少しサンプルです。プレーンなAspectJで作成しましたが、アスペクトコードはSpring AOPで同じにする必要があります。
ヘルパークラスコードのコンパイルを行い、実行するために:
package de.scrum_master.app;
import java.util.Random;
public class Host {
private static final Random RANDOM = new Random();
private String name;
public Host(String name) {
this.name = name;
}
public void doSomething() {
if (RANDOM.nextBoolean())
throw new RuntimeException("oops!");
}
@Override
public String toString() {
return "Host(name=" + name + ")";
}
}
package de.scrum_master.app;
import java.util.HashMap;
import java.util.Map;
public class ConfigReader {
private Map<Integer, Host> hostMap = new HashMap<>();
public ConfigReader() {
hostMap.put(1, new Host("mercury"));
hostMap.put(2, new Host("venus"));
hostMap.put(3, new Host("earth"));
hostMap.put(4, new Host("mars"));
}
public Map<Integer, Host> getHostMap() {
return hostMap;
}
}
ドライバアプリケーション:
私は古いJDKのバージョンからの遺物であるIterator
を好きではなかったです、だから私はより現代的なJavaスタイルfor
ループに置き換えました。ポイントカット/アドバイスを同時に扱うロギングと例外をやってと
package de.scrum_master.app;
class MyClass {
private ConfigReader configReader = new ConfigReader();
void check() throws Exception {
for (Host host : configReader.getHostMap().values()) {
System.out.println(host);
host.doSomething();
}
}
public static void main(String[] args) throws Exception {
new MyClass().check();
}
}
アスペクト比:
また、コードの最後で私のコメントを注意してください。
package de.scrum_master.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class AopLogger {
private static final InheritableThreadLocal<String> indent = new InheritableThreadLocal<String>() {
@Override
protected String initialValue() {
return "";
}
};
@Around("execution(* de.scrum_master.app..*(..)) && !execution(* toString())")
public Object logAround(ProceedingJoinPoint thisJoinPoint) throws Throwable {
Object result = null;
System.out.println(indent.get() + ">> " + thisJoinPoint);
try {
indent.set(indent.get() + " ");
result = thisJoinPoint.proceed();
indent.set(indent.get().substring(2));
} catch (Exception e) {
System.out.println(indent.get() + "Caught exception: " + e);
indent.set(indent.get().substring(2));
}
System.out.println(indent.get() + "<< " + thisJoinPoint);
// Attention: If a method with a caught exception does not have 'void'
// return type, we return a (probably unexpected) result of 'null' here.
// So maybe we should not catch all execptions but rather pick more
// specific joinpoints where we are sure we can cleanly handle the
// corresponding exceptions.
return result;
}
}
コンソールログ:例外処理からログを分離
>> execution(void de.scrum_master.app.MyClass.main(String[]))
>> execution(void de.scrum_master.app.MyClass.check())
>> execution(Map de.scrum_master.app.ConfigReader.getHostMap())
<< execution(Map de.scrum_master.app.ConfigReader.getHostMap())
Host(name=mercury)
>> execution(void de.scrum_master.app.Host.doSomething())
Caught exception: java.lang.RuntimeException: oops!
<< execution(void de.scrum_master.app.Host.doSomething())
Host(name=venus)
>> execution(void de.scrum_master.app.Host.doSomething())
<< execution(void de.scrum_master.app.Host.doSomething())
Host(name=earth)
>> execution(void de.scrum_master.app.Host.doSomething())
Caught exception: java.lang.RuntimeException: oops!
<< execution(void de.scrum_master.app.Host.doSomething())
Host(name=mars)
>> execution(void de.scrum_master.app.Host.doSomething())
Caught exception: java.lang.RuntimeException: oops!
<< execution(void de.scrum_master.app.Host.doSomething())
<< execution(void de.scrum_master.app.MyClass.check())
<< execution(void de.scrum_master.app.MyClass.main(String[]))
第二の態様の変種:
package de.scrum_master.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class AopLogger {
private static final InheritableThreadLocal<String> indent = new InheritableThreadLocal<String>() {
@Override
protected String initialValue() {
return "";
}
};
@Around("execution(* de.scrum_master.app..*(..)) && !execution(* toString())")
public Object logAround(ProceedingJoinPoint thisJoinPoint) throws Throwable {
System.out.println(indent.get() + ">> " + thisJoinPoint);
try {
indent.set(indent.get() + " ");
Object result = thisJoinPoint.proceed();
indent.set(indent.get().substring(2));
System.out.println(indent.get() + "<< " + thisJoinPoint);
return result;
} catch (Exception e) {
indent.set(indent.get().substring(2));
System.out.println(indent.get() + "<< " + thisJoinPoint);
throw e;
}
}
@Around("execution(void de.scrum_master.app.Host.doSomething())")
public void handleException(ProceedingJoinPoint thisJoinPoint) throws Throwable {
try {
thisJoinPoint.proceed();
} catch (Exception e) {
System.out.println(indent.get() + "Caught exception: " + e);
}
}
}
ログ出力は、例外処理を同じまま、今回より正確なポイントカットを持つ別のアドバイスにあります。ロギングアドバイスはロギングのみを扱います(正しいインデント用でない場合はtry-catchは必要ありません)。例外処理のアドバイスは、自分の仕事だけを行います。
お気軽にフォローアップの質問をしてください。
あなたは十分な情報を提供していません。ジョインポイントがdoSomethingメソッド(publicであると仮定)にある場合、try catching blockをreturn proceedingJoinPoint.proceed()の周りに置くだけで十分です。 "それは何のために良いのですか?" doSomethingを入力すると、メソッドが戻るときにログに記録されることがあります。実際にはこれがあなたのコードにないことは奇妙です。 –
私はtry catch catchブロックを置くときに、proceedingJoinPoint.proceed()の反復が終了し、アプリケーションが終了します。私がtry.getSoolean()の周りにtry catchブロックを置くと、反復は続行されますが、logAroundに何も記録できません。 – user2683906
まずjoinpointを見つけてください:return proceedingJoinPoint.proceed()およびProceedingJoinPointのさまざまなフィールドを調べます。どのメソッドが傍受されているかを確認する必要があります。そこから推理しよう。 –