Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create multiple beans from one method in @Configuration class

Tags:

java

spring

I am Spring for DI and am NOT using XML.

Based on configuration (eg. an xml/properties file), I am looking to create a number of beans (exact number is determined by the configuration) of a specific type to put in my context so that they can be autowired into classes.

I would autowire by: @Autowired public MyClass(List<MyType> types)

I am looking at using an class annotated with @Configuration.

So I can do something like this:

@Configuration
public MyConfigurationClass {

    @Autowired
    public void configure(ApplicationContext context) {
        // register stuff here
    }
}

...but it doesn't "feel" right...

What is the "Spring" way to achieve this?

EDIT:

Imagine this code, where To and Ty are just empty class definitions.

@Configuration
public class Config {

    @Bean
    public Collection<Ty> tyList() {
        return new ArrayList<Ty>() {{
            this.add(new Ty()); // could be any number of Ty instances.
        }};
    }

    @Bean
    public To to(Collection<Ty> tylist) {
        return new To();
    }
}
like image 846
Cheetah Avatar asked Oct 19 '22 23:10

Cheetah


2 Answers

If you don't need to have separate qualifiers and can Autowire as List you can do this in Spring 4:

@Configuration
public MyConfigurationClass {

    @Bean
    public List<MyType> configure() {
        //create your dynamical list here
    }
}

But for Spring 3 (where generics were ignored) you would be safer to use:

@Configuration
public MyConfigurationClass {

    @Bean
    @Qualifier("mylist")
    public List<MyType> configure() {
        //create your dynamical list here
    }
}

and autowire:

@Autowired public MyClass(@Qualifier("mylist") List<MyType> types)

With this you wouldn't need to touch ApplicationContext instance directly. It's not considered as very good practice.

EDIT:

Did you try this?:

@Configuration
public class Config {

    @Bean
    @Qualifier("tylist")
    public Collection<Ty> tyList() {
        return new ArrayList<Ty>() {{
            this.add(new Ty()); // could be any number of Ty instances.
        }};
    }

    @Bean
    public To to(@Qualifier("tylist") Collection<Ty> tylist) {
        return new To();
    }
}
like image 125
luboskrnac Avatar answered Oct 22 '22 14:10

luboskrnac


I think it depends on where and how properties are read. If you read those properties using vanilla java, you could register bean definitions by implementing BeanFactoryPostProcessor. However, if the properties themselves come as a bean (eg. as a result of @ConfigurationProperties), I'm somewhat confident you're out of luck. After googling for some time, I come to conclusion that the only robust solution is to refactor whole design, and instead of providing multiple MyType beans, provide single MyTypeProvider bean, which in turn would have a single method with signature List<MyType> getStuff(). Then, at the point where you had List<MyType> injected, inject List<MyTypeProvider> instead, and merge their results of getStuff into a single List<MyType>. Again, I know this is more of a workaround, but this the best I could find so far.

like image 31
Coderino Javarino Avatar answered Oct 22 '22 14:10

Coderino Javarino