I have a bean with singleton scope as below:
public class MyImpl implements MyInterface {
private HashMap<String, String> config = new HashMap<>();
private void load(String check) {
if ("abc".equalsIgnoreCase(check)) {
config.put("key", "val");
}
else {
config.put("key", "val_else");
}
}
#Override
public HashMap<String, String> getConfig(String check) {
load(check);
return config;
}
}
Then in other class, I inject MyImpl and try to use config as below:
#Service
public class Service {
#Inject
MyInterface impl;
public doJob(String check){
HashMap<String, String> config = impl.getConfig(check);
String myValue= config.get("key");
//some other code
}
}
If I have 100s of request/sec, and if value of check is abc for some request and and something else for other requests, would I still having different value in myValue? I tried to generalized the code as I can not share the exact code here. My question here is can we modify the property of singleton bean per request?
Create a ThreadLocal storage (see the example) to avoid the problem.
Alternatively you can change the bean scope to be REQUEST
Related
i did a singleton class named AcessoCliente
public class AcessoCliente {
private HashMap<String, Cliente> clientes;
private new HashMap<String, Date> clientesNaoEncontrados;
private static AcessoCliente instance;
static {
instance = new AcessoCliente();
}
public static AcessoCliente get() {
return instance;
}
private AcessoCliente() {
clientes = new HashMap<String, Cliente>();
clientesNaoEncontrados = new HashMap<String, Date>();
}
/*business*/
}
But i need to do a dependency injection of a class named ValidadorNivelDeAcessoBusiness on my singleton class
#Component
public class ValidadorNivelDeAcessoBusiness {
#Autowired
QuerysNiveisDeAcesso querysNiveisDeAcesso;
/*business*/
}
I'm trying do this dependency injection but isn't working, This is what I did:
public class AcessoCliente {
#Autowired
ValidadorNivelDeAcessoBusiness validadorNivelDeAcessoBusiness;
private HashMap<String, Cliente> clientes;
private new HashMap<String, Date> clientesNaoEncontrados;
private static AcessoCliente instance;
static {
ApplicationContext context = new AnnotationConfigApplicationContext(AcessoCliente.class);
instance = context.getBean(AcessoCliente.class);
}
public static AcessoCliente get() {
return instance;
}
private AcessoCliente() {
clientes = new HashMap<String, Cliente>();
clientesNaoEncontrados = new HashMap<String, Date>();
}
/*business*/
}
but the dependency injection isn't working and I get this error:
Error creating bean with name 'acessoCliente': Unsatisfied dependency expressed through field 'validadorNivelDeAcessoBusiness'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'my.project.business.interceptorBusiness.ValidadorNivelDeAcessoBusiness' available: expected at least 1 bean which qualifies as autowire candidate.
Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
Edit1. That's the QuerysNiveisDeAcesso class
#Component
public class QuerysNiveisDeAcesso extends QuerysClientes {
public QueryIntegratorBuilder queryBuscaNiveisDeAcesso(String[] condicoesQuery) throws Exception {
return super.executaQuery("BUSCA_NIVEIS_DE_ACESSO", condicoesQuery);
}
public QueryIntegratorBuilder queryBuscaNiveisDeAcesso() throws Exception {
return super.executaQuery("BUSCA_NIVEIS_DE_ACESSO");
}
public QueryIntegratorBuilder queryBuscaNiveisDeAcesso(String sqlWhere, String[] condicoesQuery) throws Exception {
return super.executaQuery("BUSCA_NIVEIS_DE_ACESSO", condicoesQuery, sqlWhere);
}
}
You are trying to mix Java Singleton and Spring singleton.
To make it compatible with plain java and spring both, you should make static factory method with your injected service in parameter and make a singleton's bean in #Configuration file.
public class AcessoCliente {
ValidadorNivelDeAcessoBusiness validadorNivelDeAcessoBusiness;
private HashMap<String, Cliente> clients;
private HashMap<String, Date> clientesNaoEncontrados;
private static AcessoCliente instance;
public static AcessoCliente getInstance(ValidadorNivelDeAcessoBusiness validadorNivelDeAcessoBusiness) {
if(instance == null) {
instance = new AcessoCliente(validadorNivelDeAcessoBusiness);
}
return instance;
}
private AcessoCliente(ValidadorNivelDeAcessoBusiness validadorNivelDeAcessoBusiness) {
clientes = new HashMap<String, Cliente>();
clientesNaoEncontrados = new HashMap<String, Date>();
this.validadorNivelDeAcessoBusiness = validadorNivelDeAcessoBusiness;
}
}
#Configuration
public class AcessoClienteConfiguration
{
#Bean
#Scope("singleton")
public AcessoCliente acessoCliente(ValidadorNivelDeAcessoBusiness validadorNivelDeAcessoBusiness)
{
return AcessoCliente.getInstance(validadorNivelDeAcessoBusiness);
}
}
I've tried to recreate the same issue you are having, it would seem that your dependencies in ValidadorNivelDeAcessoBusiness class is trying to load, however one of the fields in this class might be missing an #Component annotation, for the Spring application context to load.
#Component public class AcessoCliente {
#Autowired
ValidadorNivelDeAcessoBusiness validadorNivelDeAcessoBusiness;
}
#Component
public class ValidadorNivelDeAcessoBusiness {
#Autowired
QuerysNiveisDeAcesso querysNiveisDeAcesso;
}
public class QuerysNiveisDeAcesso {
// some code
}
Would produce the above error: 'acessoCliente': Unsatisfied dependency expressed through field 'validadorNivelDeAcessoBusiness'
Ensuring that all the fields in ValidadorNivelDeAcessoBusiness have an #Component got the spring application context to work i.e.:
#Component
public class QuerysNiveisDeAcesso {
// some code
}
You've completely misused the purpose of spring.
First off, there is no point in creating an application context inside the AcessoCliente class.
Application context is a "global" spring's registry objects that usually exists once in a whole application.
If you're using Plain Spring - you can create the application context right in the public static void main method. And then get the beans from there.
Next, when you create the application context, you should pass to it the configuration objects and not a single class. You can also work with component scanning, there are many techniques. But all-in-all it should accept the "rules" to configure - read find and load the beans.
Now lets return to the AccessCliente class. You've defined it as a singleton with static methods and private constructor, that's ok. But It doesn't work with spring - in fact if you're using spring, you can make this class a Singleton in a sense that there will be a single bean in the whole application context.
This is much more manageable and clear (+ no boilerplate code).
In fact all beans by default are singletons in spring universe.
The next thing to mentions is when you make is a singleton bean (a class whose instance is managed by spring) then the whole autowiring magic will start working automatically.
What you've done is a strange hybrid that won't work anyway (how spring can create a bean if its not instructed to do so, and even if it was, the constructor is private).
So, to recap, you need something like this:
public class Main {
public static void main(String [] args) {
ApplicationContext ctx = ...;
ctx.getBean(SomeClassThatStartsTheFlow.class).doSomething();
}
}
#Service
public class AcessoCliente {
#Autowired
ValidadorNivelDeAcessoBusiness validadorNivelDeAcessoBusiness;
private HashMap<String, Cliente> clientes;
private new HashMap<String, Date> clientesNaoEncontrados;
public AcessoCliente() {
clientes = new HashMap<String, Cliente>();
clientesNaoEncontrados = new HashMap<String, Date>();
}
/*business*/
}
I am writing a service that gets an input based on which I need to call certain impl of one service. This input is a list of names of impls needs to called.
public interface Processor {
Map<String, String> execute();
}
#Service("BUCKET_PROCESSOR")
public class BucketProcessor implements Processor {
..... //first impl
}
#Service("QUERY_PROCESSOR")
public class QueryProcessor implements Processor {
..... //second impl
}
#Service("SQL_PROCESSOR")
public class SQLProcessor implements Processor {
..... //third impl
}
then I have a service where I want to inject a map of all these impls so that I can iterate over input and call respective impl.
#Service
public class MyAysncClient {
#Autowired
private Map<String, Processor> processorMap;
public void execute(List<String> processors) {
List<Future> tasks = new ArrayList<>();
for (String p : processors) {
final Processor processor = this.processorMap.get(p);
processor.execute()
....
}
}
}
you can just use getBeansOfType(Processor.class):
Returns a Map with the matching beans, containing the bean names as keys and the corresponding bean instances as values
#Bean
public Map<String, Processor> processorMap(ApplicationContext context) {
return context.getBeansOfType(Processor.class);
}
Yes, you can - spring has this feature enabled by default. Namely, you can define inject a Map<String, Processor> into the spring bean.
This will instruct spring to find all beans which are implementations of Processor interface and these will be values of the map, the corresponding keys will be bean names.
So the code presented in the question should work.
Check the documentation of well-known #Autowired annotation.
In the section "Autowiring Arrays, Collections, and Maps" it states the following:
In case of an array, Collection, or Map dependency type, the container autowires all beans matching the declared value type. For such purposes, the map keys must be declared as type String which will be resolved to the corresponding bean names. Such a container-provided collection will be ordered, taking into account Ordered and #Order values of the target components, otherwise following their registration order in the container. Alternatively, a single matching target bean may also be a generally typed Collection or Map itself, getting injected as such.
See This example - the relevant part of it is where the map is injected into the test.
A better and elegant way to do the same is
Define a Service locator pattern using below code
#Configuration
public class ProcessorConfig {
#Bean("processorFactory")
public FactoryBean<?> serviceLocatorFactoryBean() {
ServiceLocatorFactoryBean factoryBean = new ServiceLocatorFactoryBean();
factoryBean.setServiceLocatorInterface(ProcessorFactory.class);
return factoryBean;
}
}
public interface ProcessorFactory {
Processor getProcessor(ProcessorTypes processorTypes);
}
then
public interface Processor {
Map<String, String> execute();
}
#Component(ProcessorTypes.ProcessorConstants.BUCKET_PROCESSOR)
#Slf4j
public class BucketProcessor implements Processor {
#Override
public Map<String, String> execute() {
return Collections.singletonMap("processor","BUCKET_PROCESSOR");
}
}
#Component(ProcessorTypes.ProcessorConstants.QUERY_PROCESSOR)
#Slf4j
public class QueryProcessor implements Processor {
#Override
public Map<String, String> execute() {
return Collections.singletonMap("processor","QUERY_PROCESSOR");
}
}
#Component(ProcessorTypes.ProcessorConstants.SQL_PROCESSOR)
#Slf4j
public class SqlProcessor implements Processor {
#Override
public Map<String, String> execute() {
return Collections.singletonMap("processor","SQL_PROCESSOR");
}
}
Now define your service injecting the factory
#Service
#RequiredArgsConstructor
#Slf4j
public class ProcessorService {
private final ProcessorFactory processorFactory;
public void parseIndividual(ProcessorTypes processorTypes) {
processorFactory
.getProcessor(processorTypes)
.execute();
}
public void parseAll(List<ProcessorTypes> processorTypes) {
processorTypes.forEach(this::parseIndividual);
}
}
In client, you can execute in below way
processorService.parseAll(Arrays.asList(ProcessorTypes.SQL, ProcessorTypes.BUCKET, ProcessorTypes.QUERY));
processorService.parseIndividual(ProcessorTypes.BUCKET);
If you want to expose as REST API you can do it in below way
#RestController
#RequestMapping("/processors")
#RequiredArgsConstructor
#Validated
public class ProcessorController {
private final ProcessorService processorService;
#GetMapping("/process")
public ResponseEntity<?> parseContent(#RequestParam("processorType") #Valid ProcessorTypes processorTypes) {
processorService.parseIndividual(ProcessorTypes.BUCKET);
return ResponseEntity.status(HttpStatus.OK).body("ok");
}
#GetMapping("/process-all")
public ResponseEntity<?> parseContent() {
processorService.parseAll(Arrays.asList(ProcessorTypes.SQL, ProcessorTypes.BUCKET, ProcessorTypes.QUERY));
return ResponseEntity.status(HttpStatus.OK).body("ok");
}
}
Hope your problem gets resolved by the solution
I think this will help you , add bean configuration into configuration file
#Bean(name = "mapBean")
public Map<String, Processor > mapBean() {
Map<String, Processor > map = new HashMap<>();
//populate the map here
return map;
}
in your service
#Service
public class MyAysncClient {
#Autowired
#Qualifier("mapBean")
private Map<String, Processor> processorMap;
public void execute(List<String> processors) {
List<Future> tasks = new ArrayList<>();
for (String p : processors) {
final Processor processor = this.processorMap.get(p);
processor.execute()
....
}
}
}
by the way if you dont need name of the beans (according your example) so define a list , spring will inject all bean defined as service on the same interface
#Autowired
private List<Processor> processors; // include all defined beans
after that iterate each of them and call execute method.
Yes, you can, but it needs some improvements to your current code in order to make it work in this way.
First of all you have to add the getProcessorName method to the Processor interface:
public interface Processor {
Map<String, String> execute();
String getProcessorName();
}
When you implement it, you should set it's name in returning of getProcessorName method
#Service
public class QueryProcessor implements Processor {
//...
#Override
public String getProcessorName() {
return "QUERY_PROCESSOR";
}
}
Then you must create a spring configuration or add bean creation to the existing one
#Configuration
public class MyShinyProcessorsConfiguration {
#Bean
#Qualifier("processorsMap")
public Map<String, Processor> processorsMap(List<Processor> processors) {
Map<String, Processor > procMap = new HashMap<>();
processors.forEach(processor -> procMap.put(processor.getProcessorName(), processor);
return procMap;
}
}
...and then you can simply add your processors map to any component
#Service
public class MyAysncClient {
#Autowired
#Qualifier("processorsMap")
private Map<String, Processor> processorsMap;
}
With reference with below links, i want my spring boot app to replace bean at runtime in applicationcontext.
Add Bean
Remove Bean
Below is my try,
MainClass.java
#SpringBootApplication
public class MainClass {
public static void main(String[] args) {
SpringApplication.run(
MainClass.class, args);
new Thread(new MyThread()).run();
}
}
ApplicationContextProvider.java
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
public static ApplicationContext getApplicationContext(){
return context;
}
#Override
public void setApplicationContext(ApplicationContext arg0) throws BeansException {
context = arg0;
}
public Object getBean(String name){
return context.getBean(name, Object.class);
}
public void addBean(String beanName, Object beanObject){
ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext)context).getBeanFactory();
beanFactory.registerSingleton(beanName, beanObject);
}
public void removeBean(String beanName){
BeanDefinitionRegistry reg = (BeanDefinitionRegistry) context.getAutowireCapableBeanFactory();
reg.removeBeanDefinition(beanName);
}
}
Config.java
#Configuration
#ComponentScan(value="com.en.*")
public class Config {
#Bean
#Qualifier("myMap")
public MapBean myMap(){
MapBean bean = new MapBean();
Map<String, String> mp = new HashMap<>();
mp.put("a", "a");
bean.setMp(mp);
return bean;
}
#Bean
ApplicationContextProvider applicationContextProvider(){
return new ApplicationContextProvider();
}
}
MapBean.java
import java.util.Map;
public class MapBean {
private Map<String, String> mp;
public Map<String, String> getMp() {
return mp;
}
public void setMp(Map<String, String> mp) {
this.mp = mp;
}
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("MapBean [mp=");
builder.append(mp);
builder.append("]");
return builder.toString();
}
}
MyThread.java
import java.util.HashMap;
import java.util.Map;
import com.en.model.MapBean;
public class MyThread implements Runnable{
static ApplicationContextProvider appCtxPrvdr = new ApplicationContextProvider();
public void run(){
try {
Thread.sleep(5000);
if(ApplicationContextProvider.getApplicationContext().containsBean("myMap")){
System.out.println("AppCtx has myMap");
MapBean newM = (MapBean) ApplicationContextProvider.getApplicationContext().getBean("myMap", MapBean.class);
System.out.println(newM);
appCtxPrvdr.removeBean("myMap");
System.out.println("Removed myMap from AppCtx");
}
MapBean bean1 = new MapBean();
Map<String, String> mp = new HashMap<>();
mp.put("b", "b");
bean1.setMp(mp);
appCtxPrvdr.addBean("myMap", bean1);
System.out.println("myMap added to AppCtx");
if(ApplicationContextProvider.getApplicationContext().containsBean("myMap")){
System.out.println("AppCtx has myMap");
MapBean newM = (MapBean) ApplicationContextProvider.getApplicationContext().getBean("myMap", MapBean.class);
System.out.println(newM);
appCtxPrvdr.removeBean("myMap");
System.out.println("Removed myMap from AppCtx");
}
MapBean bean2 = new MapBean();
Map<String, String> map2 = new HashMap<>();
map2.put("c", "c");
bean2.setMp(map2);
appCtxPrvdr.addBean("myMap", bean2);
System.out.println("myMap added to AppCtx");
MapBean newM = (MapBean) ApplicationContextProvider.getApplicationContext().getBean("myMap", MapBean.class);
System.out.println(newM);
} catch (Exception e) {
e.printStackTrace();
}
}
}
The output i am getting is as below,
AppCtx has myMap
MapBean [mp={a=a}]
Removed myMap from AppCtx
myMap added to AppCtx
AppCtx has myMap
MapBean [mp={b=b}]
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'myMap' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.removeBeanDefinition(DefaultListableBeanFactory.java:881)
at com.en.config.ApplicationContextProvider.removeBean(ApplicationContextProvider.java:47)
at com.en.config.MyThread.run(MyThread.java:36)
at java.lang.Thread.run(Unknown Source)
at com.en.MainClass.main(MainClass.java:77)
So as per my understanding below things are happening.
In Config class, it is adding myMap to appctx.
In Mythread class, it is able to find myMap in appctx.
It is able to print and then remove from appctx.
It is able to add new myMap to appctx.
When above step is done. It is not able to remove it again.
Please advice on how to add and remove it multiple time.
BeanDefinitions and beans are totally different things in spring. When BeanDefinition is removed, the bean still exists in ApplicationContext.
Hence I can't really understand the implementation of ApplicationContextProvider in your example.
Now the thing you're asking for is very unusual, it could be great if you could provide more information on why do you need such a logic in runtime.
I personally don't think you should remove the beans when the application starts.
It's possible or at least kind of "conventional" to do the following:
Conditionally load the bean when the application context Starts with the help of #Conditional annotation (there are many of those) / #Profile annotation
Alter the bean during the runtime to give it additional functionality, for this use BeanPostProcessor
Alter Bean definition by means of defining BeanFactoryPostProcessor (used in extremely rare cases)
Now, if you're aware of all these mechanisms and none of them suits your needs, try the following:
Define an internal state in the singleton bean and check the state every time the bean's method is called.
This can be implemented right inside the bean, with wrapper / decorator or in any other way, but the logic is the same.
Example:
public class MySingleton {
private boolean shouldWork = true;
public void stop() {
shouldWork = false;
}
public void start() {
shouldWork = true;
}
public void doSomething() {
if(shouldWork) {
// do real logic
}
else {
// do nothing, or some minimal thing to not break anything
}
}
}
Well your logic is pretty wired and if you are really trying to do something like refresh the bean with different configurations at runtime or sort of a thing,
Please consider looking at externalized configurations and refresh configs on the fly
But if still you are not happy with this and you need to stick with what you have done above, I guess the problem is with your method :
public void addBean(String beanName, Object beanObject){
ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext)context).getBeanFactory();
beanFactory.registerSingleton(beanName, beanObject);
}
Because since it does not register a bean definition, spring context will not know that its really there.
Would suggest to try adding :
BeanDefinitionRegistry reg = (BeanDefinitionRegistry) context.getAutowireCapableBeanFactory();
reg.registerBeanDefinition(beanName,beanDefinition);
so basically your addBean method should change as follows,
public void addBean(String beanName, Object beanObject){
ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext)context).getBeanFactory();
beanFactory.registerSingleton(beanName, beanObject);
BeanDefinition beanDefinition = beanFactory.getBeanDefinition( beanName );
BeanDefinitionRegistry reg = (BeanDefinitionRegistry) context.getAutowireCapableBeanFactory();
reg.registerBeanDefinition(beanName,beanDefinition);
}
Let's say I have the following:
#Component
#NoArgsConstructor
public class ToolFactory {
public Tool getTool(String type) {
return StaticToolProvider.getTool(type);
}
}
This class will be injected elsewhere and called like this:
Tool screwdriver = ToolFactory.getTool("screwdriver")
If the tools can be screwdriver, hammer, or wrench, I want Spring to create Singleton beans for each, and return them when getTool() is called. I believe #Provides #Singleton would do this in Guice, but how could I do it here?
I would create map with all needed beans. Map will be singleton by default and unmodifiable to prevent anyone changing it by mistake. If you need hammer to be spring bean just autowire it, if no you can just use regular object creation using new
#Configuration
class Config {
#Bean
Map<String, Tool> tools(Hammer hammer) {
Map<String, Tool> map = new HashMap<>();
map.put("hammer", hammer);
//map.put("hammer",new Hammer())
return Collections.unmodifiableMap(map);
}
}
#Component
public class Container {
private Map<String, Tool> tools;
#Autowired
public Container(Map<String, Tool> tools) {
this.tools = tools;
}
Tool getTool(String tool) {
return tools.get(tool);
}
}
I am writing services in Spring boot that get their configurations from Spring cloud. These services are multi-tenant and the tenant is based on the host name.
what I have now is
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);
}
}
where MyServiceFactory looks something like...
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;
}
}
then in a configuration file
#Configuration
public ServiceFactoryConfiguration {
#Bean
public MyServiceFactory getMyServiceFactory() {
return new MyServiceFactory()
.withService("client1", new MyService1())
.withService("client2", new MyService2());
}
}
While what I have now works, I don't like that I need to create a factory for every dependency my controller may have. I'd like to have my code look something like this...
public class MyController {
#Autowired
public MyController(MyService service) {
...
}
#RequestMapping("some/path/{id}")
ResponseEntity<SomeEntity> getSomeEntity(#PathVariable id) {
return service.handle(id);
}
}
with a configuration file like
#Configuration
public class MyServiceConfiguration() {
#Bean
#Qualifier("Client1")
public MyService getMyService1() {
return new MyService1();
}
#Bean
#Qualifier("Client2")
public MyService getMyService2() {
return new MyService2();
}
}
I can get the code that I want to write if I use a profile at application start up. But I want to have lots of different DNS records pointing to the same (pool of) instance(s) and have an instance be able to handle requests for different clients. I want to be able to swap out profiles on a per request basis.
Is this possible to do?
Spring profiles would not help here, you would need one application context per client, and that seems not what you want.
Instead you could use scoped beans.
Create your client dependent beans with scope 'client' :
#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();
}
There will be at least 3 beans of type MyService : the scoped one, and one for each client. The annotation #Primary tells spring to always use the scoped bean for injection.
Create a scope :
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;
};
}
And your client specific beans are configured like this :
#Bean('Client1.myService')
public MyService getMyService1() {
return new MyService1();
}
#Bean('Client2.myService')
public MyService getMyService2() {
return new MyService2();
}
Did not test it but used it in my projects. Should work.
tutorial spring custom scope