我正在使用带有注释的Spring Beans,我需要在运行时选择不同的实现.
@Service public class MyService { public void test(){...} }
例如对于我需要的Windows平台MyServiceWin extending MyService
,对于我需要的linux平台MyServiceLnx extending MyService
.
现在我只知道一个可怕的解决方案:
@Service public class MyService { private MyService impl; @PostInit public void init(){ if(windows) impl=new MyServiceWin(); else impl=new MyServiceLnx(); } public void test(){ impl.test(); } }
请考虑我只使用注释而不是XML配置.
Condition
public class LinuxCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { return context.getEnvironment().getProperty("os.name").contains("Linux"); } }
同样的Windows
.
@Conditional
在Configuration
课堂上使用@Configuration public class MyConfiguration { @Bean @Conditional(LinuxCondition.class) public MyService getMyLinuxService() { return new LinuxService(); } @Bean @Conditional(WindowsCondition.class) public MyService getMyWindowsService() { return new WindowsService(); } }
@Autowired
照常使用@Service public class SomeOtherServiceUsingMyService { @Autowired private MyService impl; // ... }
让我们创建漂亮的配置.
想象一下,我们有Animal界面,我们有Dog和Cat实现.我们想写写:
@Autowired Animal animal;
但我们应该返回哪个实施?
那么解决方案是什么?有很多方法可以解决问题.我将一起编写如何使用 @Qualifier和Custom Conditions.
首先,让我们创建自定义注释:
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE}) public @interface AnimalType { String value() default ""; }
和配置:
@Configuration @EnableAutoConfiguration @ComponentScan public class AnimalFactoryConfig { @Bean(name = "AnimalBean") @AnimalType("Dog") @Conditional(AnimalCondition.class) public Animal getDog() { return new Dog(); } @Bean(name = "AnimalBean") @AnimalType("Cat") @Conditional(AnimalCondition.class) public Animal getCat() { return new Cat(); } }
注意我们的bean名称是AnimalBean.为什么我们需要这个豆?因为当我们注入Animal接口时,我们只会编写@Qualifier("AnimalBean")
我们还创建了自定义注释来将值传递给我们的自定义条件.
现在我们的条件看起来像这样(假设"Dog"名称来自配置文件或JVM参数或...)
public class AnimalCondition implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { if (annotatedTypeMetadata.isAnnotated(AnimalType.class.getCanonicalName())){ return annotatedTypeMetadata.getAnnotationAttributes(AnimalType.class.getCanonicalName()) .entrySet().stream().anyMatch(f -> f.getValue().equals("Dog")); } return false; } }
最后注射:
@Qualifier("AnimalBean") @Autowired Animal animal;
您可以将bean注入移动到配置中,如下所示:
@Configuration public class AppConfig { @Bean public MyService getMyService() { if(windows) return new MyServiceWin(); else return new MyServiceLnx(); } }
另外,您也可以使用配置文件windows
和linux
,然后与注释您的服务实现@Profile
批注,如@Profile("linux")
或@Profile("windows")
,并提供此配置文件用于您的应用程序之一.