- 浏览: 804845 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (360)
- Java (101)
- JPA/Hibernate (10)
- Spring (14)
- Flex/BlazeDS (37)
- Database (30)
- Lucene/Solr/Nutch (0)
- Maven/Ant (25)
- CXF/WebService (3)
- RPC/RMI/SOAP/WSDL (1)
- REST (6)
- TDD/BDD/JUnit (1)
- Servlet/JSP (2)
- AI/MachineLearning (3)
- Resource (1)
- 字符编码 (2)
- OOA/OOPS/UML (5)
- DesignPattern (8)
- 算法与数据结构 (11)
- Web&App Server (13)
- 并发&异步&无阻塞 (7)
- Entertainment (4)
- JavaScript/ExtJS (45)
- CodeStyle&Quality (1)
- svn/git/perforce (8)
- JSON (2)
- JavaScriptTesting (4)
- Others (6)
- RegularExpression (2)
- Linux/Windows (12)
- Protocal (2)
- Celebrities (1)
- Interview (1)
- 计算机语言 (1)
- English (2)
- Eclipse (5)
- TimeZone/时区 (1)
- Finance (1)
- 信息安全 (1)
- JMS/MQ (2)
- XSD/XML/DTD (3)
- Android (4)
- 投资 (3)
- Distribution (3)
- Excel (1)
最新评论
-
qdujunjie:
如果把m换成具体的数字,比如4或者5,会让读者更明白
m阶B树中“阶”的含义 -
java-admin:
不错,加油,多写点文章
关于Extjs的mixins和plugin -
xiehuaidong880827:
你好,我用sencha cmd打包完本地工程后,把app.js ...
ExtJS使用Sencha Cmd合并javascript文件为一个文件 -
KIWIFLY:
lwpan 写道inverse = "true&qu ...
Hibernate中什么时候使用inverse=true -
luedipiaofeng:
good
消除IE stop running this script弹出框
java动态代理UndeclaredThrowableException InvocationTargetException
- 博客分类:
- Java
原文链接:说说动态代理中碰到的一个小问题 https://my.oschina.net/GivingOnenessDestiny/blog/153300
JDK内置 Proxy类和 InvocationHandler接口来提供动态代理的实现。在实现连接池的时候动态代理就可以派上用场了。通过代理接管close方法, connectoin关闭的时候就不需要真正关闭,而只是放回连接池,具体实现原理可以参考红薯关于连接池的文章。
我要写的呢是关于在测试使用动态代理时碰到的一个问题,先看我的代码:
首先是接口 IFunction
public interface IFunction {
void doSomething () throws IllegalStateException;
}
接口实现 FunctionImpl
public class FunctionImpl implements IFunction {
@Override
public void doSomething() throws IllegalStateException {
// 方法什么也不做, 只抛异常
throw new IllegalStateException();
}
}
拦截 IFunctioin 的动态代理类 FunctionHandler
public class FunctionHandler implements InvocationHandler{
private IFunction fun;
public FunctionHandler(IFunction function) {
this.fun = function;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(fun, args);
}
}
最后是简单的调用
public class Client {
public static void main(String[] args) {
IFunction fun = (IFunction) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class[]{IFunction.class}, new FunctionHandler(new FunctionImpl()));
try {
fun.doSomething();
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
}
如此,一个简单的动态代理完成了, 一眼瞥上去没什么问题, 可惜一运行就抛异常了
Exception in thread "main" java.lang.reflect.UndeclaredThrowableException
at com.sun.proxy.$Proxy0.doSomething(Unknown Source)
at designpattern.proxy.Client.main(Client.java:18)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at designpattern.proxy.FunctionHandler.invoke(FunctionHandler.java:21)
... 7 more
Caused by: java.lang.IllegalStateException
at designpattern.proxy.FunctionImpl.doSomething(FunctionImpl.java:9)
... 12 more
很奇怪啊,接口只声明了IllegalStateException, 结果却抛出了 InvocationTargetException 及 UndeclaredThrowableException.
接下来我们看看这两个不速之客是如何产生的。
首先这两个异常肯定是接口实现类抛出 IllegalStateException 引起的, 于是可以定位到 java.lang.reflect.Method 的 invoke(Object obj, Object... args), 该方法文档已经说明: 当代理的方法抛出异常时 invoke(Object obj, Object... args) 方法会抛出 InvocationTargetException 异常, 也就是说我的 IllegalStateException 此时会被包装成 InvocationTargetException。
好,现在已经知道 InvocationTargetException 是因为Method反射机制包装产生的。
接下来再看 UndeclaredThrowableException 如何产生。
在 InvocationHandler 声明的方法 invoke(Object proxy, Method method, Object[] args) 的文档中有这么一句话
Throwable the exception to throw from the method invocation on the proxy instance. The exception's type must be assignable either to any of the exception types declared in the throws clause of the interface method or to the unchecked exception types java.lang.RuntimeException or code java.lang.Error. If a checked exception is thrown by this method that is not assignable to any of the exception types declared in the throws clause of the interface method, then an UndeclaredThrowableException containing the exception that was thrown by this method will be thrown by the method invocation on the proxy instance.
这里也就是说被代理接口的方法在执行的时候抛出的受检异常必须是接口定义中声明的异常, 如果抛出的受检异常未被接口声明, 那么此时这个异常就会被包装成UndeclaredThrowableException。
那么也就清楚了,之前已经看到Method.invoke()时抛出了异常InvocationTargetException 恰好不在 接口声明的异常范围内, 因此动态代理执行的时候会抛出异常 UndeclaredThrowableException。
对于这个问题可以改良下 FunctionHandler 的代码就可解决
public class FunctionHandler implements InvocationHandler{
private IFunction fun;
public FunctionHandler(IFunction function) {
this.fun = function;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
return method.invoke(fun, args);
} catch (InvocationTargetException e) {
throw e.getCause();
}
}
}
这样再次运行测试得到的结果如下
java.lang.IllegalStateException
at designpattern.proxy.FunctionImpl.doSomething(FunctionImpl.java:9)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at designpattern.proxy.FunctionHandler.invoke(FunctionHandler.java:23)
at com.sun.proxy.$Proxy0.doSomething(Unknown Source)
at designpattern.proxy.Client.main(Client.java:18)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
两个不速之客已经消失了, "老板再也不用担心我的异常", 哈哈。
发表评论
-
sapjco3 notes
2019-03-21 14:51 1164sapjco https://support.sap.com/ ... -
使用RestTemplate发送post JSON请求
2019-01-12 17:30 4742private final String BASE_URL = ... -
使用RestTemplate发送post JSON请求
2019-01-12 17:30 3511private final String BASE_URL = ... -
Spring线程池ThreadPoolTaskExecutor
2018-08-06 09:51 1890<!-- spring thread pool ex ... -
Spring注解事物@Transactional不工作
2018-08-02 18:50 2679“In proxy mode (which is the de ... -
创建前缀索引报长度超出错误
2018-07-25 15:44 1732表结构定义如下: CREATE TABLE `sku` ( ` ... -
Mysql Varchar字符长度
2018-07-25 15:23 1353`sku_name` VARCHAR(200) NOT NUL ... -
使用 Spring RestTemplate 发送 post 请求
2018-07-23 18:49 11730注意点: 1)使用MultiValueMap设置入参,不要使 ... -
Java动态代理Dynamic Proxy
2018-07-21 16:33 817JAVA学习篇--静态代理VS动态代理 https://blo ... -
分布式实时日志分析解决方案 ELK 部署架构
2018-07-20 09:52 1190原文链接:http://www.importn ... -
为什么HashMap容量一定要为2的幂呢?
2018-07-19 10:07 1728原文链接:https://blog.csdn.net/wang ... -
为什么计算HashCode时通常选择31这个数?
2018-07-19 10:05 1423摘自http://www.importnew.com/2208 ... -
jackson自定义序列化和反序列化
2018-07-10 18:47 2244原文链接:https://blog.csdn.net/liu ... -
Pay special attention when modifying online running system
2017-06-23 10:25 0Never remove any properties, me ... -
Map中的Null key, Null Value
2017-06-14 10:52 1946ConcurrentHashMap的key和value都不能为 ... -
Java语法糖
2017-06-05 20:03 531Java语法糖之foreach http://www.imp ... -
Java集合相关
2017-05-24 17:55 0Java集合框架:ArrayList http://www. ... -
Java数据类型的转换:隐式(自动)转换与强制转换
2017-05-14 10:46 0http://blog.csdn.net/u011240877 ... -
分布式开放消息系统(RocketMQ)的原理与实践
2017-05-07 19:55 732分布式开放消息系统(RocketMQ)的原理与实践 http ... -
面试知识点复习(Interview knowledge review)
2017-05-07 18:39 0JVM,多线程相关知识 http://darrenzhu.it ...
相关推荐
在使用Java动态代理时出现了一个很棘手的问题,实现类里抛出了一个自定义异常,但外面捕获不到。 虽然使用 printStack 可以输出调试信息,但通过 getMessage 获取不到提示,因为项目需求是捕捉到同一种自定义异常...
import java.lang.reflect.UndeclaredThrowableException; import java.math.BigInteger; import java.security.GeneralSecurityException; import java.util.Date; public class TOTP { // 共享密钥 private ...
### JAVA程序员面试必备的32个要点详解 #### 1. final、finally、finalize 的区别 - **final**: 用于声明变量、方法或类时,表示该元素是不可变的。例如,当一个变量被声明为final时,则该变量不能重新赋值;如果是...
超级有影响力的Java面试题大全文档 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节。...
### JAVA程序员常见的面试题解析 #### 一、final, finally, finalize 的区别 - **final**: 关键字“final”在 Java 中有多种用途。它可以用于声明类、方法或变量。当一个类被声明为 final 时,它不能被继承。如果...
在Java 8引入Lambda表达式后,开发者可以更简洁地编写代码,但同时也带来了一些挑战,其中之一就是Lambda表达式不能抛出检查异常(Checked Exception)。在传统的Java代码中,我们通常会捕获并处理这些检查异常,但...
在 Java 语言中,Runtime Exception 是指在程序运行时抛出的异常。常见的 Runtime Exception 有 ArithmeticException、ArrayStoreException、BufferOverflowException、BufferUnderflowException、...