當習慣用Spring之後
突然遇到不使用Spring的系統真的很不方便…
要寫一堆Factory...
更別提到寫一堆log真的會煩死人…
於是興起了這個念頭…
何不自已寫一個Singleton Bean Factory與AOP做LOG
最好能夠用自定義的ANNOTATION就能作動…
ok… 搞了一個鐘頭… 還好不太難
主要在中間層service的部份做log就夠了
先來看成果:
2013/4/6 上午 02:34:54 idv.tsaipifong.MyLogger invoke
資訊:
代理類別:sun.proxy.$Proxy4
2013/4/6 上午 02:34:54 idv.tsaipifong.MyLogger invoke
資訊:
執行類別:idv.tsaipifong.MyService
2013/4/6 上午 02:34:54 idv.tsaipifong.MyLogger invoke
資訊:
執行方法:doSome01
2013/4/6 上午 02:34:54 idv.tsaipifong.MyLogger invoke
資訊:
傳入值:{"傳入值類別 > java.lang.String":"00001"}
2013/4/6 上午 02:34:54 idv.tsaipifong.MyLogger invoke
資訊:
傳回值:{"id":"00001","name":"Pifong Tsai"}
2013/4/6 上午 02:34:54 idv.tsaipifong.MyLogger invoke
資訊:
代理類別:sun.proxy.$Proxy4
2013/4/6 上午 02:34:54 idv.tsaipifong.MyLogger invoke
資訊:
執行類別:idv.tsaipifong.MyService
2013/4/6 上午 02:34:54 idv.tsaipifong.MyLogger invoke
資訊:
執行方法:doException
2013/4/6 上午 02:34:54 idv.tsaipifong.MyLogger invoke
資訊:
傳入值:{"傳入值類別 > java.lang.String":"這是例外訊息"}
2013/4/6 上午 02:34:54 idv.tsaipifong.MyLogger invoke
資訊:
發生例外,訊息如后:
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
java.lang.reflect.Method.invoke(Unknown Source)
idv.tsaipifong.MyLogger.invoke(MyLogger.java:41)
sun.proxy.$Proxy4.doException(Unknown Source)
idv.tsaipifong.Test.main(Test.java:10)
處理例外
相當不錯
記錄了執行類別、方法、傳入值、傳回值、例外資訊
動態代理的AOP主程式如下:(仔細看invoke()就覺得跟Spring AOP的實作有點像)
public class MyLogger implements InvocationHandler {
private Logger logger = Logger.getLogger(this.getClass().getName());
private Object target;
public Object getProxy(Object target) {
this.target = target;
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
try {
logger.info("\n\n代理類別:" + proxy.getClass().getName());
logger.info("\n執行類別:" + target.getClass().getName());
logger.info("\n執行方法:" + method.getName());
if(args==null || args.length<=0){
logger.info("\n傳入值:無傳入值");
}else{
JSONObject json = new JSONObject();
for(Object obj : args){
json.put("傳入值類別 > " + obj.getClass().getName(), obj);
}
logger.info("\n傳入值:" + json.toString());
}
result = method.invoke(target, args);
if(result==null){
logger.info("\n傳回值:無傳回值");
}else{
logger.info("\n傳回值:" + JSONObject.fromObject(result));
}
} catch (Exception e){
StackTraceElement[] ste = e.getStackTrace();
StringBuffer sb = new StringBuffer();
for(StackTraceElement s : ste){
sb.append("\n" + s);
}
logger.info("\n發生例外,訊息如后:" +sb.toString());
throw e; //處理log之後,拋出例外
}
return result;
}
}
動態單一實例工廠主程式如下:
public class ServiceFactory {
private static Map map = null;
private ServiceFactory(){
}
public static Object getInstance(String classname)throws Exception {
if(classname==null){
throw new Exception("Classname is null...");
}
if(map==null){
synchronized(HashMap.class){
map = new HashMap();
}
}
Object obj = null;
synchronized(map){
if(map.get(classname)==null){
Class cls = Class.forName(classname);
//如果有@DoLogger註解,則套上aop proxy
if(cls.isAnnotationPresent(idv.tsaipifong.DoLogger.class)){
MyLogger mylogger = new MyLogger();
map.put(classname, mylogger.getProxy(cls.newInstance()));
}else{
map.put(classname, cls.newInstance());
}
}
obj = map.get(classname);
}
return obj;
}
}
自定義的ANNOTATION如下:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface DoLogger {
}
以上就完成了… 那要怎麼使用呢…!?
一、首先要定義service的介面
public interface IMyService {
public Map doSome01(String str);
public void doException(String msg)throws Exception;
}
二、然後實作介面的類別
如果這個service要做log
就在類別宣告加上自訂的annotation,@DoLogger
沒加就不做log
@DoLogger
public class MyService implements IMyService {
@Override
public Map doSome01(String str) {
Map map = new HashMap();
map.put("id", str);
map.put("name", "Pifong Tsai");
return map;
}
@Override
public void doException(String msg) throws Exception {
throw new Exception(msg);
}
}
三、最後當然要執行一下看看囉~
IMyService myservice = null;
try {
myservice = (IMyService)ServiceFactory.getInstance("idv.tsaipifong.MyService");
myservice.doSome01("00001");
myservice.doException("這是例外訊息");
} catch (Exception e) {
System.out.println("處理例外");
}
運用aop搭配annotation,程式碼就簡潔多了
資料格式驗證、交易等等,都可以用類似的方式去實作
不過Spring已經是很成熟優秀的框架了…
能用就用囉… 不必這麼累還需要自已開發…
小弟實在是千萬個不得已啊…