I am using the below code to log entry, exit and exceptions using aspects. This way I have to define a bean for every class in my application in my ApplicationContext and it becomes cumbersome to maintain such length of bean definitions and their properties. Can you help me simplify this? I don't think it is appropriate design to define bean everytime I create a class. Help is appreciated, thanks in advance.
<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 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());
}
============================== ExceptionLogger 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();
}
}
}
}
======================= Main method:
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();
}
}
答案 0 :(得分:3)
you can use Spring's component scan to autowire your beans.
Simply add
<context:component-scan base-package="<PACKAGE>" />
to your applicationContext.xml. You have to replace "" with the package you want to scan for beans.
Also, you have to annotate your beans with
@Component
to say "hey, this is a bean" to Spring. To inject dependencies into other beans, simply tag the field with
@Autowired
and they will be injected.
I hope this will help :).
~Fabian
EDIT: How to use spring-aop and AspectJ.
You have to add
<aop:aspectj-autoproxy />
to your applicationContext.xml. Then, you have to define a class that will contain your aspects. This class is a basic Spring bean, annotated with
@Component
Then you have to define the join-points where you want to execute your logging via pointcuts.
Example:
@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;
}
You continue the execution via joinPoint.proceed(). It is important that you return the result! Otherwise, every method will return null! Also, you must throw the thrown exception, otherwise it will be suppressed.