#
SpringBoot(15) @ Conditional annotationFunction @Conditional is a new annotation provided by Spring 4. Its function is to judge according to certain conditions and register beans for containers only when the conditions are met.
I. Overview
1. @Conditional annotation definition
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Conditional { Class<? extends Condition>[] value(); }
2,Condition
When we checked in, we found that it was an interface and had a method.
@FunctionalInterface public interface Condition { boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2); }
3,ConditionContext
It holds a lot of useful objects and can be used to obtain a lot of system-related information to enrich conditional judgment. The interface is defined as follows
public interface ConditionContext { /** * Getting Bean Definitions */ BeanDefinitionRegistry getRegistry(); /** * Get the bean project, so you can get all the beans in the container */ @Nullable ConfigurableListableBeanFactory getBeanFactory(); /** * environment Hold all configuration information */ Environment getEnvironment(); /** * resource information */ ResourceLoader getResourceLoader(); /** * Class loading information */ @Nullable ClassLoader getClassLoader(); }
## 2. Cases
Requirements vary according to different instances of the current system environment, such as Mac, which is an instance of a Bean, if it is a Window s system instance of another Bean.
1,SystemBean
First create a Bean class
@Data @AllArgsConstructor @NoArgsConstructor @ToString public class SystemBean { /** * System name */ private String systemName; /** * System code */ private String systemCode; }
2. Instantiating Bean s through Configuration Configuration Configuration
@Slf4j @Configuration public class ConditionalConfig { /** * If the implementation of Windows Condition returns true, the bean is injected */ @Bean("windows") @Conditional({WindowsCondition.class}) public SystemBean systemWi() { log.info("ConditionalConfig Method injection windows entity"); return new SystemBean("windows system","002"); } /** * If the implementation of LinuxCondition returns true, the bean is injected */ @Bean("mac") @Conditional({MacCondition.class}) public SystemBean systemMac() { log.info("ConditionalConfig Method injection mac entity"); return new SystemBean("Mac ios system","001"); } }
3. Windows Conditions and MacCondition
Both classes implement the Condition interface, and only when the matches method returns true will the current Bean be instantiated.
1)WindowsCondition
@Slf4j public class WindowsCondition implements Condition { /** * @param conditionContext:Judging the context in which conditions can be used * @param annotatedTypeMetadata:Annotation information for the location of the annotation */ @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { //Get the beanFactory used by ioc ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory(); //Get the class loader ClassLoader classLoader = conditionContext.getClassLoader(); //Getting current environmental information Environment environment = conditionContext.getEnvironment(); //Get the registration class defined by the bean BeanDefinitionRegistry registry = conditionContext.getRegistry(); //Get the current system name String property = environment.getProperty("os.name"); //Including Windows means that it is a Windows system, returning true if (property.contains("Windows")){ log.info("The current operating system is: Windows"); return true; } return false; } }
2) MacCondition
@Slf4j public class MacCondition implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { Environment environment = conditionContext.getEnvironment(); String property = environment.getProperty("os.name"); if (property.contains("Mac")) { log.info("The current operating system is: Mac OS X"); return true; } return false; } }
4. Test class testing
/** * @author xub * @date 2019/6/13 10:42 p.m. */ @SpringBootTest(classes = Application.class) @RunWith(SpringRunner.class) public class TestConditionOn { @Autowired private SystemBean windows; @Autowired private SystemBean mac; @Test public void test() { if (windows != null) { System.out.println("windows = " + windows); } if (mac != null) { System.out.println("linux = " + mac); } } }
Operation results
It can be seen from the results of operation.
1. Although two Beans are configured, only one Bean is instantiated here, because I have a Mac computer on my side, so the SystemBean of MAC is instantiated.
2. Note that window s are not null, but mac instantiated beans. It shows that as long as you instantiate a Bean, whatever you name, you can inject the Bean.
Modify
Let's make a change here. We comment out this line of code in Conditional Config.
// @Conditional({WindowsCondition.class})
Run the code again
As you can see from the running results, both beans of the configuration class have been injected successfully.
Note that when the same object is injected twice or more, then when you use the current object, the name must be one of the two bean names, otherwise an error will be reported. For example, change to
@Autowired private SystemBean windows; @Autowired private SystemBean mac; @Autowired private SystemBean linux;
On startup, it was found that the error was reported.
Obviously, when you only instantiate a System Bean above, you name it by any name. Anyway, you just inject the object that has been instantiated into you.
But now you have injected two System Beans at the same time. You have a name of linux at this time. It doesn't know which Bean should be injected, so it adopts the error-reporting strategy.
GitHub source code https://github.com/yudiandemingzi/spring-boot-study
Project name 03-conditional
### Reference
1. Spring@Conditional annotation
As long as you become excellent, everything else will follow (Lieutenant General 3)