2016-03-11 8 views
0

Я пишу услуги в Spring boot, которые получают свои конфигурации из облака Spring. Эти услуги являются многопользовательскими, а арендатор основан на имени хоста.Загрузка бобов на основе имени хоста

то, что я сейчас

public class MyController { 
    @Autowired 
    public MyController(MyServiceFactory factory) { 
     ... 
    } 

    @RequestMapping("some/path/{id}") 
    ResponseEntity<SomeEntity> getSomeEntity(@RequestHeader header, @PathVariable id) { 
     return factory.getMyService(header).handle(id); 
    } 
} 

где MyServiceFactory выглядит как ...

public class MyServiceFactory { 
    private final HashMap<String, MyService> serviceRegistry = new HashMap<>(); 
    public MyService getMyService(String key) { 
     return serviceRegistry.get(key); 
    } 

    MyServiceFactory withService(String key, MyService service) { 
     this.serviceRegistry.put(key, service); 
     return this; 
    } 

} 

затем в файле конфигурации

@Configuration 
public ServiceFactoryConfiguration { 

    @Bean 
    public MyServiceFactory getMyServiceFactory() { 
     return new MyServiceFactory() 
      .withService("client1", new MyService1()) 
      .withService("client2", new MyService2()); 
    } 
} 

Хотя то, что я в настоящее время работает, Мне не нравится, что мне нужно создать фабрику для каждой зависимости, которую может иметь мой контроллер. Я хотел бы, чтобы мой код выглядит примерно так ...

public class MyController { 
    @Autowired 
    public MyController(MyService service) { 
    ... 
    } 

    @RequestMapping("some/path/{id}") 
    ResponseEntity<SomeEntity> getSomeEntity(@PathVariable id) { 
     return service.handle(id); 
    } 
} 

с файлом конфигурации, как

@Configuration 
public class MyServiceConfiguration() { 

    @Bean 
    @Qualifier("Client1") 
    public MyService getMyService1() { 
     return new MyService1(); 
    } 

    @Bean 
    @Qualifier("Client2") 
    public MyService getMyService2() { 
     return new MyService2(); 
    } 
} 

я могу получить код, который я хочу написать, если я использую профиль в запуск приложения. Но я хочу иметь много разных записей DNS, указывающих на один и тот же (пул) экземпляров, и иметь экземпляр, способный обрабатывать запросы для разных клиентов. Я хочу иметь возможность обменивать профили на основе запроса.

Это можно сделать?

+0

Не ... Создание прокси для 'MyService' и на основе арендатора использовать правильный. Мы использовали этот подход для переключения источников данных «на лету». Я написал об этом [здесь] (https://mdeinum.wordpress.com/2007/01/05/one-application-per-client-database/), а код [здесь] (https://github.com/mdeinum/пружинно-Utils). (Я работаю над тем, чтобы вытащить его в собственный проект). Он обеспечивает возможность переключения любого компонента во время выполнения с тем, который вам нужен или нужен, или по умолчанию. –

+0

Почему бы не использовать весенние профили, по одному для каждого хоста, а затем передать имя хоста при запуске в качестве имени профиля. – cjstehno

ответ

1

Весенние профили здесь не помогли, для каждого клиента вам понадобится один контекст приложения, и это кажется не тем, что вы хотите.

Вместо этого вы можете использовать бобовые бобы. Создания клиентской зависимой фасоли с размахом «клиентом»:

@Bean 
@Scope(value="client",proxyMode = ScopedProxyMode.INTERFACES) 
@Primary 
MyService myService(){ 
    //does not really matter, which instance you create here 
    //the scope will create the real instance 
    //may be you can even return null, did not try that. 
    return new MyServiceDummy(); 
} 

Там будет по крайней мере 3 фасоли типа MyService: с контекстными один, и один для каждого клиента. Аннотация @Primary сообщает весне, что всегда используется бокс для инъекций.

Создание области:

public class ClientScope implements Scope { 
    @Autowired 
    BeanFactory beanFactory; 

    Object get(String name, ObjectFactory<?> objectFactory){ 
     //we do not use the objectFactory here, instead the beanFactory   
     //you somehow have to know which client is the current 
     //from the config, current request, session, or ThreadLocal.. 
     String client=findCurrentClient(..); 
     //client now is something like 'Client1' 

     //check if your cache (HashMap) contains an instance with 
     //BeanName = name for the client, if true, return that 
     .. 
     //if not, create a new instance of the bean with the given name 
     //for the current client. Easiest way using a naming convention 
     String clientBeanName=client+'.'+name; 
     Object clientBean=BeanFactory.getBean(clientBeanName); 
     //put in cache ... 
     return clientBean; 
    }; 
} 

и ваш клиент конкретные бобы настроены так:

@Bean('Client1.myService') 
public MyService getMyService1() { 
    return new MyService1(); 
} 

@Bean('Client2.myService') 
public MyService getMyService2() { 
    return new MyService2(); 
} 

не проверял, но использовали его в своих проектах. Должно сработать.

tutorial spring custom scope

Смежные вопросы