001/* 002 * Copyright 2002-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.remoting.rmi; 018 019import org.springframework.aop.framework.ProxyFactory; 020import org.springframework.beans.factory.BeanClassLoaderAware; 021import org.springframework.beans.factory.FactoryBean; 022import org.springframework.util.Assert; 023 024/** 025 * {@link FactoryBean} for RMI proxies, supporting both conventional RMI services 026 * and RMI invokers. Exposes the proxied service for use as a bean reference, 027 * using the specified service interface. Proxies will throw Spring's unchecked 028 * RemoteAccessException on remote invocation failure instead of RMI's RemoteException. 029 * 030 * <p>The service URL must be a valid RMI URL like "rmi://localhost:1099/myservice". 031 * RMI invokers work at the RmiInvocationHandler level, using the same invoker stub 032 * for any service. Service interfaces do not have to extend {@code java.rmi.Remote} 033 * or throw {@code java.rmi.RemoteException}. Of course, in and out parameters 034 * have to be serializable. 035 * 036 * <p>With conventional RMI services, this proxy factory is typically used with the 037 * RMI service interface. Alternatively, this factory can also proxy a remote RMI 038 * service with a matching non-RMI business interface, i.e. an interface that mirrors 039 * the RMI service methods but does not declare RemoteExceptions. In the latter case, 040 * RemoteExceptions thrown by the RMI stub will automatically get converted to 041 * Spring's unchecked RemoteAccessException. 042 * 043 * <p>The major advantage of RMI, compared to Hessian, is serialization. 044 * Effectively, any serializable Java object can be transported without hassle. 045 * Hessian has its own (de-)serialization mechanisms, but is HTTP-based and thus 046 * much easier to setup than RMI. Alternatively, consider Spring's HTTP invoker 047 * to combine Java serialization with HTTP-based transport. 048 * 049 * @author Juergen Hoeller 050 * @since 13.05.2003 051 * @see #setServiceInterface 052 * @see #setServiceUrl 053 * @see RmiClientInterceptor 054 * @see RmiServiceExporter 055 * @see java.rmi.Remote 056 * @see java.rmi.RemoteException 057 * @see org.springframework.remoting.RemoteAccessException 058 * @see org.springframework.remoting.caucho.HessianProxyFactoryBean 059 * @see org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean 060 */ 061public class RmiProxyFactoryBean extends RmiClientInterceptor implements FactoryBean<Object>, BeanClassLoaderAware { 062 063 private Object serviceProxy; 064 065 066 @Override 067 public void afterPropertiesSet() { 068 super.afterPropertiesSet(); 069 Class<?> ifc = getServiceInterface(); 070 Assert.notNull(ifc, "Property 'serviceInterface' is required"); 071 this.serviceProxy = new ProxyFactory(ifc, this).getProxy(getBeanClassLoader()); 072 } 073 074 075 @Override 076 public Object getObject() { 077 return this.serviceProxy; 078 } 079 080 @Override 081 public Class<?> getObjectType() { 082 return getServiceInterface(); 083 } 084 085 @Override 086 public boolean isSingleton() { 087 return true; 088 } 089 090}