I'm relatively new to Spring and I've got myself dug in a hole. I'm trying to model motor cars. Each model has it's own builder object, and I have a BuilderFactory that returns the correct builder based upon user selection from a web-app.
So I'm looking for suggestions on how to approach this problem where I need to create a number of individual vehicles, but I don't know what type of vehicle I'm going to need until run-time, and each vehicle needs to be unique to the user.
What I've got at the moment is shown below. The problem I have at the moment is that because the individual builders are singletons so are the individual vehicles. I need them to be prototypes. I know it all looks pretty horrible so I'm sure there must be a better way of doing this.
The top level from the web-app looks like;
Vehicle vehicle = vehicleBuilderFactory.getBuilder(platform).build();
My vehicleBuilderFactory looks like this;
@Service
public class VehicleBuilderFactory {
@Autowired
Discovery3Builder discovery3Builder;
@Autowired
Discovery4Builder discovery4Builder;
// Lots of @Autowired statements here.
@Autowired
FreeLander2010Builder freeLander2010Builder;
public VehicleBuilder getBuilder(Platform platform) {
switch (platform.getId()) {
case 1: return discovery3Builder;
case 2: return discovery4Builder;
// Lots of case statements here
case 44: return freeLander2010Builder;
default: return null;
}
}
}
which itself looks pretty horrible. Each individual builder looks like;
@Service
public class DefenderBuilder implements VehicleBuilder {
@Autowired
Defender defender;
// Loads of Defender specific setters ommitted
@Override
public Vehicle build() {
return defender;
}
}
and finally the individual vehicle
@Service
@Scope("prototype")
public class Defender extends Vehicle {
}
The main problem now, is that because the builders are singletons, so are the vehicles, and I need them to be prototypes, because User A's Defender is different to user B's Defender.
Without reading too much into the detail you say you want to produce Prototype beans from a singleton possibly with a look up in the IoC container.
Section 3.4.6.1 Lookup method injection of the Spring documentation describes how this can be done without losing the Inversion of Control i.e. without your beans knowing about the bean store.
I have made use of the ServiceLocatorFactoryBean to solve a similar problem before. The class level Javadoc is excellent and contains some clear examples.
Two things: 1) You can use proxy in order to hold narrower scope from wider scope(e.g prototype from singleton) All you need is to define the prototype component with the relevant scope and proxyMode You can read about scoped proxy here.
2) Another thing that I have noticed is that you plan to use multiple autowired annotation. note that you can use autowire on a list of interface and it will autowire all components that implements this interface as discussed here.
Moreover you can add a platform id to the VehicleBuilder interface and then generate a map in the constructor e.g:
in that way you can avoid the switch case.
You can use Spring's ObjectFactory to have it service up prototype scoped beans from a singleton scoped bean. The usage is pretty straightforward:
This returns a new Defender on each call to defenderFactory.getObject()