Во-первых, ваш класс аспект должен содержать аннотацию @Aspect
. Во-вторых, если вы хотите использовать Spring AOP, а не полный AspectJ, ваш аспект и все целевые классы также должны быть весной @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);
}
}
}
Выход журнала остается неизменным, но на этот раз обработка исключений находится в отдельном совете с более точным pointcut. Совет по протоколированию заботится только о протоколировании (даже если бы не правильный отступ, ему даже не понадобился бы try-catch). Совет по обработке исключений выполняет только свою работу.
Не стесняйтесь спрашивать о последующих вопросах.
Вы не даете достаточной информации; если точка соединения находится в методе doSomething (при условии, что он является общедоступным), тогда этого должно быть достаточно, чтобы поместить try catch block вокруг return continueJoinPoint.proceed(). «Что это хорошо для ...», вы можете войти в систему, когда вы входите в doSomething, и когда метод возвращается; на самом деле странно, что этого не хватает в вашем коде. –
, когда я помещаю блок catch try вокруг return continueJoinPoint.proceed() завершает итерацию и завершает работу приложения. Когда я помещаю блок catch try на host.doSomething(), итерация продолжается, но я ничего не могу зарегистрировать в logAround – user2683906
, сначала узнайте, что такое точка соединения: поместите контрольную точку в свою IDE при возврате continueJoinPoint.proceed() и проверьте различные области ProceedingJoinPoint - вы должны увидеть, какой метод перехвачен.Попытайтесь рассуждать оттуда. –