0

In my application I would like to instantiate a class on demand and pass some runtime parameters to is as well as have Spring automatically fulfil any @Autowired dependencies. For example, the class I would like to instantiate on demand:

@Service
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class FileProcess implements Runnable
{
    @Autowired
    private MyDAO myDAO;

    private String configOne;

    private String configTwo;

    @Override
    public void run()
    {
    }
}

The object myDAO exists already within the ApplicationContext and I would like Spring to fulfil this dependency for me. Indeed any instantiation of this class shouldn't really know the internals of FileProcess only that it requires the configuration parameters configOne and configTwo

To get an instance of FileProcess I have use the getBean() method of the ApplicationContext but I am unable to pass in only the configuration parameters:

final FileProcess fileProcess = this.applicationContext.getBean(FileProcess.class, configOne, configTwo)

This results in the error:

Could not resolve matching constructor (hint: specify index/type/name arguments for simple parameters to avoid type ambiguities

I have found that no matter what constructor I add to FileProcess I get the same error. I would like to only have to pass in the configuration parameters and not, in this case not an instance of MyDAO. Again, having to pass in an instance of MyDAO means the caller must have knowledge of the internals of FileProcess and in general must be aware of the scope of such beans.

Is there a way I can achieve this without having to resort to a @Configuration class and a @Bean annotated method?

D-Dᴙum
  • 7,689
  • 8
  • 58
  • 97
  • Create setters for the config fields and a constructor for the Dao, then you can create it in a `@Bean` method. – daniu Jan 19 '20 at 14:34
  • I I have understood you correctly if I did that, I believe I could not use the `getBean()` method to automatically inject `MyDAO` because it results in a circular reference, and I don't want to pass in a DAO because I would need to know its scope – D-Dᴙum Jan 19 '20 at 14:42

1 Answers1

1

I think you'd be best off with a factory bean, like

@Bean
BiFunction<String, String, FileProcess> createFileProcess(MyDAO dao) {
    return (c1, c2) -> {
        FileProcess result = new FileProcess(dao) ;
        result.setConfig1(c1);
        result.setConfig2(c2);
        return result;
   };
}

This in a configuration class, and you can Autowire it to create the process object with your config values.

@Autowired
BiFunction<String, String, FileProcess> processFactory;
... 
FileProcess p = processFactory.apply("val1", "val2");
daniu
  • 14,137
  • 4
  • 32
  • 53
  • 1
    Although this is not how I have solved it, your answer was the basis for my solution. Above you have solved for my specific case and uses a `BiFunction` type I extended it further to sove for the general case. Instead of `BiFunction` I created a factory class with `getInstance`. The factory class is annotated as a service and I can use the `ApplicationContext.getBean()` within `getInstance` to autowire the dependencies. – D-Dᴙum Jan 19 '20 at 16:01