arrière-plan
Dans l'interface RPC, l'appel des scénarios ou l'utilisation de scénarios de proxy dynamique, une conception non détect-throwable se produit parfois, ou dans un scénario de réflexion, une conception invocationTargetException se produit, qui ne sont pas cohérentes avec l'exception que nous attendons, et les informations d'exception réelles sont cachées dans une pile plus profonde. Cet article se concentrera sur l'analyse de la non-indication
Donnez une conclusion d'abord
Lorsque vous utilisez l'interface proxy dynamique JDK, si une exception détectée est lancée lors de l'exécution de la méthode mais que la signature de la méthode ne déclare pas l'exception, elle sera enveloppée dans la classe de procuration en tant que non-ECLARDTHROWABLEException.
Restaurer le problème
// Définition de l'interface Interface publique Iservice {void foo () lève SQLEXception;} public class ServiceIMPl implémente Iservice {@Override public void foo () lance sqlexception {throw new sqException ("i test lance une exception vérifiée"); }} // Classe publique Dynamic Proxy IserviceProxy implémente InvocationHandler {Private Object Target; IServiceProxy (objet Target) {this.target = cible; } @Override Public Object Invoke (Proxy d'objet, méthode de la méthode, objet [] args) lève le throwable {return method.invoke (cible, args); }} classe publique MAINTest {public static void main (String [] args) {iService Service = new ServiceImpl (); IService ServiceProxy = (iService) proxy.newProxyInstance (service.getClass (). GetClassLoader (), service.getClass (). GetInterfaces (), new IserviceProxy (service)); essayez {ServiceProxy.foo (); } catch (exception e) {e.printStackTrace (); }}}Exécutez le plus haut ci-dessus et la pile d'exception est
java.lang.reflect.undeclaredThrowableException à com.sun.proxy. $ proxy0.foo (source inconnue) sur com.learn.reflect.mainst.main (maintest.java:16) causée par: java.lang.reflect.invocationtargexception att Sun.Reflect.NativeMethodAccessOrimpl.invoke0 (méthode native) à Sun.Reflect.NativeMethodAccessOrimp.invoke (Nativemethodaccessorimpempl.java:62) à Sun.Reflect.delegatingMethodaccessorimp.invoke (DelegatingMethodAccessorImml java.lang.reflect.method.invoke (method.java:498) sur com.learn.reflect.iserviceproxy.invoke (iServiceproxy.java:19) ... 2 morecausé par: java.sql.sqlexception: Je teste une exception vérifiée à une exception vérifiée à une exception vérifiée à une exception vérifiée à une exception vérifiée à une exception vérifiée AT Vérifie com.learn.reflect.serviceImpl.foo (serviceImpl.java:11) ... 7 plus
Ce que nous attendons est
java.sql.sqlexception: je teste lancer une exception vérifiée sur com.learn.reflect.serviceImpl.foo (serviceImpl.java:11) ...
Analyse des causes
Dans la restauration du problème ci-dessus, la vraie sqlexception est enveloppée dans deux couches, d'abord enveloppée par invocationTargetException, puis enveloppée par une neclaredthrowableException. Parmi eux, InvocationTargetException est l'exception détectée, et UnclaredThrowableException est l'exception d'exécution. Pourquoi est-il enveloppé? Il commence également par la classe proxy générée par Dynamic Proxy.
Le proxy dynamique JDK générera la classe d'implémentation spécifique de l'interface déléguée à l'exécution. Nous générons manuellement le fichier de classe via ProxyGenerator, puis utilisons l'idée pour analyser le fichier de classe pour obtenir la classe de proxy spécifique: intercepter la pièce:
Classe finale publique IserviceProxy 1 $ étend les outils de proxy Iservice {Méthode statique privée M1; Méthode statique privée M2; Méthode statique privée M3; Méthode statique privée M0; public IserviceProxy $ (invocationhandler var1) lance {super (var1); } public final void foo () lève sqlexception {try {super.h.invoke (this, m3, (object []) null); } catch (runtimeException | sqlexception | error var2) {throw var2; } Catch (Throwable Var3) {Throw New UnclaredThrowableException (var3); }} static {try {m1 = class.forname ("java.lang.object"). getMethod ("equals", new class [] {class.forname ("java.lang.object")}); m2 = class.forname ("java.lang.object"). getMethod ("toString", new class [0]); m3 = class.forname ("com.learn.reflect.iservice"). getMethod ("foo", new class [0]); m0 = class.forname ("java.lang.object"). getMethod ("hashcode", new class [0]); } catch (NosuchMethodexception var2) {Throw New NosuchMetHoDerror (var2.GetMessage ()); } catch (classNotFoundException var3) {lance un nouveau noclassdeffoundError (var3.getMessage ()); }}}Lors de l'appel de la méthode FOO de la "classe Delegate", la méthode FOO de la classe procassée est-ce que le 1 $ est appelé, et la logique principale de la classe proxy est d'appeler la méthode invoquée de l'invocationHandler. La logique de la gestion des exceptions est de lancer directement RuntimeException, l'exception déclarée par l'interface, et l'erreur est lancée, et d'autres exceptions sont enveloppées comme non détect-throwableException. À ce stade, peut-être que vous l'avez déjà, peut-être avez-vous une question, dans l'implémentation de l'interface, il est en effet de lancer une nouvelle sqlexception, pourquoi est-il toujours enveloppé? Regardons la méthode invoquée d'IserviceProxy. Il exécute directement la méthode cible par réflexion. C'est le problème. Method.invoke (objet obj, objet ... args) La déclaration de la méthode a été expliqué que si la méthode cible lance une exception, elle sera enveloppée comme invocationTargetException. (Pour plus de détails, veuillez vérifier Javadoc)
Par conséquent, le résumé est: dans l'implémentation de la méthode spécifique, la SQLEXception est lancée et réfléchie et enveloppée comme invocationTargetException. Il s'agit d'une exception vérifiée. Lorsque la classe de proxy gère l'exception, elle constate que l'exception n'est pas déclarée dans l'interface, elle est donc emballée comme une neclaredthrowableException.
Solution
Dans le corps de la méthode invoquée qui implémente InvocationHandler, essayez de capter la méthode.invoke (cible, args); Appelez et jetez la cause de InvocationTargetException. Tout de suite:
@Override public Object Invoke (Proxy d'objet, méthode de la méthode, objet [] args) lève throwable {try {return metheth.invoke (cible, args); } catch (invocationTargetException e) {throw e.getCause (); }}Hors sujet
Pourquoi une exception vérifiée non déclarée dans la classe de proxy se transforme-t-elle en une exception non détectableable? En raison du principe de l'héritage Java: Lorsqu'une sous-classe remplace la classe parent ou une méthode qui implémente l'interface parent, l'exception lancée doit être dans la liste d'exception prise en charge par la méthode d'origine. La classe proxy implémente l'interface parent ou écrase la méthode de la classe parent
se référer à
https://www.ibm.com/developerworks/cn/java/j-lo-proxy1/index.html#icomements
Résumer
Ce qui précède est l'intégralité du contenu de cet article. J'espère que le contenu de cet article a une certaine valeur de référence pour l'étude ou le travail de chacun. Si vous avez des questions, vous pouvez laisser un message pour communiquer. Merci pour votre soutien à wulin.com.