Revision history [back]

click to hide/show revision 1
initial version

answered 2017-02-28 12:40:54 +0800

chillworld gravatar image chillworld flag of Belgium

https://github.com/chillw...

We use Spring 4 and have this helper class :

import javax.persistence.Transient;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * service locator permits the decoupling of calling code from the
 * org.springframework.beans.factory.BeanFactory API
 * <p>
 * A sample config in an XML-based org.springframework.beans.factory.BeanFactory
 * look as follows :
 *
 * <pre class="code">
 * &lt;beans&gt;
 *
 * &lt;bean class=&quot;eu.mil.meat.config.ServiceLocator&quot;
 * factory-method=&quot;getInstance&quot;/&gt;
 *
 * lt;/beans&gt;
 * </pre>
 *
 * <p>
 * The attendant <code>MyClientBean</code> class implementation might then look
 * something like this:
 *
 * <pre class="code">
 * package a.b.c;
 *
 * public class MyClientBean {
 *
 * public void someBusinessMethod() {
 *
 * MyService service = ServiceLocator.getService(MyService.class); // use the
 * service object to effect the business logic... }
 * </pre>
 *
 * @author wim
 *
 */
public class ServiceLocator implements ApplicationContextAware,
        InitializingBean {

    /**
     * The instance.
     */
    private static ServiceLocator instance = new ServiceLocator();

    /**
     * Sets the instance.
     *
     * @param instance the new instance
     */
    public static void setInstance(ServiceLocator instance) {
        ServiceLocator.instance = instance;
    }
    /**
     * The Constant SERVICE_LOCATOR_WAS_NOT_PROPERLY_INITIALIZED.
     */
    private static final String SERVICE_LOCATOR_WAS_NOT_PROPERLY_INITIALIZED = "ServiceLocator was not properly initialized, initialize SpringContext";
    @Transient
    private boolean test = false;

    /**
     * Gets the bean.
     *
     * @param <T> the generic type
     * @param class1 the class1
     * @param name the name
     * @return the bean
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(final Class<T> class1, final String name) {
        return (T) getInstance().getBeanWithName(name);
    }

    /**
     * Gets the context.
     *
     * @return the context
     */
    public static ApplicationContext getContext() {
        return getInstance().getApplicationContext();
    }

    /**
     * Gets the single instance of ServiceLocator.
     *
     * @return single instance of ServiceLocator
     */
    protected static ServiceLocator getInstance() {
        return instance;
    }

    /**
     * Return a single bean of the given type or subtypes.
     *
     * @param <T> the generic type
     * @param serviceInterface type of bean to match
     * @return the matching bean instance
     */
    public static <T> T getService(final Class<T> serviceInterface) {
        LoggerFactory.getLogger(ServiceLocator.class).debug("getting Service :" + serviceInterface.getName());
        return getInstance().locateService(serviceInterface);
    }
    /**
     * The context.
     */
    private ApplicationContext context;
    /**
     * The logger.
     */
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /* (non-Javadoc)
     * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        this.logger.debug("{}", "initialized");
    }

    /**
     * Gets the application context.
     *
     * @return the application context
     */
    private ApplicationContext getApplicationContext() {
        return this.context;
    }

    /**
     * Gets the bean with name.
     *
     * @param name the name
     * @return the bean with name
     */
    private Object getBeanWithName(final String name) {
        return this.getApplicationContext().getBean(name);
    }

    /**
     * Locate2.
     *
     * @param <T> the generic type
     * @param serviceInterface the service interface
     * @return the t
     */
    @SuppressWarnings({"cast"})
    <T> T locate2(final Class<T> serviceInterface) {
        if (test) {
            return null;
        }
        if (this.getApplicationContext() == null) {
            throw new IllegalStateException(
                    SERVICE_LOCATOR_WAS_NOT_PROPERLY_INITIALIZED);
        }
        return (T) BeanFactoryUtils.beanOfTypeIncludingAncestors(this.getApplicationContext(), serviceInterface);
    }

    /**
     * Locate by class name.
     *
     * @param <T> the generic type
     * @param serviceInterface the service interface
     * @return the t exception
     */
    @SuppressWarnings("unchecked")
    public <T> T locateByClassName(final Class<T> serviceInterface) {
        T result = null;
        if (this.getApplicationContext() == null) {
            throw new IllegalStateException(
                    SERVICE_LOCATOR_WAS_NOT_PROPERLY_INITIALIZED);
        }
        this.logger.debug("locate : {}", serviceInterface);
        final String[] matchingBeanNames = BeanFactoryUtils
                .beanNamesForTypeIncludingAncestors(
                        this.getApplicationContext(), serviceInterface);
        for (final String beanName : matchingBeanNames) {
            final Object bean = this.getApplicationContext().getBean(beanName);
            if (bean != null && bean.getClass().equals(serviceInterface)) {
                result = (T) bean;
            }
        }
        if (result == null) {
            throw new NoSuchBeanDefinitionException(serviceInterface.getClass()
                    .getName());
        }
        return result;
    }

    /**
     * Return a single bean of the given type or subtypes.
     *
     * @param <T> the generic type
     * @param serviceInterface type of bean to match
     * @return the matching bean instance
     */
    @SuppressWarnings("cast")
    public <T> T locateService(final Class<T> serviceInterface) {
        T result = null;
        if (this.getApplicationContext() == null) {
            throw new IllegalStateException(
                    SERVICE_LOCATOR_WAS_NOT_PROPERLY_INITIALIZED);
        }
        this.logger.debug("locate : {}", serviceInterface);
        try {
            result = (T) BeanFactoryUtils.beanOfType(
                    this.getApplicationContext(), serviceInterface);
        } catch (final NoSuchBeanDefinitionException e) {
            return this.locate2(serviceInterface);
        }
        return result;
    }

    /* (non-Javadoc)
     * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
     */
    @Override
    public void setApplicationContext(final ApplicationContext applicationContext) {
        this.context = applicationContext;
    }

    /**
     * package private for testing purpose
     * @param test 
     */
    void setTest(boolean test) {
        this.test = test;
    }


}

And in our context :

<bean lazy-init="false" factory-method="getInstance" class="be.mil.service.util.ServiceLocator" id="serviceLocator"/>

We use Spring 4 and have this helper class :

import javax.persistence.Transient;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * service locator permits the decoupling of calling code from the
 * org.springframework.beans.factory.BeanFactory API
 * <p>
 * A sample config in an XML-based org.springframework.beans.factory.BeanFactory
 * look as follows :
 *
 * <pre class="code">
 * &lt;beans&gt;
 *
 * &lt;bean class=&quot;eu.mil.meat.config.ServiceLocator&quot;
 * factory-method=&quot;getInstance&quot;/&gt;
 *
 * lt;/beans&gt;
 * </pre>
 *
 * <p>
 * The attendant <code>MyClientBean</code> class implementation might then look
 * something like this:
 *
 * <pre class="code">
 * package a.b.c;
 *
 * public class MyClientBean {
 *
 * public void someBusinessMethod() {
 *
 * MyService service = ServiceLocator.getService(MyService.class); // use the
 * service object to effect the business logic... }
 * </pre>
 *
 * @author wim
 *
 */
public class ServiceLocator implements ApplicationContextAware,
        InitializingBean {

    /**
     * The instance.
     */
    private static ServiceLocator instance = new ServiceLocator();

    /**
     * Sets the instance.
     *
     * @param instance the new instance
     */
    public static void setInstance(ServiceLocator instance) {
        ServiceLocator.instance = instance;
    }
    /**
     * The Constant SERVICE_LOCATOR_WAS_NOT_PROPERLY_INITIALIZED.
     */
    private static final String SERVICE_LOCATOR_WAS_NOT_PROPERLY_INITIALIZED = "ServiceLocator was not properly initialized, initialize SpringContext";
    @Transient
    private boolean test = false;

    /**
     * Gets the bean.
     *
     * @param <T> the generic type
     * @param class1 the class1
     * @param name the name
     * @return the bean
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(final Class<T> class1, final String name) {
        return (T) getInstance().getBeanWithName(name);
    }

    /**
     * Gets the context.
     *
     * @return the context
     */
    public static ApplicationContext getContext() {
        return getInstance().getApplicationContext();
    }

    /**
     * Gets the single instance of ServiceLocator.
     *
     * @return single instance of ServiceLocator
     */
    protected static ServiceLocator getInstance() {
        return instance;
    }

    /**
     * Return a single bean of the given type or subtypes.
     *
     * @param <T> the generic type
     * @param serviceInterface type of bean to match
     * @return the matching bean instance
     */
    public static <T> T getService(final Class<T> serviceInterface) {
        LoggerFactory.getLogger(ServiceLocator.class).debug("getting Service :" + serviceInterface.getName());
        return getInstance().locateService(serviceInterface);
    }
    /**
     * The context.
     */
    private ApplicationContext context;
    /**
     * The logger.
     */
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /* (non-Javadoc)
     * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        this.logger.debug("{}", "initialized");
    }

    /**
     * Gets the application context.
     *
     * @return the application context
     */
    private ApplicationContext getApplicationContext() {
        return this.context;
    }

    /**
     * Gets the bean with name.
     *
     * @param name the name
     * @return the bean with name
     */
    private Object getBeanWithName(final String name) {
        return this.getApplicationContext().getBean(name);
    }

    /**
     * Locate2.
     *
     * @param <T> the generic type
     * @param serviceInterface the service interface
     * @return the t
     */
    @SuppressWarnings({"cast"})
    <T> T locate2(final Class<T> serviceInterface) {
        if (test) {
            return null;
        }
        if (this.getApplicationContext() == null) {
            throw new IllegalStateException(
                    SERVICE_LOCATOR_WAS_NOT_PROPERLY_INITIALIZED);
        }
        return (T) BeanFactoryUtils.beanOfTypeIncludingAncestors(this.getApplicationContext(), serviceInterface);
    }

    /**
     * Locate by class name.
     *
     * @param <T> the generic type
     * @param serviceInterface the service interface
     * @return the t exception
     */
    @SuppressWarnings("unchecked")
    public <T> T locateByClassName(final Class<T> serviceInterface) {
        T result = null;
        if (this.getApplicationContext() == null) {
            throw new IllegalStateException(
                    SERVICE_LOCATOR_WAS_NOT_PROPERLY_INITIALIZED);
        }
        this.logger.debug("locate : {}", serviceInterface);
        final String[] matchingBeanNames = BeanFactoryUtils
                .beanNamesForTypeIncludingAncestors(
                        this.getApplicationContext(), serviceInterface);
        for (final String beanName : matchingBeanNames) {
            final Object bean = this.getApplicationContext().getBean(beanName);
            if (bean != null && bean.getClass().equals(serviceInterface)) {
                result = (T) bean;
            }
        }
        if (result == null) {
            throw new NoSuchBeanDefinitionException(serviceInterface.getClass()
                    .getName());
        }
        return result;
    }

    /**
     * Return a single bean of the given type or subtypes.
     *
     * @param <T> the generic type
     * @param serviceInterface type of bean to match
     * @return the matching bean instance
     */
    @SuppressWarnings("cast")
    public <T> T locateService(final Class<T> serviceInterface) {
        T result = null;
        if (this.getApplicationContext() == null) {
            throw new IllegalStateException(
                    SERVICE_LOCATOR_WAS_NOT_PROPERLY_INITIALIZED);
        }
        this.logger.debug("locate : {}", serviceInterface);
        try {
            result = (T) BeanFactoryUtils.beanOfType(
                    this.getApplicationContext(), serviceInterface);
        } catch (final NoSuchBeanDefinitionException e) {
            return this.locate2(serviceInterface);
        }
        return result;
    }

    /* (non-Javadoc)
     * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
     */
    @Override
    public void setApplicationContext(final ApplicationContext applicationContext) {
        this.context = applicationContext;
    }

    /**
     * package private for testing purpose
     * @param test 
     */
    void setTest(boolean test) {
        this.test = test;
    }


}

And in our context :

<bean lazy-init="false" factory-method="getInstance" class="be.mil.service.util.ServiceLocator" class="be.chillworld.service.util.ServiceLocator" id="serviceLocator"/>
Support Options
  • Email Support
  • Training
  • Consulting
  • Outsourcing
Learn More