Spring Qualifier and property placeholder

2020-01-24 12:59发布

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

4条回答
爱情/是我丢掉的垃圾
2楼-- · 2020-01-24 13:10

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
查看更多
Ridiculous、
3楼-- · 2020-01-24 13:11

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.
查看更多
Summer. ? 凉城
4楼-- · 2020-01-24 13:27

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/

查看更多
做自己的国王
5楼-- · 2020-01-24 13:30

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;
}
查看更多
登录 后发表回答