使用方面记录 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!还有,抛出的异常一定要抛出,否则会被压制。
我正在使用以下代码使用方面记录进入、退出和异常。这样,我必须在我的 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!还有,抛出的异常一定要抛出,否则会被压制。