SpringBoot(15) @ Conditional annotation

Posted by afrim12 on Wed, 21 Aug 2019 14:46:44 +0200

#

SpringBoot(15) @ Conditional annotation

Function @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)

Topics: Windows Mac Spring Linux