用 java.lang.reflect.Proxy 制作类似AOP 的方法调用 Log 层
个人认为,java.lang.reflect.Proxy 简直是懒人必备的工具。
如,我负责编写一个分布式系统的一个服务,别的应用要调用我的服务的 RMI接口方法。而多人开发有着一个必然的缺点:每人负责的模块均对外提供接口,但事情往往会因为接口的定义者、实现者、使用者间对接口理解的偏差,而在软件的开发中引出不少麻烦。于是,接口调用日志就有作用了。特别是 RMI Interface 的日志。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.text.MessageFormat;
import java.util.Arrays;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
/**
*Afactoryofmethodinvokeloginterceptor.
*logtheinvokeparamandresult.
*@param<TargetInterface>
*/
publicclass InvokeLogProxyFactory<TargetInterface> {
publicclass MyInvocationHandler implements InvocationHandler {
private Level logLevel;
private TargetInterface impl;
public MyInvocationHandler(Level logLevel, TargetInterface impl) {
this.logLevel = logLevel;
this.impl = impl;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
final Logger log = Logger.getLogger( impl.getClass() );
String msg = MessageFormat.format( "Calling method {0}({1})", method.getName(), Arrays.toString( args ) );
log.log( logLevel, msg );
Object returnedResult = null;
try {
returnedResult = method.invoke( impl, args );
} catch ( InvocationTargetException e ) {
String msg1 = MessageFormat.format( "Call method[{0}]: catch exceptions:", method.getName() );
log.log( logLevel, msg1, e.getCause() );
throw e.getCause();
} catch( Throwable e ) {
log.error( "Runtime exception:", e );
throw e;
}
log.log( logLevel, "returned val=" + returnedResult );
return returnedResult;
}
}
@SuppressWarnings("unchecked")
public TargetInterface create(TargetInterface impl, Level logLevel) {
MyInvocationHandler handler = new MyInvocationHandler( logLevel, impl);
Object result = Proxy.newProxyInstance(impl.getClass().getClassLoader(),
impl.getClass().getInterfaces(),
handler);
return (TargetInterface) result;
}
}