Spring Qualifier, service implementation when application starts

1.3k Views Asked by At

(spring version is 4.1.6) I have a service Interface "ContractService" that retreives contracts of a person. 2 service classes ContratServiceImpl & ContratServiceImplWeb implementing this interface. ContratServiceImpl calls dao to retreive data ContratServiceImplWeb calls web service...

The Interface ContractService is used by another service (UTService):

 @org.springframework.stereotype.Service
    @Transactional(value="transactionManager")
    public class UTServiceImpl implements UTService {

        @Autowired @Qualifier(...<variable.propeties>...)
        private ContractService contractService;
   ...
}

Here are services implementing the interface that can be in

@Service("ContratServiceImplWeb") @Transactional(value="transactionManager")
class ContratServiceImplWeb implements ContratService {
...
}

@Service("ContratServiceImpl") @Transactional(value="transactionManager")
class ContratServiceImpl implements ContratService {
...
}

Configuration class
@Configuration
@EnableTransactionManagement
@ImportResource(value={ "classpath:sessionFactory-datasource-spring.xml", "classpath:contrat_factories.xml"} )
@ComponentScan(basePackages = { "com.xxx.core.service.impl"
                              , "com.xxx.core.dao.impl"}
)
public class ContextCoreServiceConfiguration {

}

When my application starts I would like to "qualify" ContractService with ContratServiceImpl or ContratServiceImplWeb depending an external configuration file (.properties or XML) where bean names are set.

How can I do this ?

----- Last comments ------- contractServiceImpl & contractServiceImplWeb are set as @service and scanned by configuration.

In "UTServiceImple" class, 1 of the 2 classes need to be @autowired with a discriminating parameter (may Profile ?). This is not the only group of classes that is concerned.

Profile should not be the same from a couple to another. So, I have to set a profile for each group of classes ?

3

There are 3 best solutions below

0
On

I guess Spring profiles is exactly what you are looking for.

They let you choose a specific bean implementation dynamically based on a parameter (active profile).

For detailed information, please have a look here if you are using boot or here if using raw spring.

0
On

You are close. You want your ContractService declaration to look more like this:

@Autowired
private @Qualifier("contractServiceImpl") ContractService contractServive;

This of course presumes that your ContractServiceImpl bean was correctly configured and created, either manually or using the @Service or @Component annotation on your class.

0
On

I post the solution. I used @Profiles. It really feeds my needs. Thanks for having given me this information.

@org.springframework.stereotype.Service
@Transactional(value="transactionManager")
public class UTServiceImpl implements UTService {

    private static final Logger logger = Logger.getLogger(UTServiceImpl.class);

    // SERVICES
    @Autowired
    private VerificationHabilitationService verificationHabilitationService;

    @Autowired
    private ContratService contratService;
...
}

Interface referenced in the main service

public interface ContratService {

    Set rechercheIdentifiantAdherent(String numeroImmatriculation);
...
}

Database Service

@Service("ContratServiceDb") @Transactional(value="transactionManager") @Profile("contratServiceDb")
class ContratServiceImplDb implements ContratService {

    private Logger logger = null;

    @Autowired
    private ContratFactory contratFactory;
...
}

Web Service

@Service("ContratServiceWeb") @Transactional(value="transactionManager") @Profile("contratServiceWeb")
class ContratServiceImplWeb implements ContratService {

    private Logger logger = Logger.getLogger(ContratServiceImplWeb.class);

    @Autowired
    private ContratFactory contratFactory;
...
}

Configuration

@Configuration
@EnableTransactionManagement
@ImportResource(value={ "classpath:sessionFactory-datasource-spring.xml", "classpath:contrat_factories.xml"} )
@ComponentScan(basePackages = { "com.xxx.core.service.impl"
                              , "com.xxx.core.dao.impl"}
)
public class ContextCoreServiceConfiguration {

}

For each implementation classe I define a Pofile : contratServiceDb, contratServiceWeb. When context is initialized I set active profile (using external properties file). Then, services matching profiles are autowired. See below :

String configCoreClass = servlet.getInitParameter("contextCoreConfigurationClass");
            String[] profiles = { PropertiesHelper.getProperty(PropertiesHelper.PROPERTY_SERVICE_CONTRAT)
                                 ,PropertiesHelper.getProperty(PropertiesHelper.PROPERTY_SERVICE_ADHERENT) 
            };
            AnnotationContextCoreLocator.getInstance().getEnvironment().setActiveProfiles(profiles);
            AnnotationContextCoreLocator.getInstance().register( Class.forName(configCoreClass) );
            AnnotationContextCoreLocator.getInstance().refresh();