08-02-2023, 05:48 AM
Using Spring's Java Config, I need to acquire/instantiate a prototype-scoped bean with constructor arguments that are only obtainable at runtime. Consider the following code example (simplified for brevity):
@Autowired
private ApplicationContext appCtx;
public void onRequest(Request request) {
//request is already validated
String name = request.getParameter("name");
Thing thing = appCtx.getBean(Thing.class, name);
//System.out.println(thing.getName()); //prints name
}
where the Thing class is defined as follows:
public class Thing {
private final String name;
@Autowired
private SomeComponent someComponent;
@Autowired
private AnotherComponent anotherComponent;
public Thing(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
Notice `name` is `final`: it can only be supplied via a constructor, and guarantees immutability. The other dependencies are implementation-specific dependencies of the `Thing` class, and shouldn't be known to (tightly coupled to) the request handler implementation.
This code works perfectly well with Spring XML config, for example:
<bean id="thing", class="com.whatever.Thing" scope="prototype">
<!-- other post-instantiation properties omitted -->
</bean>
How do I achieve the same thing with Java config? The following does not work using Spring 3.x:
@Bean
@Scope("prototype")
public Thing thing(String name) {
return new Thing(name);
}
Now, I *could* create a Factory, e.g.:
public interface ThingFactory {
public Thing createThing(String name);
}
But that _defeats the entire point of using Spring to replace the ServiceLocator and Factory design pattern_, which would be ideal for this use case.
If Spring Java Config could do this, I would be able to avoid:
* defining a Factory interface
* defining a Factory implementation
* writing tests for the Factory implementation
That's a ton of work (relatively speaking) for something so trivial that Spring already supports via XML config.
@Autowired
private ApplicationContext appCtx;
public void onRequest(Request request) {
//request is already validated
String name = request.getParameter("name");
Thing thing = appCtx.getBean(Thing.class, name);
//System.out.println(thing.getName()); //prints name
}
where the Thing class is defined as follows:
public class Thing {
private final String name;
@Autowired
private SomeComponent someComponent;
@Autowired
private AnotherComponent anotherComponent;
public Thing(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
Notice `name` is `final`: it can only be supplied via a constructor, and guarantees immutability. The other dependencies are implementation-specific dependencies of the `Thing` class, and shouldn't be known to (tightly coupled to) the request handler implementation.
This code works perfectly well with Spring XML config, for example:
<bean id="thing", class="com.whatever.Thing" scope="prototype">
<!-- other post-instantiation properties omitted -->
</bean>
How do I achieve the same thing with Java config? The following does not work using Spring 3.x:
@Bean
@Scope("prototype")
public Thing thing(String name) {
return new Thing(name);
}
Now, I *could* create a Factory, e.g.:
public interface ThingFactory {
public Thing createThing(String name);
}
But that _defeats the entire point of using Spring to replace the ServiceLocator and Factory design pattern_, which would be ideal for this use case.
If Spring Java Config could do this, I would be able to avoid:
* defining a Factory interface
* defining a Factory implementation
* writing tests for the Factory implementation
That's a ton of work (relatively speaking) for something so trivial that Spring already supports via XML config.