Is it a good practice in Java EE and CDI to select the implementatation to be injected based on the configuration value stored in the database?

Egor Erofeev :

I have a task to rewrite some old logic stored in the database procedures in java, using JavaEE 7. The application is deployed on JBoss EAP 7.

There is a critical functionality, therefore we need to have some sort of a switcher, in order to be able to switch between old and new implementation of some services in production quickly.

Unfortunatelly we are not able to deliver and deploy new versions immediately, even in case of critical problems. So we need to introduce such switcher in form of a database table.

In order to provide good maintainability, I would like to use CDI to inject old/new implementations based on the switcher.

The simpliest way I see, is to utilize CDI Producers. Would it be the good solution to make a DB-Request in a Producer Method?

My Example:

@ApplicationScoped
public class NewServiceProducer {

    @Inject
    private ImplementationSwitcherDAO implementationSwitcherDAO;

    @Produces
    @RequestScoped
    public NewService produceNewService(){
        //a DB-Call is done here        
        boolean useOldVersion = implementationSwitcherDAO.isUseOldVersionForService("NewService");

        if(useOldVersion){
            return CDI.current().select(NewServiceOldImpl.class).get();
        }

        return CDI.current().select(NewServiceImpl.class).get();
    }
}
Laird Nelson :

I can't really comment on the "good practice" question, but you have a question in here that deserves an answer.

To do what you want, you need to do one, but not both, of the following:

  1. Make sure that NewServiceOldImpl.class and NewServiceImpl.class do not have NewService in their set of bean types
  2. Veto NewServiceOldImpl.class and NewServiceImpl.class entirely

Otherwise, if you try to @Inject a NewService, there will be two possibilities, and, all else being equal, CDI will fail with some kind of AmbiguousResolutionException.

I would implement your solution like this:

// Let's assume that NewServiceImpl is a regular managed bean
@RequestScoped
@Typed({ NewServiceImpl.class, Object.class }) // ...or whatever, but not NewService.class
public class NewServiceImpl { /*...*/ }

// Let's assume that NewServiceOldImpl is a regular managed bean
@RequestScoped
@Typed({ NewServiceOldImpl.class, Object.class }) // ...or whatever, but not NewService.class
public class NewServiceOldImpl { /*...*/ }

// Then somewhere else:
@Produces
@RequestScoped
private static NewService produceNewService(final NewServiceOldImpl oldImpl,
                                            final NewServiceImpl newImpl) {
  if (implementationSwitcherDAO.isUseOldVersionForService("NewService")) {
    return oldImpl;
  }
  return newImpl;
}

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=388537&siteId=1