項目中總要發佈一下服務供系統內外調用,爲了方便排查錯誤,入參出參都要以日誌的形式記錄下來。
傳統作法:缺點一目瞭然,參數少的時候只能說還好,參數一多,煩不勝煩,浪費時間。
- private static final Logger logger = Logger.getLogger(HelloServiceImpl.class);
- public String sayHello(String name,String words) {
- logger.info("remote input:name="+name+",words="+words);
- //業務邏輯
- String result = "Hello"+name+","+words);
- logger.info("remote output:result="+result);
- return result;
- }
因而基於java.lang.annotation,借鑑AOP的思想,將日誌功能作成一個切面,橫向切入到業務邏輯先後(方法開始前和結束後)。
因爲java的反射是不能獲取方法的參數名的,網上有一個第三方工具包JAVAssist提供了現成的方法,但筆者以爲挺麻煩的,決定使用約定優於配置的方式來獲取方法的參數名。你們大概猜到是什麼了吧?對!就是建一個自定義註解。
- @Target (ElementType.METHOD)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface AOPLog4jAnnotation {
- String paramCollection();
- }
在須要日誌切面的地方(方法)加上這個註解。
- public class HelloServiceImpl implements HelloService{
- @Override
- @AOPLog4jAnnotation(paramCollection="name,words")
- public String sayHello(String name,String words) {
- String text = "Hello "+name+"!"+words+".";
- return text;
- }
- }
你們也看到了,筆者的這種方式的明顯的缺點:須要按必定規則(把參數按順序填進去,並用英文逗號隔開)把方法參數名配置在註解中。
- @AOPLog4jAnnotation(paramCollection="name,words")
惟一的好處是...只須要複製上面這行,而後遵循規則填寫參數名。
惟二的好處是...日誌格式統一。
完了,傷心了,感受實用性不強,哎。
算了,把代碼都貼上吧,留着之後改進。
Spring配置:
- <bean id="helloService" class="com.aop.log4j.service.impl.HelloServiceImpl" />
- <bean id="aspect" class="com.aop.log4j.aspect.HelloAspect"/>
- <aop:config>
- <aop:pointcut id="pointcut" expression="execution(* com.aop.log4j.service.HelloService.*(..)))" />
- <aop:aspect ref="aspect">
- <aop:around pointcut-ref="pointcut" method="arround"/>
- </aop:aspect>
- </aop:config>
切面代碼:
- public class HelloAspect {
- private static final Logger logger = Logger.getLogger(HelloAspect.class);
- private static final String DOT = ".";//點號
- private static final String COMMA = ",";//逗號
-
- public Object arround(ProceedingJoinPoint joinPoint) throws Throwable {
- StringBuilder sb = new StringBuilder();
- Object[] paramValues = joinPoint.getArgs();//獲取參數值
- String[] paramNames = new String[paramValues.length];
- Class<? extends Object> invokeClass = joinPoint.getTarget().getClass();
- String signatureName = joinPoint.getSignature().getName();
- Method methods[] = invokeClass.getMethods();
- for (Method method : methods) {
- if(method.getName().equals(signatureName)) {
- String paramCollection = method.getAnnotation
- (AOPLog4jAnnotation.class).paramCollection();//獲取註解值
- String[] names = paramCollection.split(COMMA);
- System.arraycopy(names, 0, paramNames, 0, names.length);
- }
- }
- for (int i = 0; i < paramValues.length; i++) {
- sb.append(paramNames[i] + "=" + paramValues[i] + COMMA);
- }
- //入參日誌
- logger.info(invokeClass + DOT + signatureName + ",remote input:"
- + sb.toString().substring(0, sb.length() - 1));
- try {
- Object result = joinPoint.proceed();
- //出參日誌
- logger.info(invokeClass + DOT + signatureName
- + ",remote output:" + result);
- return result;
- } catch (Exception e) {
- logger.error(invokeClass + DOT + signatureName
- + " invoke error");
- }
- return null;
- }
- }
調用HelloService服務,輸出:
- [INFO] 2012-10-03 11:54:29,807 [com.aop.log4j.aspect.HelloAspect.arround] - class com.aop.log4j.service.impl.HelloServiceImpl.sayHello,remote input:name=Java,words=I love you.
- [INFO] 2012-10-03 11:54:29,808 [com.aop.log4j.aspect.HelloAspect.arround] - class com.aop.log4j.service.impl.HelloServiceImpl.sayHello,remote output:Hello Java!I love you.
oschina好像不能插入附件,請移步去個人iteye博客下載吧,謝謝。 java
http://dl.iteye.com/topics/download/0e1af44b-81d0-351c-badb-5e758093767b express