正文
Void
run
()
{
cons.setAccessible(
true
);
return
null
;
}
});
}
return
cons.newInstance(
new
Object[]{h});
}
catch
(IllegalAccessException|InstantiationException e) {
throw
new
InternalError(e.toString(), e);
}
catch
(InvocationTargetException e) {
Throwable t = e.getCause();
if
(t
instanceof
RuntimeException) {
throw
(RuntimeException) t;
}
else
{
throw
new
InternalError(t.toString(), t);
}
}
catch
(NoSuchMethodException e) {
throw
new
InternalError(e.toString(), e);
}
}
④ 最后就是实现我们的
invoke
方法了,先看一下方法的结构和我们的实现:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
LOGGER.info("{} 方法的入参:{}", methodName, args);
try {
Object result = method.invoke(realSubject, args);
LOGGER.info("{}方法的返回结果为:{}", methodName,result);
return result;
} catch (Throwable e) {
LOGGER.error("执行目标方法发生异常,异常:", e);
return Boolean.FALSE;
} finally {
LOGGER.info("方法执行完成");
}
}
是不是很简单呢,下面是入口程序:
package proxy;
public class Bootstrap {
public static void main(String[] args){
demo1();
}
public static void demo1(){
ISmsSupport smsSupport = new SmsSupportImpl();
ISmsSupport proxy = (ISmsSupport) new SmsProxy(smsSupport).getProxy();
proxy.sendMsg("hello world", "110");
}
}
我们先看一下运行结果
先把
SmsSupportImpl
中的
int i = 1/ 0;
注释掉正常运行:
17:12:26.976 [main] INFO proxy.SmsProxy - sendMsg 方法的入参:[hello world, 110]
hello world,110
17:12:26.980 [main] INFO proxy.SmsProxy - sendMsg方法的返回结果为:true
17:12:26.980 [main] INFO proxy.SmsProxy - 方法执行完成
再取消注释,发生异常:
17:13:31.169 [main] INFO proxy.SmsProxy - sendMsg 方法的入参:[hello world, 110]
17:13:31.175 [main] ERROR proxy.SmsProxy - 执行目标方法发生异常,异常:
java.lang.reflect.InvocationTargetException: null
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at proxy.SmsProxy.invoke(SmsProxy.java:63)
at com.sun.proxy.$Proxy0.sendMsg(Unknown Source)
at proxy.Bootstrap.demo1(Bootstrap.java:19)
at proxy.Bootstrap.main(Bootstrap.java:12)
Caused by: java.lang.ArithmeticException: / by zero
at proxy.SmsSupportImpl.sendMsg(SmsSupportImpl.java:13)
... 8 common frames omitted
17:13:31.175 [main] INFO proxy.SmsProxy - 方法执行完成
从上面的运行结果可以看出,打印了入参和返回结果,正确拦截了异常并打印了异常信息,还有方法调用完成的日志。好啦!到这里动态代理的实现就结束了,接下来看看为什么要使用动态代理。
在这个案例中其实体现不出来动态代理的优势,为什么呢,因为要打印日志的类太少了,完全可以采用硬编码的方式去实现,那么想象一下有一万个类,每个类中有10个方法,每个方法之前都没有打日志,现在要你去实现为每个方法都实现入参和返回结果打印,你还会采用硬编码的方式吗?此时动态代理就发挥了作用,你只需要写一个日志代理类,专门用来完成这个打印功能,上代码:
package proxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class LogProxy<T> implements InvocationHandler {
private final static Logger LOGGER = LoggerFactory.getLogger(LogProxy.class);
private T realSubject;
public LogProxy(T realSubject) {
this.realSubject = realSubject;
}
public T getProxy() {
Class<?> subjectClass = realSubject.getClass();
return (T) Proxy.newProxyInstance(subjectClass.getClassLoader(), subjectClass.getInterfaces(), this);
}
@Override