package org.springframework.cloud.config; import java.util.List; import java.util.logging.Logger; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.cloud.Cloud; import org.springframework.cloud.CloudFactory; import org.springframework.cloud.app.ApplicationInstanceInfo; import org.springframework.cloud.config.java.ServiceScan; import org.springframework.cloud.service.GenericCloudServiceConnectorFactory; import org.springframework.cloud.service.ServiceInfo; /** * <p> * Each service populated by this bean has the same name as the service it is bound to. * </p> * * Usage: * Most applications should use either the Java config using {@link ServiceScan} annotation * or XML config using <cloud:service-scan/> that introduce a bean of this type logically * equivalent to: * <pre> * <bean class="org.cloudfoundry.runtime.service.CloudServicesScanner"/> * </pre> * to have an easy access to all the services. * * If there is unique bean of a type, you can inject beans using the following * code (shows Redis, but the same scheme works for all services): * <pre> * @Autowired RedisConnectionFactory redisConnectionFactory; * </pre> * * If there are more than one services of a type, you can use the @Qualifier * as in the following code: * <pre> * @Autowired @Qualifier("service-name1") RedisConnectionFactory redisConnectionFactory; * @Autowired @Qualifier("service-name2") RedisConnectionFactory redisConnectionFactory; * </pre> * @author Ramnivas Laddad * */ public class CloudScanHelper { private static final String CLOUD_FACTORY_BEAN_NAME = "__cloud_factory__"; private static Logger logger = Logger.getLogger(CloudScanHelper.class.getName()); private Cloud cloud; public void registerServiceBeans(BeanDefinitionRegistry registry) { initializeCloud(registry); List<ServiceInfo> serviceInfos = cloud.getServiceInfos(); for(ServiceInfo serviceInfo: serviceInfos) { registerServiceBean(registry, serviceInfo); } } public void registerApplicationInstanceBean(BeanDefinitionRegistry registry) { initializeCloud(registry); BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(ApplicationInstanceInfoWrapper.class); definitionBuilder.addConstructorArgValue(cloud); definitionBuilder.getRawBeanDefinition().setAttribute( "factoryBeanObjectType", ApplicationInstanceInfo.class); registry.registerBeanDefinition("spring.cloud.appplicationInstanceInfo", definitionBuilder.getBeanDefinition()); } private void initializeCloud(BeanDefinitionRegistry registry) { if (cloud != null) { return; } ConfigurableListableBeanFactory beanFactory = (ConfigurableListableBeanFactory) registry; if(beanFactory.getBeansOfType(CloudFactory.class).isEmpty()) { beanFactory.registerSingleton(CLOUD_FACTORY_BEAN_NAME, new CloudFactory()); } CloudFactory cloudFactory = beanFactory.getBeansOfType(CloudFactory.class).values().iterator().next(); cloud = cloudFactory.getCloud(); } private void registerServiceBean(BeanDefinitionRegistry registry, ServiceInfo serviceInfo) { try { GenericCloudServiceConnectorFactory serviceFactory = new GenericCloudServiceConnectorFactory(serviceInfo.getId(), null); serviceFactory.setBeanFactory((BeanFactory) registry); serviceFactory.afterPropertiesSet(); BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(ScannedServiceWrapper.class); definitionBuilder.addConstructorArgValue(serviceFactory); definitionBuilder.getRawBeanDefinition().setAttribute( "factoryBeanObjectType", serviceFactory.getObjectType()); registry.registerBeanDefinition(serviceInfo.getId(), definitionBuilder.getBeanDefinition()); } catch (Exception ex) { logger.warning("Unable to create service for " + serviceInfo.getId() + " during service scanning. Skipping."); } } public static class ScannedServiceWrapper implements FactoryBean<Object> { private GenericCloudServiceConnectorFactory cloudServiceConnectorFactory; public ScannedServiceWrapper(GenericCloudServiceConnectorFactory cloudServiceConnectorFactory) { this.cloudServiceConnectorFactory = cloudServiceConnectorFactory; } @Override public Object getObject() throws Exception { return cloudServiceConnectorFactory.getObject(); } @Override public Class<?> getObjectType() { return cloudServiceConnectorFactory.getObjectType(); } @Override public boolean isSingleton() { return true; } } public static class ApplicationInstanceInfoWrapper implements FactoryBean<ApplicationInstanceInfo> { private Cloud cloud; public ApplicationInstanceInfoWrapper(Cloud cloud) { this.cloud = cloud; } @Override public ApplicationInstanceInfo getObject() throws Exception { return cloud.getApplicationInstanceInfo(); } @Override public Class<?> getObjectType() { return ApplicationInstanceInfo.class; } @Override public boolean isSingleton() { return true; } } }