\$\begingroup\$
\$\endgroup\$
1
I went through some of the stuffs on net regarding spring AOP and wrote a Spring AOP logger.
Can you guys check my code and give your valuable inputs to improve it or if it is not proper, give me an another example of how can I achieve it?
My Code is as below :
@Aspect
public class SpringAOPLogger {
@Around("execution(* com.sample.dao.*.*(..)) || execution(* com.sample.service.*.*(..))"
+ "|| execution(* com.sample.controller.*.*(..))")
public Object logMethod(ProceedingJoinPoint joinPoint) throws Throwable {
String className = joinPoint.getTarget().getClass().getSimpleName();
final Logger logger = Logger.getLogger(joinPoint.getTarget().getClass());
Object retVal = null;
try {
StringBuffer startMessageStringBuffer = new StringBuffer();
startMessageStringBuffer.append("Entered in ").append(className).append(".");
startMessageStringBuffer.append(joinPoint.getSignature().getName());
startMessageStringBuffer.append("(");
Object[] args = joinPoint.getArgs();
for (Object arg : args) {
startMessageStringBuffer.append(arg).append(", ");
}
if (args.length > 0) {
startMessageStringBuffer.deleteCharAt(startMessageStringBuffer.length() - 1);
}
startMessageStringBuffer.append(")");
//Method Entry Log
logger.debug(startMessageStringBuffer.toString());
StopWatch stopWatch = new StopWatch();
stopWatch.start();
retVal = joinPoint.proceed();
stopWatch.stop();
StringBuffer endMessageStringBuffer = new StringBuffer();
endMessageStringBuffer.append("Exit from ").append(className).append(".");
endMessageStringBuffer.append(joinPoint.getSignature().getName());
endMessageStringBuffer.append("(..); Execution time: ");
endMessageStringBuffer.append(stopWatch.getTotalTimeMillis());
endMessageStringBuffer.append(" ms;");
//Method Exit Log
logger.debug(endMessageStringBuffer.toString());
} catch (Throwable ex) {
StringBuffer errorMessageStringBuffer = new StringBuffer();
// Create error message
logger.error(errorMessageStringBuffer.toString(), ex);
throw ex;
}
return retVal;
}
}
and below is the spring xml configuration for the same :
<aop:aspectj-autoproxy>
<aop:include name="springAopLogger" />
</aop:aspectj-autoproxy>
<bean id="springAopLogger" class="com.sample.utility.SpringAOPLogger" />
Chirag ParmarChirag Parmar
asked Oct 25, 2016 at 10:25
-
\$\begingroup\$ Can anybody please review it? \$\endgroup\$Chirag Parmar– Chirag Parmar2016年11月04日 07:38:51 +00:00Commented Nov 4, 2016 at 7:38
1 Answer 1
\$\begingroup\$
\$\endgroup\$
1
- Use
StringBuilder
instead ofStringBuffer
since the latter is synchronized and you're not sharing the instances in a multi-threading manner. So use ofStringBuilder
would be a bit faster. - Narrow down the scope of
retVal
. Generally speaking, your variables should be as close to the use places as possible. Note that you can move theretVal
declaration and thereturn
statement to thetry
block entirely. - A matter of style, but I would use
final
as much as possible. - Concatenate the
@Around
expression into a single constant if possible and if it's not disallowed by your code convention. - Split your single method into smaller ones. First off, you separate different responsibilities and improve the readability. Note that the message formatting methods return String (why should the call site know what's behind the scenes?). You can shorten the behind-the-scenes object names to simple
builder
as there are no name conflicts. These methods are declared static, and they useJoinPoint
instead ofProceedingJoinPoint
just because it's enough to accept an instance of the first class. AndgetPostMessage
is better to acceptlong
and notStopWatch
-- what if you would useSystem.currentTimeMillis()
? StringBuilder
is a perfect example of the fluent interface concept, so you might want even use it more (and even discard its variables: seegetPostMessage
with a singlereturn
but multiple chainedappend
s).- Joining a sequence of items using a separator is a trivial problem, and you could eliminate use of
deleteCharAt
. Just ignore the very first "imaginary" separator and not append it. Or use GuavaJoiner.appendTo(StringBuilder,Object[])
if possible (can't recall if there is a Java 8StringBuilder
-friendly collector). Note thatappendTo()
from the answer is really an utility-candidate method so you might want to reuse it elsewhere if it's justified. targetClass
is introduced, because I don't know if getting the target is cheap (I believe it's extremely cheap, but this is a particular case -- but this is an interface, and what if you mock yourJoinPoint
to unit-test the logger and don't want thegetTarget
code behind to happen twice?). However, having a variable namedtargetClass
is a good self-describing hint.- Also, usually, a
try
/catch
block can cover the whole method, thusclassName
can be moved into it safely without changing the semantics (but notlogger
because it's used in separate blocks). - Static imports may improve readability, so maybe just
getLogger(...)
instead ofLogger.getLogger(...)
? - And one more thing that I'm not sure about, and it would require more investigation:
StringBuilder
can be replaced with string concatenation. At least for simple cases like https://gist.github.com/lyubomyr-shaydariv/ffdc40df722ca489e14364da8a8c4e30 (those two methods produce the same Java byte-code). See more at https://stackoverflow.com/questions/1532461/stringbuilder-vs-string-concatenation-in-tostring-in-java .
@Aspect
public class SpringAOPLogger {
@Around("execution(* com.sample.dao.*.*(..)) || execution(* com.sample.service.*.*(..)) || execution(* com.sample.controller.*.*(..))")
public Object logMethod(final ProceedingJoinPoint joinPoint)
throws Throwable {
final Class<?> targetClass = joinPoint.getTarget().getClass();
final Logger logger = getLogger(targetClass);
try {
final String className = targetClass.getSimpleName();
logger.debug(getPreMessage(joinPoint, className));
final StopWatch stopWatch = new StopWatch();
stopWatch.start();
final Object retVal = joinPoint.proceed();
stopWatch.stop();
logger.debug(getPostMessage(joinPoint, className, stopWatch.getTotalTimeMillis()));
return retVal;
} catch ( final Throwable ex ) {
logger.error(getErrorMessage(ex), ex);
throw ex;
}
}
private static String getPreMessage(final JoinPoint joinPoint, final String className) {
final StringBuilder builder = new StringBuilder()
.append("Entered in ").append(className).append(".")
.append(joinPoint.getSignature().getName())
.append("(");
appendTo(builder, joinPoint);
return builder
.append(")")
.toString();
}
private static String getPostMessage(final JoinPoint joinPoint, final String className, final long millis) {
return new StringBuilder()
.append("Exit from ").append(className).append(".")
.append(joinPoint.getSignature().getName())
.append("(..); Execution time: ")
.append(millis)
.append(" ms;")
.toString();
}
private static String getErrorMessage(final Throwable ex) {
return ex.getMessage();
}
private static void appendTo(final StringBuilder builder, final JoinPoint joinPoint) {
final Object[] args = joinPoint.getArgs();
for ( int i = 0; i < args.length; i++ ) {
if ( i != 0 ) {
builder.append(", ");
}
builder.append(args[i]);
}
}
}
answered Nov 10, 2016 at 17:13
-
\$\begingroup\$ For simple string concatenation, we needn't use StringBuilder; Java will do that for us. \$\endgroup\$Vito Chou– Vito Chou2018年11月29日 17:17:45 +00:00Commented Nov 29, 2018 at 17:17
Explore related questions
See similar questions with these tags.
lang-java