I have an application which exposes a service via Spring's RMI proxy mechanism. There is a problem whereby sometimes a "blip" on the file-server it has its JARs stored on causes an invocation to propagate a NoClassDefFoundError
back to the caller.
So far, so fair enough. The thing is, I would like my app to just crash if this happens - i.e. if an Error
is going to be propagated back开发者_如何学Python out to the caller.
Note that I already have an UncaughtExceptionHandler
in the app and this is not being invoked (because the exception is not really uncaught)
If you are exposing the RMI service via RmiServiceExporter
(or any other subclass of RemoteExporter
), then you can inject arbitrary interceptors into the call stack, which will be invoked whenever the RMI service is invoked.
These interceptors could trap any thrown NoClassDefFoundError
, and call System.exit()
.
For example:
public class ExitInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
try {
return methodInvocation.proceed();
} catch (NoClassDefFoundError noClassDefFoundError) {
noClassDefFoundError.printStackTrace();
System.exit(1);
return null;
}
}
}
and
<bean id="exporter" class="org.springframework.remoting.rmi.RmiServiceExporter">
<!-- existing properties -->
<property name="interceptors">
<bean class="com.x.ExitInterceptor"/>
<property>
</bean>
What you can do is to extend [RmiServiceExporter][1]
and handle the exception in the invoke
method. This can be done as so
public class AutoFailRmiServiceExporter extends RmiProxyFactoryBean implements ApplicationContextAware {
private ApplicationContext ac;
@override
public Object invoke(RemoteInvocation invocation,
Object targetObject)
throws NoSuchMethodException,
IllegalAccessException,
InvocationTargetException {
try {
super.invoke(methodInvocation, target);
} catch (NoClassDefFoundError e) {
if {ac instanceof ConfigurableApplicationContext) {
(ConfigurableApplicationContext)ac).close();
else {
//log error
}
}
}
//application context setter
}
You would then use your AutoFail version of the RmiServiceExporterwhen defining your rmi service in your spring context.
EDIT: The original answer showed a way of killing the client when the exception is thrown. This is done by subclassing RmiProxyFactorty and overriding doInvoke instead of RmiServiceExporter.
精彩评论