【问题标题】:Logging entry, exit and exceptions for methods in java using aspects使用方面记录 java 中方法的进入、退出和异常
【发布时间】:2015-10-30 21:35:39
【问题描述】:

我正在使用以下代码使用方面来记录进入、退出和异常。这样,我必须在我的 ApplicationContext 中为我的应用程序中的每个类定义一个 bean,并且维护如此长的 bean 定义及其属性变得很麻烦。你能帮我简化一下吗?我认为每次创建类时都定义 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>

===================== LogEntry 类:

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 类:

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());
}

=============================== 异常记录器类

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();
}

}

【问题讨论】:

    标签: java spring logging aop java.util.logging


    【解决方案1】:

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

    简单添加

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

    到您的 applicationContext.xml。您必须将 "" 替换为要扫描 bean 的包。

    另外,你必须用注释你的豆子

    @Component
    

    对 Spring 说“嘿,这是一个 bean”。要将依赖项注入其他 bean,只需使用

    标记该字段
    @Autowired
    

    它们将被注入。

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

    ~法比安


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

    你必须添加

    <aop:aspectj-autoproxy />
    

    到您的 applicationContext.xml。然后,您必须定义一个包含方面的类。这个类是一个基本的 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() 继续执行。返回结果很重要!否则,每个方法都将返回 null!另外,抛出的异常一定要抛出,否则会被抑制。

    【讨论】:

    • 我们如何在这种方法中定义拦截器,就像我的问题一样?
    • 您可以使用 spring-aop(与 AspectJ)。你也有更多的可能性;)。它有点复杂,但只是一点点。我会将其添加到我的答案中。
    • 感谢您的意见,您能否通过回答这个相关的问题来帮助我。 stackoverflow.com/questions/33446784/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-25
    • 2013-01-30
    • 2012-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-28
    相关资源
    最近更新 更多