How to choose bean implementations at runtime in spring

I have a problem that I am trying to solve. I need to return an implementation based on user input. I've considered using the Abstract Factory Pattern, but not sure if this is the best way to go or not (or if Spring can help me a bit along the way).

Here is the interface that factories will return to:

public interface Flow {
    List<Message> execute(String sessionKey);
}

      

and 1 implementation of this interface:

@Component("AssignSeatFlow")
public class AssignSeatFlow implements ChatbotFlow {

    private SeatService seatService;

    @Autowired
    public AssignSeatFlow(final SeatService seatService) {
        this.seatService = seatService;
    }

    @Override
    public List<Message> execute(String sessionKey) {
        // Implementation here
    }
}

      

My current Factory interface:

public interface FlowFactory {

    Flow getFlow(final String intentCode);

}

      

and its implementation:

@Component
public class FlowFactoryImpl implements FlowFactory {

    @Resource("AssignSeatFlow")
    private Flow assignSeatFlow;

    @Override
    public Flow getFlow(final String intentCode) {
        if(StringUtils.isNullOrEmpty(intentCode)) {
            throw new IllegalArgumentException("Intent Code cannot be empty");
        }

        switch (intentCode.toUpperCase()) {
            case "AssignSeatFlow":
                return assignSeatFlow;
            default:
                throw new IllegalArgumentException("Unable to determine flow");
        }
    }
}

      

The reason it doesn't seem ideal is because as I add more threads the Factory will be much larger and I will have to change it every time I do this. I am also not a fan of field Autowiring as it makes testing more difficult and less explicit.

Thanks for any feedback.

+3


source to share


1 answer


I would inject spring context into my factory and get the bean right away:

@Autowired 
private ApplicationContext ctx;
.
.
.
public Flow getFlow(final String intentCode) {
    return ctx.getBean(intentCode);
}

      



I left out error handling, but that's the main idea. This way you have a factory that you never have to touch when you add more stream types.

Accessing the application context is not a good general practice as it encourages people to use spring as a service locator. But he does work in factories.

+2


source







All Articles