使用方面记录 java 中方法的入口、出口和异常

Logging entry, exit and exceptions for methods in java using aspects

我正在使用以下代码使用方面记录进入、退出和异常。这样,我必须在我的 ApplicationContext 中为我的应用程序中的每个 class 定义一个 bean,并且维护如此长的 bean 定义及其属性变得很麻烦。你能帮我简化一下吗?我认为每次创建 class 时都定义 bean 是不合适的设计。感谢您的帮助,在此先感谢。

<bean id="logEntryBean" class="com.example.logging.LogEntry" />
<bean id="logExitBean" class="com.example.logging.LogReturn" />
<bean id="logExceptionBean" class ="com.example.logging.ExceptionLogger"/>

<bean id="simpleServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="target" ref="simpleServiceBean" />
    <property name="interceptorNames">
        <list>
            <value>logEntryBean</value>
            <value>logExitBean</value>
            <value>logExceptionBean</value>
        </list>
    </property>
</bean>

    <bean id="secondServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="target" ref="secondServiceBean" />
    <property name="interceptorNames">
        <list>
            <value>logEntryBean</value>
            <value>logExitBean</value>
            <value>logExceptionBean</value>
        </list>
    </property>
</bean>

==================== 日志条目 class:

public class LogEntry implements MethodBeforeAdvice {
private final static Logger logger = Logger.getLogger(LogEntry.class);

public void before(Method method, Object[] args, Object target) throws Throwable {

    if(logger.isDebugEnabled())
    logger.info("logged entry for method : " + method.getName());
}

========================= LogReturn class:

public class LogReturn implements AfterReturningAdvice {
private final static Logger logger = Logger.getLogger(LogReturn.class);

public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
    if(logger.isDebugEnabled())
    logger.info("Logged exit for method : " + method.getName());
}

============================== 异常记录器 class

public void afterThrowing(Exception r) throws Throwable {

    loadProperties();

    // LOG the exceptions
    logger.error("Exception  : " + r.getMessage());
    logger.error(r);

    if (logger.isDebugEnabled()) {
        // Logging complete stacktrace in better format
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        r.printStackTrace(pw);
        logger.debug((sw.toString()));
    }
    // sendMail();

    if (r instanceof ProcessingException) {

        throw new OutputException(prop.getProperty("ER004"), r);
    } else if (r instanceof SystemException) {
        throw new OutputException(Error.DATABASE.toString(), r);
    }

}

public void loadProperties() {

    // use try with resource
    try {

        // load a properties file
        input = getClass().getClassLoader().getResourceAsStream("ErrorCodes.properties");
        prop.load(input);

    } catch (IOException ex) {
        ex.printStackTrace();
    } finally {
        if (input != null) {
            try {
                input.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

======================= 主要方法:

public class App {
public static void main(String[] args) {
    ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
    SimpleService simpleService = (SimpleService) context.getBean("simpleServiceProxy");
    SecondService secondService = (SecondService) context.getBean("secondServiceProxy");
    // simple call to demo entry and exit logging to the methods of the
    // class
    simpleService.simpleCall();
    secondService.test2();
    try {
        // processing logic where exception is generated and handled
        simpleService.processingOperator();
    } catch (Exception e) {

        System.out.println(e);
        // TODO
        // Handle exception
    }

    // test the service on a different bean
    secondService.test3();
    context.close();
}

}

您可以使用 Spring 的组件扫描来自动装配您的 bean。

只需添加

<context:component-scan base-package="<PACKAGE>" />

给你的 applicationContext.xml。您必须将“”替换为您要扫描 bean 的包。

另外,你必须用

注释你的bean
@Component

对Spring说"hey, this is a bean"。要将依赖项注入其他 bean,只需使用

标记该字段
@Autowired

他们将被注射。

我希望这会有所帮助:)。

~法比安


编辑:如何使用 spring-aop 和 AspectJ。

你必须添加

<aop:aspectj-autoproxy />

给你的 applicationContext.xml。然后,您必须定义一个 class 来包含您的方面。这个 class 是一个基本的 Spring bean,用

注释
@Component

然后您必须定义要通过切入点执行日志记录的连接点。

示例:

@Around("execution(* <BASE_PACKAGE>..*.* (..))")
public Object logAll(PreecedingJoinPoint joinPoint) throws Throwable {
    Object result = null;
    Throwable throwable = null;

    final StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    try {
        result = joinPoint.proceed();
    } catch (Throwable t) {
        throwable = t;
    }
    stopWatch.stop();

    if (throwable == null) {
        LOGGER.debug("Executed " + joinPoint.getSignature() + " in " + stopWatch.getTime() + "ms!");
    } else {
        LOGGER.debug("Executed " + joinPoint.getSignature() + " in " + stopWatch.getTime() + "ms! Threw an exception: " + throwable);
        throw throwable;
    }
    return result;
}

您通过 joinPoint.proceed() 继续执行。重要的是你 return 结果!否则,每个方法都将 return null!还有,抛出的异常一定要抛出,否则会被压制。