2222import java .lang .reflect .InvocationHandler ;
2323import java .lang .reflect .InvocationTargetException ;
2424import java .lang .reflect .Method ;
25+ import java .util .HashMap ;
2526import java .util .Map ;
2627
2728import feign .InvocationHandlerFactory ;
2829import feign .InvocationHandlerFactory .MethodHandler ;
2930import feign .Target ;
3031import rx .Observable ;
3132import rx .Single ;
32- import rx .functions .Action1 ;
3333
3434import static feign .Util .checkNotNull ;
3535
@@ -38,11 +38,30 @@ final class HystrixInvocationHandler implements InvocationHandler {
3838 private final Target <?> target ;
3939 private final Map <Method , MethodHandler > dispatch ;
4040 private final Object fallback ; // Nullable
41+ private final Map <Method , Method > fallbackMethodMap ;
4142
4243 HystrixInvocationHandler (Target <?> target , Map <Method , MethodHandler > dispatch , Object fallback ) {
4344 this .target = checkNotNull (target , "target" );
4445 this .dispatch = checkNotNull (dispatch , "dispatch" );
4546 this .fallback = fallback ;
47+ this .fallbackMethodMap = toFallbackMethod (dispatch );
48+ }
49+
50+ /**
51+ * If the method param of InvocationHandler.invoke is not accessible, i.e in a package-private
52+ * interface, the fallback call in hystrix command will fail cause of access restrictions.
53+ * But methods in dispatch are copied methods. So setting access to dispatch method doesn't take
54+ * effect to the method in InvocationHandler.invoke. Use map to store a copy of method
55+ * to invoke the fallback to bypass this and reducing the count of reflection calls.
56+ * @return cached methods map for fallback invoking
57+ */
58+ private Map <Method , Method > toFallbackMethod (Map <Method , MethodHandler > dispatch ) {
59+ Map <Method , Method > result = new HashMap <Method , Method >();
60+ for (Method method : dispatch .keySet ()) {
61+ method .setAccessible (true );
62+ result .put (method , method );
63+ }
64+ return result ;
4665 }
4766
4867 @ Override
@@ -72,7 +91,7 @@ protected Object getFallback() {
7291 return super .getFallback ();
7392 }
7493 try {
75- Object result = method .invoke (fallback , args );
94+ Object result = fallbackMethodMap . get ( method ) .invoke (fallback , args );
7695 if (isReturnsHystrixCommand (method )) {
7796 return ((HystrixCommand ) result ).execute ();
7897 } else if (isReturnsObservable (method )) {
0 commit comments