简体   繁体   中英

Spring Qualifier and property placeholder

Does anyone know if I should be able to use property placeholder as an expression in a Qualifier? I can't seem to get this working.

I am using spring 3.0.4.

@Controller
public class MyController {
   @Autowired
   @Qualifier("${service.class}")
   Service service;
}

@Service
@Qualifier("ServiceA")
ServiceA implements Service {
   public void print() {
       System.out.println("printing ServiceA.print()");
   } 
}

@Service
@Qualifier("ServiceB")
ServiceB implements Service {
   public void print() {
      System.out.println("printing ServiceB.print()");
   } 
}

XML:

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="file:/etc/config.properties"/>
</bean>

config.properties:

config.properties
service.class=serviceB

This works. You can leave off the service names if you just use the default spring bean name. serviceA vs ServiceA, etc.

@Controller
class MyController {
@Autowired(required=false)
@Qualifier("Service")
Service service;

public static void main(String[] args) {
   ApplicationContext context = new ClassPathXmlApplicationContext("app-ctx.xml", MyController.class);
   for(String s:context.getBeanDefinitionNames()){
       System.out.println(s);
       for(String t:context.getAliases(s)){
           System.out.println("\t" + t);
       }
   }
   context.getBean(MyController.class).service.print();
  }
}

public interface Service {
    void print();
}

@Service(value="ServiceA")
public class ServiceA implements example.Service {
    public void print() {
        System.out.println("printing ServiceA.print()");
    } 
}

@Service(value="ServiceB")
public class ServiceB implements example.Service {
    public void print() {
        System.out.println("printing ServiceB.print()");
    } 
}

XML:

<beans>
    <alias name="${service.class}" alias="Service"/>
    <context:property-placeholder location="example/app.properties"/>
    <context:component-scan base-package="example"/>
<beans>

Props:

service.class=ServiceB

This solution works without XML and with properties file.

Yours classes improved:

MyController.java :

@Controller
public class MyController {
    @Autowired
    public MyController(@Qualifier("MyServiceAlias") MyService myService) {
        myService.print();
    }
}

ServiceA.java :

@Service("serviceA")
public class ServiceA implements MyService {
    @Override
    public void print() {
        System.out.println("printing ServiceA.print()");
    }
}

ServiceB.java :

@Service("serviceB")
public class ServiceB implements MyService {
    @Override
    public void print() {
        System.out.println("printing ServiceB.print()");
    }
}

application.properties (here you can change which class will be loaded):

service.class=serviceA

And important configuration file AppConfig.java :

@Configuration
public class AppConfig {

    @Autowired
    private ApplicationContext context;

    @Bean
    public MyService MyServiceAlias(@Value("${service.class}") String qualifier) {
        return (MyService) context.getBean(qualifier);
    }
}

Additional explanations:

  • Use @Qualifier only for field which will be autowired. For services, to specify bean name, use @Service .
  • If you want standard bean name you don't need to use @Service with specyify name. For example, standard bean name for ServiceA is serviceA (not ServiceA - see big first letter), so @Service("serviceA") redundant ( @Service is enough).
  • I based AppConfig on this answer: Spring Bean Alias in JavaConfig .
  • This solution is better than this Spring Qualifier and property placeholder , because you don't need XML.
  • Tested on Spring Boot 1.5.7.

I would venture to guess the answer is no, just based on the write ups in a few javadoc pages. For example, see the docs for @Value :

http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/beans/factory/annotation/Value.html

Notice they make special mention of using expressions in the annotation. For comparison, the docs for @Qualifier :

http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/beans/factory/annotation/Qualifier.html

Which make no mention of expressions. Obviously not a definitive answer (but spring is generally very good on documentation). Also, if expressions were supported in the @Qualifier annotation I would expect they work the same way as the @Value annotation (just based on spring being a very consistent framework).

Spring 3.1 has the new profile bean feature, which seems like it can accomplish something like what you're trying to do. Here's a write up for that:

http://blog.springsource.com/2011/02/14/spring-3-1-m1-introducing-profile/

As a workarround, you can set the desired Spring service implementation based on its name in your config.properties.

@Controller
public class MyController {
  //add a String which will hold the name of the service to implement
  @Value("${service.class}")
  private String serviceToImplement;

  Service service;

  // now autowire spring service bean based on int name using setter
  @Autowired
  public void setService(ApplicationContext context) {
    service = (Service) context.getBean(serviceToImplement);
   }
}

@Service
 @Qualifier("ServiceA")
 ServiceA implements Service {
  public void print() {
   System.out.println("printing ServiceA.print()");
  } 
}

 @Service
 @Qualifier("ServiceB")
 ServiceB implements Service {
   public void print() {
    System.out.println("printing ServiceB.print()");
   } 
}

config.properties

service.class=serviceB

Maybe give this a whirl:

@Controller
public class MyController {

   private String serviceId;

   @Value("${serviceId}")
   public void setServiceId(String serviceId) {
      this.serviceId = serviceId;
   }

   @Autowired
   @Qualifier(serviceId)
   Service service;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM