[英]Spring AOP continues iteration after throwing
我有MyClass
和AopLogger
。 如果doSomething
發生異常,則迭代停止。
如何防止退出logAround
並繼續使用下一個主機? logAround
返回的Object
什么logAround
,我們可以用這個Object
做什么呢?
class MyClass{
void check() throws Exception {
Iterator<Host> iter_host = configReader.getHostMap().values().iterator();
while (iter_host.hasNext()) {
Host host = (Host) iter_host.next();
host.doSomething();
}
}
void doSomething(){} //Exception
}
class AopLogger {
@Around("execution(* com.mypackage..*.*(..))")
Object logAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
return proceedingJoinPoint.proceed();
}
}
首先,您的方面類應具有@Aspect
批注。 其次,如果您想使用Spring AOP而不是完整的AspectJ,則您的方面和所有目標類也應該是Spring @Component
。
話雖如此,這里有一些例子。 我用普通的AspectJ創建了它,但是方面代碼在Spring AOP中應該是相同的。
使代碼編譯和運行的Helper類:
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;
}
}
驅動程序應用程序:
我不喜歡Iterator
,它是早期JDK版本的遺留物,所以我用更現代的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)。 異常處理建議僅做自己的工作。
隨時提出后續問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.