📄 jndirmiclientinterceptor.java
字号:
if (getServiceInterface() != null && Remote.class.isAssignableFrom(getServiceInterface())) {
stub = PortableRemoteObject.narrow(stub, getServiceInterface());
}
if (!(stub instanceof Remote)) {
throw new NamingException("Located RMI stub of class [" + stub.getClass().getName() +
"], with JNDI name [" + getJndiName() + "], does not implement interface [java.rmi.Remote]");
}
return (Remote) stub;
}
/**
* Return the RMI stub to use. Called for each invocation.
* <p>The default implementation returns the stub created on initialization,
* if any. Else, it invokes {@link #lookupStub} to get a new stub for
* each invocation. This can be overridden in subclasses, for example in
* order to cache a stub for a given amount of time before recreating it,
* or to test the stub whether it is still alive.
* @return the RMI stub to use for an invocation
* @throws NamingException if stub creation failed
*/
protected Remote getStub() throws NamingException {
if (!this.cacheStub || (this.lookupStubOnStartup && !this.refreshStubOnConnectFailure)) {
return (this.cachedStub != null ? this.cachedStub : lookupStub());
}
else {
synchronized (this) {
if (this.cachedStub == null) {
this.cachedStub = lookupStub();
}
return this.cachedStub;
}
}
}
/**
* Fetches an RMI stub and delegates to {@link #doInvoke}.
* If configured to refresh on connect failure, it will call
* {@link #refreshAndRetry} on corresponding RMI exceptions.
* @see #getStub
* @see #doInvoke
* @see #refreshAndRetry
* @see java.rmi.ConnectException
* @see java.rmi.ConnectIOException
* @see java.rmi.NoSuchObjectException
*/
public Object invoke(MethodInvocation invocation) throws Throwable {
Remote stub = null;
try {
stub = getStub();
}
catch (Throwable ex) {
throw new RemoteLookupFailureException("JNDI lookup for RMI service [" + getJndiName() + "] failed", ex);
}
try {
return doInvoke(invocation, stub);
}
catch (RemoteConnectFailureException ex) {
return handleRemoteConnectFailure(invocation, ex);
}
catch (RemoteException ex) {
if (isConnectFailure(ex)) {
return handleRemoteConnectFailure(invocation, ex);
}
else {
throw ex;
}
}
}
/**
* Determine whether the given RMI exception indicates a connect failure.
* <p>The default implementation delegates to
* {@link RmiClientInterceptorUtils#isConnectFailure}.
* @param ex the RMI exception to check
* @return whether the exception should be treated as connect failure
*/
protected boolean isConnectFailure(RemoteException ex) {
return RmiClientInterceptorUtils.isConnectFailure(ex);
}
/**
* Refresh the stub and retry the remote invocation if necessary.
* <p>If not configured to refresh on connect failure, this method
* simply rethrows the original exception.
* @param invocation the invocation that failed
* @param ex the exception raised on remote invocation
* @return the result value of the new invocation, if succeeded
* @throws Throwable an exception raised by the new invocation, if failed too.
*/
private Object handleRemoteConnectFailure(MethodInvocation invocation, Exception ex) throws Throwable {
if (this.refreshStubOnConnectFailure) {
if (logger.isDebugEnabled()) {
logger.debug("Could not connect to RMI service [" + getJndiName() + "] - retrying", ex);
}
else if (logger.isWarnEnabled()) {
logger.warn("Could not connect to RMI service [" + getJndiName() + "] - retrying");
}
return refreshAndRetry(invocation);
}
else {
throw ex;
}
}
/**
* Refresh the RMI stub and retry the given invocation.
* Called by invoke on connect failure.
* @param invocation the AOP method invocation
* @return the invocation result, if any
* @throws Throwable in case of invocation failure
* @see #invoke
*/
protected Object refreshAndRetry(MethodInvocation invocation) throws Throwable {
Remote freshStub = null;
synchronized (this) {
try {
freshStub = lookupStub();
if (this.cacheStub) {
this.cachedStub = freshStub;
}
}
catch (Throwable ex) {
throw new RemoteLookupFailureException("JNDI lookup for RMI service [" + getJndiName() + "] failed", ex);
}
}
return doInvoke(invocation, freshStub);
}
/**
* Perform the given invocation on the given RMI stub.
* @param invocation the AOP method invocation
* @param stub the RMI stub to invoke
* @return the invocation result, if any
* @throws Throwable in case of invocation failure
*/
protected Object doInvoke(MethodInvocation invocation, Remote stub) throws Throwable {
if (stub instanceof RmiInvocationHandler) {
// RMI invoker
try {
return doInvoke(invocation, (RmiInvocationHandler) stub);
}
catch (RemoteException ex) {
throw RmiClientInterceptorUtils.convertRmiAccessException(
invocation.getMethod(), ex, isConnectFailure(ex), getJndiName());
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
catch (Throwable ex) {
throw new RemoteProxyFailureException(
"Failed to invoke RMI stub for remote service [" + getJndiName() + "]", ex);
}
}
else {
// traditional RMI stub
try {
return RmiClientInterceptorUtils.doInvoke(invocation, stub);
}
catch (InvocationTargetException ex) {
Throwable targetEx = ex.getTargetException();
if (targetEx instanceof RemoteException) {
RemoteException rex = (RemoteException) targetEx;
throw RmiClientInterceptorUtils.convertRmiAccessException(
invocation.getMethod(), rex, isConnectFailure(rex), getJndiName());
}
else {
throw targetEx;
}
}
}
}
/**
* Apply the given AOP method invocation to the given {@link RmiInvocationHandler}.
* <p>The default implementation delegates to {@link #createRemoteInvocation}.
* @param methodInvocation the current AOP method invocation
* @param invocationHandler the RmiInvocationHandler to apply the invocation to
* @return the invocation result
* @throws RemoteException in case of communication errors
* @throws NoSuchMethodException if the method name could not be resolved
* @throws IllegalAccessException if the method could not be accessed
* @throws InvocationTargetException if the method invocation resulted in an exception
* @see org.springframework.remoting.support.RemoteInvocation
*/
protected Object doInvoke(MethodInvocation methodInvocation, RmiInvocationHandler invocationHandler)
throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
if (AopUtils.isToStringMethod(methodInvocation.getMethod())) {
return "RMI invoker proxy for service URL [" + getJndiName() + "]";
}
return invocationHandler.invoke(createRemoteInvocation(methodInvocation));
}
/**
* Create a new RemoteInvocation object for the given AOP method invocation.
* <p>The default implementation delegates to the configured
* {@link #setRemoteInvocationFactory RemoteInvocationFactory}.
* This can be overridden in subclasses in order to provide custom RemoteInvocation
* subclasses, containing additional invocation parameters (e.g. user credentials).
* <p>Note that it is preferable to build a custom RemoteInvocationFactory
* as a reusable strategy, instead of overriding this method.
* @param methodInvocation the current AOP method invocation
* @return the RemoteInvocation object
* @see RemoteInvocationFactory#createRemoteInvocation
*/
protected RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) {
return getRemoteInvocationFactory().createRemoteInvocation(methodInvocation);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -