簡體   English   中英

Spring AOP投擲后繼續迭代

[英]Spring AOP continues iteration after throwing

我有MyClassAopLogger 如果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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM