배경
RPC 인터페이스 호출 시나리오 또는 동적 프록시 시나리오를 사용하는 경우, 노출되지 않은 프록시 시나리오를 사용하거나 때때로 발생하거나 반사 시나리오에서 발생하는 경우, invocationTargetexception이 발생하며, 이는 예외와 일치하지 않으며 실제 예외 정보는 더 깊은 스택에 숨겨져 있습니다. 이 기사는 노출되지 않은 예고의 분석에 중점을 둘 것입니다
먼저 결론을 내립니다
JDK 동적 프록시 인터페이스를 사용하는 경우, 메소드 실행 중에 감지 된 예외가 발생하지만 메소드 서명이 예외를 선언하지 않으면 프록시 클래스에서 미등록 이용 가능한 예고로 래핑됩니다.
문제를 복원하십시오
// 인터페이스 정의 public interface iservice {void foo ()가 sqlexception;} public class servicempl emplements iservice {@override public void foo () sqlexception {새 sqlexception ( "검사 된 예외를 던집니다"); }} // 동적 프록시 공개 클래스 IserviceProxy는 invocationHandler {private 객체 대상; iserviceproxy (객체 대상) {this.target = target; } @override public object invoke (개체 프록시, 메소드 메소드, 개체 [] args) 던져 버릴 수있는 {return method.invoke (target, args); }} public class maintest {public static void main (string [] args) {iservice service = new ServiceMpl (); iservice serviceproxy = (iservice) proxy.newproxyInstance (service.getClass (). getClassLoader (), service.getClass (). getInterfaces (), new IserviceProxy (service)); try {serviceproxy.foo (); } catch (예외 e) {e.printstacktrace (); }}}위의 메인 테스트를 실행하면 예외 스택이 있습니다
com.sun.proxy. $ proxy0.foo (알 수없는 소스)에서 java.lang.reflect.undeclaredthrowableException : java.lang.reflect.invocationTargetexception에 의해 야기 된 com.sun.proxy. $ proxy0.foo (알 수없는 출처) sun.reflect.nativeMethodaccessorimpl.invoke0 (기본 메소드)에서 sun.reflect.nativeMethodaccessorimpl.invoke (nativeMeThodAccessorImpl.java:62)에서 sun.reflect.delegatingMethodaccessorimpl.invoke (at at at at at at atmethorimpl.4) java.lang.reflect.method.invoke (method.java:498) at com.learn.reflect.iserviceproxy.invoke (iserviceproxy.java:19) ... 2 Morecaused by : java.sql.sqlexection : 나는 검사 된 예외를 테스트합니다. com.learn.reflect.serviceimpl.foo (serviceimpl.java:11) ... 7 더
우리가 기대하는 것은
java.sql.sqlexception : com.learn.reflect.serviceimpl.foo (serviceimpl.java:11)에서 확인 된 예외를 테스트합니다.
원인 분석
위의 문제 복원에서 실제 sqlexception은 두 층으로 래핑되어 처음으로 invocationtargetexception에 의해 래핑 된 다음 노출되지 않은 추방에 의해 포장됩니다. 그중에서도 InvocationTargeteXception은 감지 된 예외이며, 선고되지 않은 예외는 런타임 예외입니다. 왜 포장 되었습니까? 또한 Dynamic Proxy에 의해 생성 된 프록시 클래스로 시작합니다.
JDK Dynamic Proxy는 런타임에서 대의원 인터페이스의 특정 구현 클래스를 생성합니다. proxygenerator를 통해 클래스 파일을 수동으로 생성 한 다음 아이디어를 사용하여 클래스 파일을 구문 분석하여 특정 프록시 클래스를 얻습니다.
공개 최종 클래스 IserviceProxy $ 1 연장 프록시 구현 Iservice {private static method m1; 개인 정적 방법 M2; 개인 정적 방법 M3; 개인 정적 방법 M0; public iserviceproxy $ 1 (invocationHandler var1) 던지기 {super (var1); } public final void foo ()는 sqlexception {try {super.h.invoke (this, m3, (Object []) null); } catch (runtimeexception | sqlexception | Error var2) {Throw var2; } catch (Throwable Var3) {Throw New NewlaredThrowableException (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) {새로운 nosuchmethoderror (var2.getMessage ()); } catch (classNotFoundException var3) {새 noclassDeffoundError (var3.getMessage ()); }}}"Delegate Class"의 FOO 메소드를 호출 할 때 프록시 클래스 IserviceProxy $ 1의 FOO 메소드가 실제로 호출되고 프록시 클래스의 주요 논리는 호출 핸들러의 호출 방법을 호출하는 것입니다. 예외 처리의 논리는 runtimeexception을 직접 던지는 것입니다. 인터페이스에 의해 선언 된 예외는 오류가 발생하고 다른 예외는 노출되지 않은 예고로 래핑됩니다. 이 시점에서, 아마도 당신은 이미 그것을 얻었을 것입니다. 아마도 질문이있을 수도 있습니다. 인터페이스 구현에서 실제로 새로운 sqlexception을 던질 것입니다. 왜 여전히 포장 된가? IserviceProxy의 호출 방법을 살펴 보겠습니다. 반사를 통해 대상 방법을 직접 실행합니다. 이것이 문제입니다. method.invoke (Object OBJ, Object ... Args) 메소드 선언은 대상 메소드가 예외를 던지면 invocationTargetexception으로 래핑 될 것이라고 설명되었습니다. (자세한 내용은 Javadoc을 확인하십시오)
따라서 요약은 다음과 같습니다. 특정 방법 구현에서 Sqlexception은 던져져 반사되어 invociationTargetexception으로 랩됩니다. 이것은 점검 된 예외입니다. 프록시 클래스가 예외를 처리하면 인터페이스에서 예외가 선언되지 않았으므로 노출되지 않은 예고로 포장됩니다.
해결책
InvocationHandler를 구현하는 Invoke 메소드 본문에서 Method.Invoke (Target, Args)를 잡으십시오. 전화를 걸어 avocationTargetexception의 원인을 던집니다. 지금 바로:
@override public Object Invoke (Object Proxy, Method Method, Object [] args) 던지기 가능 {try {return method.invoke (target, args); } catch (invocationTargeteXception e) {Throw e.getCause (); }}주제에서
프록시 클래스에서 선언되지 않은 점검 예외가 노출되지 않은 예외로 변하는 이유는 무엇입니까? Java 상속 원칙 원칙 : 서브 클래스가 상위 클래스 또는 상위 인터페이스를 구현하는 메소드를 무시할 때, 던진 예외는 원래 메소드에서 지원되는 예외 목록 내에 있어야합니다. 프록시 클래스는 상위 인터페이스를 구현하거나 부모 클래스 방법을 덮어 씁니다.
참조하십시오
https://www.ibm.com/developerworks/cn/java/j-lo-proxy1/index.html#icomments
요약
위는이 기사의 전체 내용입니다. 이 기사의 내용에 모든 사람의 연구 나 작업에 대한 특정 참조 가치가 있기를 바랍니다. 궁금한 점이 있으면 의사 소통을 위해 메시지를 남길 수 있습니다. Wulin.com을 지원 해주셔서 감사합니다.