Announcement Announcement Module
Collapse
No announcement yet.
FailoverProxyFactoryBean Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • FailoverProxyFactoryBean

    Hi,

    In our current project we need to provide a simple (stand alone POJO) service
    with high availability guarantees. The simplest way (for us) is to install it
    on multiple servers and build a failover mechanism into the clients.
    I was pleasantly surprised by how easy it is to achieve a transparent failover
    using Spring, and I thought that this could be useful for others too.

    Our first version below, is very basic: it always tries the first service
    provider in the list, and if an exception is thrown, the next one is tried,
    etc.
    Possible improvements are:
    - first try the provider that previously worked
    - use round robin for basic load balancing

    All comments are welcome,

    Ivo

    Code:
    <bean id="highAvailabilityBean"
    class="org.springframework.remoting.support.FailoverProxyFactoryBean">
              <property name="serviceInterface" value="com.x.MyInterface" />
              <property name="serviceProviders">
                      <list>
                      <!-- service beans are typically proxies to remote services  -->
                              <ref bean="primaryServiceProvider"/>
                              <ref bean="fallBackServiceProvider"/>
                      </list>
              </property>
    </bean>
    Code:
    package org.springframework.remoting.support;
    
    
    import java.lang.reflect.InvocationTargetException;
    import java.util.Iterator;
    import java.util.List;
    
    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;
    import org.springframework.aop.framework.ProxyFactory;
    import org.springframework.beans.factory.FactoryBean;
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.remoting.support.RemoteAccessor;
    
    /**
     * Factory bean for proxies to redundant services. Behaves like the proxied
     * service when used as bean reference, exposing the specified service
     * interface, but with transparent fail-over. All call to the proxy are
     * delegated to the first object in the list of service providers (@see
     * #setServiceProviders(List)). When this delegated call fails, the next
     * provider in the list will be called, etc.
     *
     * @author be324288
     *
     */
    public class FailoverProxyFactoryBean extends RemoteAccessor implements
    MethodInterceptor,
            InitializingBean, FactoryBean {
    
        private Object serviceProxy;
    
        private List serviceProviders;
    
        /**
         * The list of (redundant) objects that implement the interface specified
         * with {@link RemoteAccessor#setServiceInterface(java.lang.Class)}
         *
         * @return
         */
        public List getServiceProviders() {
            return serviceProviders;
        }
    
        /**
         * @param serviceProviders
         */
        public void setServiceProviders(List serviceProviders) {
            this.serviceProviders = serviceProviders;
        }
    
        public void afterPropertiesSet() throws Exception {
            if (getServiceInterface() == null) {
                throw new IllegalArgumentException("serviceInterface is required");
            }
            if (serviceProviders == null || serviceProviders.isEmpty()) {
                throw new IllegalArgumentException("serviceBeans is required");
            }
            for (Object o : serviceProviders) {
                if (!getServiceInterface().isInstance(o)) {
                    throw new IllegalArgumentException(o.getClass()
                            + " does not implement the serviceInterface: " +
    getServiceInterface());
                }
            }
            this.serviceProxy = ProxyFactory.getProxy(getServiceInterface(), this);
        }
    
        public Object getObject() {
            return this.serviceProxy;
        }
    
        public Class getObjectType() {
            return getServiceInterface();
        }
    
        public boolean isSingleton() {
            return true;
        }
    
        public Object invoke(MethodInvocation mi) throws Throwable {
            Iterator iter = serviceProviders.iterator();
            while (iter.hasNext()) {
                Object bean = iter.next();
                try {
                    return bean.getClass().getMethod(mi.getMethod().getName(),
                            (Class[])
    mi.getMethod().getParameterTypes()).invoke(bean,
                            mi.getArguments());
                } catch (InvocationTargetException e) {
                    // try next bean or throw exception if this is the last bean
                    if (!iter.hasNext()) {
                        throw e.getCause();
                    }
                }
            }
            return null;
        }
    
    }
Working...
X