Spring 限定符和属性占位符

发布于 2024-12-10 18:27:28 字数 844 浏览 0 评论 0 原文

有谁知道我是否应该能够使用属性占位符作为限定符中的表达式?我似乎无法让这个工作。

我正在使用 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
service.class=serviceB

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

说谎友 2024-12-17 18:27:28

这有效。如果您只使用默认的 spring bean 名称,则可以省略服务名称。 serviceA 与 ServiceA 等

@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 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
伪装你 2024-12-17 18:27:28

该解决方案无需 XML,只需使用属性文件即可工作。

您的类已改进:

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 (在这里您可以更改将加载哪个类):

service.class=serviceA

以及重要的配置文件AppConfig.java

@Configuration
public class AppConfig {

    @Autowired
    private ApplicationContext context;

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

附加说明:

  • 仅对将自动装配的字段使用@Qualifier。对于服务,要指定 bean 名称,请使用 @Service
  • 如果您想要标准 bean 名称,则不需要使用 @Service 来指定名称。例如,ServiceA 的标准 bean 名称是 serviceA (不是 ServiceA - 请参阅大首字母),因此 @Service("serviceA") 是多余的(@Service 就足够了)。
  • 我基于AppConfig这个答案:Spring Bean Alias in JavaConfig
  • 这个解决方案比这个 Spring 限定符和属性占位符更好,因为您不需要 XML。
  • 在 Spring Boot 1.5.7 上测试。

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.
月依秋水 2024-12-17 18:27:28

仅根据一些 javadoc 页面中的记录,我敢猜测答案是否定的。例如,请参阅 @Value 的文档:

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

注意他们特别提到在注释中使用表达式。为了进行比较,@Qualifier 的文档:

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

其中没有提及表达式。显然不是一个明确的答案(但 spring 在文档方面通常非常好)。另外,如果 @Qualifier 注释支持表达式,我希望它们的工作方式与 @Value 注释相同(仅基于 spring 是一个非常一致的框架)。

Spring 3.1 具有新的配置文件 bean 功能,这似乎可以完成您想要做的事情。这是一篇文章:

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

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/

千秋岁 2024-12-17 18:27:28

作为解决方法,您可以根据 config.properties 中的名称设置所需的 Spring 服务实现。

@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()");
   } 
}

配置属性

service.class=serviceB

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
我不咬妳我踢妳 2024-12-17 18:27:28

只需使用@ConditionalOnProperty
如果您不需要在一个上下文中使用这两种服务,那么您的代码可能类似于:

@Service
@ConditionalOnProperty(value="storage.type", havingValue = "serviceA")
ServiceA implements Service {
   public void print() {
       System.out.println("printing ServiceA.print()");
   } 
}

@Service
@ConditionalOnProperty(value="service.class", havingValue = "serviceB")
ServiceB implements Service {
   public void print() {
      System.out.println("printing ServiceB.print()");
   } 
}

@Controller
public class MyController {
   @Autowired
   Service service;
}

Just use @ConditionalOnProperty.
If you don't need to use both of those services in one context, then your code could be something like:

@Service
@ConditionalOnProperty(value="storage.type", havingValue = "serviceA")
ServiceA implements Service {
   public void print() {
       System.out.println("printing ServiceA.print()");
   } 
}

@Service
@ConditionalOnProperty(value="service.class", havingValue = "serviceB")
ServiceB implements Service {
   public void print() {
      System.out.println("printing ServiceB.print()");
   } 
}

@Controller
public class MyController {
   @Autowired
   Service service;
}
平安喜乐 2024-12-17 18:27:28

也许尝试一下:

@Controller
public class MyController {

   private String serviceId;

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

   @Autowired
   @Qualifier(serviceId)
   Service service;
}

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文