The Secret to Mastering Spring Conditional Assembly

This article is shared from Huawei Cloud Community " The Road to Spring Master 9 - Mastering the Secret Weapon of Spring Conditional Assembly ", author: Zhuanyeyang__.

In the Spring framework, conditional assembly is a powerful feature that can help us better manage and control the Bean creation process. This article explains in detail how to use Spring's @Profile and @Conditional annotations to implement conditional assembly. Through specific examples, you can better understand the usage and applicable scenarios of these two annotations. In-depth study of these annotations can help improve the skills of Spring application development and better grasp the Spring framework.

1. Conditional assembly

1.1 Understanding conditional assembly and its important role in Spring

In Springthe framework, conditional assembly ( Conditional Configuration) is a very important feature, which allows developers to dynamically Beanregister or create according to the conditions met. In this way, different Beaninstances can be created according to different environments or configurations. This feature is very useful for creating configurable and modular applications.

SpringA series of annotations are provided to implement conditional assembly, including:

  • @Profile : This isthe annotation. This annotation means that only when the specific oneis activated, the one with the annotation is created. We can set the activation in the application configuration file. Spring ProfileBeanProfile

  • @Conditional : This is the annotation that takes one or more classes that need to implement the interface and override its methods. Annotated ones are created only when all methods of the class return. Spring ConditionConditionmatchesConditionmatchestrue@ConditionalBean

The following annotations are provided, mainly for auto-configuration functions: Spring Boot 

  • @ConditionalOnProperty : This annotation indicates that only when one or more given properties have a specific value, create a property with this annotation Bean.

  • @ConditionalOnClass and @ConditionalOnMissingClass : These two annotations indicate that Classpathonly when there is (or is not) a specific class among them, the one with this annotation will be created Bean.

  • @ConditionalOnBean and @ConditionalOnMissingBean : These two annotations indicate that only Spring ApplicationContextwhen there is (or is not) specific Bean, the one with the annotation is created Bean.

By combining these annotations, developers can implement complex conditional assembly logic and flexibly control Springapplication configuration and behavior.

2. @Profile

In , it is used to solve the needs of different configurations in different environments, and it can assemble applications according to the requirements of specific environments. For example, we may have a set of configurations for the development environment and another set of configurations for the production environment, which can be used . It can determine which environment is active at runtime, and then decide which ones to register . Spring Profile Profilebean

2.1 Actual application scenarios based on @Profile

For example, we may need to use a different database or a different service endpoint.

Here we can take the database configuration as an example. The databases in the development environment, test environment, and production environment may be different. We can configure the databases of these environments separately through annotations. @Profile 

@Configuration
public class DataSourceConfiguration {
    @Value("${spring.datasource.username}")
    private String username;

    @Value("${spring.datasource.password}")
    private String password;

    @Value("${spring.datasource.url}")
    private String url;

    @Bean
    @Profile("dev")
    public DataSource devDataSource() {
        return DataSourceBuilder.create()
                .username(username)
                .password(password)
                .url(url + "?useSSL=false&serverTimezone=Asia/Shanghai")
                .driverClassName("com.mysql.cj.jdbc.Driver")
                .build();
    }

    @Bean
    @Profile("test")
    public DataSource testDataSource() {
        return DataSourceBuilder.create()
                .username(username)
                .password(password)
                .url(url + "?useSSL=false&serverTimezone=Asia/Shanghai")
                .driverClassName("com.mysql.cj.jdbc.Driver")
                .build();
    }

    @Bean
    @Profile("prod")
    public DataSource prodDataSource() {
        return DataSourceBuilder.create()
                .username(username)
                .password(password)
                .url(url + "?useSSL=true&serverTimezone=Asia/Shanghai")
                .driverClassName("com.mysql.cj.jdbc.Driver")
                .build();
    }
}

In actual development, different environments have different Apolloconfigurations Apollo, and the database connection configuration is written on it. There is no need for multiple codes for production and testing Bean, and you only need to load different Apolloconfigurations to establish a database connection.

ApolloIt is a distributed configuration center open sourced by Ctrip's framework department, which can centrally manage the configuration information of applications. ApolloThe main goal of is to enable applications to dynamically adjust their configuration at runtime without redeployment.

Apolloand solve the same problem - how to manage the configuration of different environments, but Springprovide more powerful functions, especially in large-scale and complex distributed systems. In addition, it also supports configuration version control, audit logs, rights management and other functions, providing a comprehensive solution for configuration management.ProfileApolloApollo

2.2 Understand the working principle and purpose of @Profile

Let's use the library opening hours example, and use the configuration to control the opening hours. Spring Profiles 

The whole code is as follows:

First, we need a class representing the opening hours : LibraryOpeningHours

package com.example.demo.bean;

public class LibraryOpeningHours {
    private final String openTime;
    private final String closeTime;

    public LibraryOpeningHours(String openTime, String closeTime) {
        this.openTime = openTime;
        this.closeTime = closeTime;
    }

    @Override
    public String toString() {
        return "LibraryOpeningHours{" +
                "openTime='" + openTime + '\'' +
                ", closeTime='" + closeTime + '\'' +
                '}';
    }
}

Then, we need a class to hold this open time: Library 

package com.example.demo.bean;

public class Library {
    private final LibraryOpeningHours openingHours;

    public Library(LibraryOpeningHours openingHours) {
        this.openingHours = openingHours;
    }

    public void displayOpeningHours() {
        System.out.println("Library opening hours: " + openingHours);
    }
}

Next, we need to define two different configurations, representing the opening hours on weekdays and weekends:

package com.example.demo.configuration;

import com.example.demo.bean.Library;
import com.example.demo.bean.LibraryOpeningHours;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@Profile("weekday")
public class WeekdayLibraryConfiguration {
    @Bean
    public LibraryOpeningHours weekdayOpeningHours() {
        return new LibraryOpeningHours("8:00 AM", "6:00 PM");
    }

    @Bean
    public Library library(LibraryOpeningHours openingHours) {
        return new Library(openingHours);
    }
}

Opening hours on weekdays are morning 8and evening 6.

package com.example.demo.configuration;

import com.example.demo.bean.Library;
import com.example.demo.bean.LibraryOpeningHours;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@Profile("weekend")
public class WeekendLibraryConfiguration {
    @Bean
    public LibraryOpeningHours weekendOpeningHours() {
        return new LibraryOpeningHours("10:00 AM", "4:00 PM");
    }

    @Bean
    public Library library(LibraryOpeningHours openingHours) {
        return new Library(openingHours);
    }
}

Opening hours on weekends are morning 10and afternoon 4.

Finally we run in the main program and change the opening hours of the library by selecting different : Profile 

package com.example.demo.application;

import com.example.demo.bean.Library;
import com.example.demo.configuration.WeekdayLibraryConfiguration;
import com.example.demo.configuration.WeekendLibraryConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class DemoApplication {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

        context.getEnvironment().setActiveProfiles("weekday");
        context.register(WeekdayLibraryConfiguration.class, WeekendLibraryConfiguration.class);
        context.refresh();

        Library library = context.getBean(Library.class);
        library.displayOpeningHours();
    }
}

Some friends here may have doubts, why do we need to have a method setActiveProfilesin the future ?registerrefresh

setActiveProfilesmethod is used to specify which ones Profileare active, and simply setting the active one Profiledoes not trigger Springthe container to instantiate the corresponding one bean.

registerThe method is to register the configuration class Springin the application context, it does not immediately create the declaration in the configuration class bean, and beanthe creation process of these is refreshcarried out in the phase of the context. At this stage, Springthe container will read all configuration classes and @Beanparse the annotated methods in the configuration classes before creating and initializing them bean.

So, if you refreshtry to get one of the configuration classes before calling the method bean, you will not find it, because it beanmay not have been created yet. Only after the context is refreshed (that is, the method is called refresh), all beanwill be created and registered in Springthe container, and then they can be obtained through the context bean.

operation result:

image.png

If we choose , the library will be open on weekdays; if we choose , the library will be open on weekends. "weekday" Profile "weekend" Profile

Note: registermethods, @Component, @Bean, @Importare all ways to register Beanto Springthe container, they have different applicable scenarios and working methods:

  • register method : This method is used to register one or more configuration classes (that is, classes marked with @Configurationannotations) Springinto ApplicationContext. This process is to add the meta information of the configuration class to the context, but it does not instantiate it immediately Bean. The actual Beaninstantiation process will happen at ApplicationContextrefresh time (that is, refreshwhen the method is called), and this process may be affected by conditional assembly annotations such as @Profile. @Conditional

  • @Component : This is a generic annotation that can be used to mark any class as Springa component. If an annotated @Componentclass is Springunder the component scanning path, it Springwill be automatically created Beanand added to the container.

  • @Bean : This annotation is usually used on methods in configuration classes. Annotated @Beanmethods indicate how to instantiate, configure, and initialize a new Beanobject. Spring IoCThe container will be responsible for calling these methods at the appropriate time (during ApplicationContextthe refresh phase) to create Beanthe instance.

  • @Import : This annotation is used to import other configuration classes in a configuration class. By using this annotation, we can Beandisperse the definition of config into multiple configuration classes for better modularity and organization.

In Springthe framework, the above methods and annotations work together to provide powerful dependency injection and management capabilities, and support us to create complex and modular applications.

In Springthe framework, refreshmethods are used to start Springthe life cycle of the application context, which dominates the resolution, creation and initialization process ApplicationContextin the framework Bean. Here are refreshthe main steps of the method in action:

  1. Read all registered configuration classes: refreshThe method first scans ApplicationContextall registered configuration classes (usually @Configurationclasses marked with annotations). It looks for all @Beanannotated methods in these configuration classes.

  2. Parsing @Beanmethod: For each @Beanmethod, how to create and configure the corresponding method will be determined Springbased on the method's signature, return type, and possible other annotations (such as @Scope, @Lazy, etc.) .@ProfileBean

  3. BeanCreation and dependency injection: Based on the information obtained by parsing, Spring IoCthe container will create Beaninstances on demand. After instantiation Bean, this dependency Springis also processed , i.e. it will automatically inject the other that this depends on into its properties or constructor parameters.BeanBeanBean

  4. Initialization: If the interface Beanis implemented InitializingBeanor annotated methods are defined , these initialization methods will be called @PostConstructafter all dependency injection is complete .Spring

Therefore, after calling refreshthe method, we can be sure that everything defined in the configuration class Beanhas been correctly parsed, created, and registered in Springthe ApplicationContext. This includes Beaninstantiation, dependency injection, and possibly initialization.

The above steps are not necessarily performed sequentially. In fact, some optimizations and adjustments may be made Springby IoCthe container when processing these steps. The specific processing order may be affected by the following factors:

  • Bean dependencies : If one Bean Adepends on the other Bean B, it Springneeds to be created and initialized Bean Bbefore it can be created Bean A. This may result in Beana different order of creation than the order in which they were defined in the configuration class.

  • Bean lifecycle and scope : For example, if one Beanis a singleton (the default scope), then it will usually be created when the container starts. But if it's prototypical, it's only created when it's needed.

  • Conditional annotations : Conditional annotations like @Profileand may also affect the creation of . If the condition is not met, the corresponding one will not be created.@ConditionalBeanBean

Although in general, it is true that the life cycle will be processed according to the steps of Spring"reading configuration class-parsing @Beanmethod-creating -dependency injection-initialization" , the specific processing process may be affected by the above-mentioned The influence of various factors.BeanBean

Keep in mind the library opening hours example, many examples will follow around this example.

2.3 Why is there @Profile? Doesn't the application have configuration files for various environments?

application-dev.yml, application-test.ymland these configuration files can be used to specify different configuration parameters in different environments, such as database connection strings, service addresses, and so on. application-prod.yml 

Compared with applicationconfiguration files, @Profile annotations provide a higher level of environmental difference control in the application, which can control the entire or configuration class, not just configuration parameters. With this , we can make the entire or configuration class only take effect in a specific environment, which means that we can use completely different implementations or different configuration methods according to the environment. Spring  Bean  @Profile Bean  Bean 

To give an example, consider a mail service, we may use a simulated mail service in the development environment, just simply print out the content of the mail, and in the production environment we may need to use an actual mail service. We can create two , one with annotations and one with annotations. In this way, we can choose which mail service to use according to the environment without changing other codes. Bean @Profile("dev")  @Profile("prod") 

In general, application-{profile}.yml files and annotations are provided environmental difference management tools, which are used to manage configuration parameters and /or configuration classes respectively, and can be selected according to the specific needs of the application. @Profile  Spring  Bean

2.4 How to determine the active Profile in Spring?

SpringThe current activity can be specified in a number of ways Profile, in order of priority from high to low as follows:

  1. ConfigurableEnvironment.setActiveProfiles
  2. JVM's -Dspring.profiles.active parameter or environment variable SPRING_PROFILES_ACTIVE (available only for Spring Boot)
  3. SpringApplicationBuilder.profiles (available only for Spring Boot)
  4. SpringApplication.setDefaultProperties (available only for Spring Boot)
  5. Profile property spring.profiles.active

If there are configurations above, the configuration with higher priority will override the configuration with lower priority.

Let's take a look at them separately. Here we take 2.1the example of the section as the basis, only modify the main program, and do not put other repeated codes:

1.ConfigurableEnvironment.setActiveProfiles:

This is Springa framework API, so it can be Spring Bootused not only in , but also in native applications. We can set the activity Springthrough the obtained environment .ApplicationContextProfile

package com.example.demo.application;

import com.example.demo.configuration.WeekdayLibraryConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class DemoApplication {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.getEnvironment().setActiveProfiles("weekday");
        context.register(WeekdayLibraryConfiguration.class);
        context.refresh();
        // 下面这行调试使用
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
    }
}

operation result:

image.png

Here you can see WeekdayLibraryConfigurationthat it has been created, but WeekendLibraryConfigurationnot created.

2. JVM's -Dspring.profiles.active parameter and environment variable SPRING_PROFILES_ACTIVE (available only for Spring Boot)

Both of these are features, and there is no built-in support in Spring Bootnative applications. The main program we use here demonstratesSpringSpring Boot

  • Configure -Dspring.profiles.active parameter

For example, when starting an Spring Bootapplication, we can use the following command:

-Dspring.profiles.active=weekend

In this example, -Dspring.profiles.active=weekendit is the part that sets the system properties, indicating that only those marked as @Profile("weekend")will Beanbe created and used.

Let's use 2.1the example in the above section to modify the code and set the system properties

image.png

Or configure like this

image.png

Spring BootMain program:

package com.example.demo.application;

import com.example.demo.configuration.WeekendLibraryConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan("com.example")
public class DemoApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        WeekendLibraryConfiguration bean = context.getBean(WeekendLibraryConfiguration.class);
        System.out.println(bean.weekendOpeningHours());
    }
}

ProfileThere are only for- weekendpurposes here bean, but Profilefor weekday-purposes beanhave not been created, you can debug and verify by yourself.

The result of the operation is as follows:

image.png

  • Configure the environment variable SPRING_PROFILES_ACTIVE

We can set it in the environment variables of the operating system SPRING_PROFILES_ACTIVE.

In Unix/Linuxthe system, we can use commands to set environment variables before starting the application export. For example:

export SPRING_PROFILES_ACTIVE=dev
java -jar myapp.jar

In Windowsthe system, we can use setthe command to set environment variables:

set SPRING_PROFILES_ACTIVE=dev
java -jar myapp.jar

3. SpringApplicationBuilder.profiles (available only for Spring Boot)

package com.example.demo.application;

import com.example.demo.configuration.WeekendLibraryConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan("com.example")
public class DemoApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = new SpringApplicationBuilder(DemoApplication.class)
                .profiles("weekend")
                .run(args);

        WeekendLibraryConfiguration bean = context.getBean(WeekendLibraryConfiguration.class);
        System.out.println(bean.weekendOpeningHours());
    }
}

operation result:

image.png

4. SpringApplication.setDefaultProperties (available only for Spring Boot)

SpringApplication.setDefaultPropertiesThe method is used to set default properties, which can set a series of default properties, including spring.profiles.activeproperties. When spring.profiles.activea property is set, Springit is considered to be currently active Profile.

Main program:

package com.example.demo.application;

import com.example.demo.configuration.WeekdayLibraryConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;

import javax.annotation.Resource;
import java.util.Properties;

@SpringBootApplication
@ComponentScan(basePackages = "com.example.demo")
public class DemoApplication {
    @Resource
    private WeekdayLibraryConfiguration weekdayLibraryConfiguration;

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(DemoApplication.class);
        Properties props = new Properties();
        props.put("spring.profiles.active", "weekday");
        application.setDefaultProperties(props);
        ConfigurableApplicationContext context = application.run(args);
        // 验证当前激活Profile
        String[] activeProfiles = context.getEnvironment().getActiveProfiles();
        for (String profile : activeProfiles) {
            System.out.println("当前活动Profile:" + profile);
        }
    }
}

operation result:

image.png

5. Configuration file property spring.profiles.active configuration file

In application.propertiesor application.ymlfiles, we can set spring.profiles.activeproperties.

For example, in application.propertiesthe file we can add the following lines:

spring.profiles.active=weekday

In application.ymlthe file we can add the following:

spring:
  profiles:
    active: weekday
 

3. @Conditional

3.1 @Conditional annotation and its use

@Conditionalis Spring 4.0a core annotation introduced in to Beanassociate the creation of a with a specific condition. This feature Spring Bootis heavily used in , to create and assemble when certain conditions are met Bean.

@ConditionalThe annotation accepts one or more classes that implement Conditionthe interface as parameters. ConditionThe interface has only one matchesmethod named , which needs to return a boolean value to indicate whether the condition is met or not. If matchesthe method returns true, Springthis will @Conditionalbe created and assembled Bean; if it returns false, this will not be created and assembled Bean.

@ConditionalThe application of annotations is very flexible. It can be used to mark classes that use annotations directly or indirectly @Component, including but not limited to @Configurationclasses. Additionally, it can be used to mark @Beanmethods, or as a meta-annotation to compose custom annotations.

If a @Configurationclass is marked with an annotation, all methods @Conditionalassociated with that class , as well as any and annotations, are also subject to the same conditions. This means that these methods and annotations will only be processed if the condition of the method is met.@Bean@Import@ComponentScan@Conditional

Overall, @Conditionalprovides a powerful mechanism that can be used to control Beanthe creation and assembly based on certain conditions. By using it, we can more flexibly control Springthe configuration of the application in order to adapt to various operating environments and requirements.

3.2 Use @Conditional to implement conditional assembly

Suppose we have a library application where we have two classes, Librarianand Librarywe want the class to be created only if it exists . At this time, it cannot be realized, because it is impossible to check whether the other exists. Librarian Library @Profile@Profile  bean 

The whole code is as follows:

First, we create Librarianthe class:

package com.example.demo.bean;

public class Librarian {
}

create Libraryclass

package com.example.demo.bean;

public class Library {
    // Library class
    private final String libraryName;

    public Library(String libraryName) {
        this.libraryName = libraryName;
    }

    public void showLibraryName() {
        System.out.println("Library name: " + libraryName);
    }
}

Next, we create a conditional class to check for the existence of the definition of Librarian:bean

package com.example.demo.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class LibrarianCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return context.getBeanFactory().containsBeanDefinition("librarian");
    }
}

Here a conditional class named is defined LibrarianCondition, implements Conditionthe interface and overrides matchesthe method. In matchesthe method, a check is made to see if a definition named " " Springexists in the application context .librarianBean

Then, we need to create a configuration class that defines a condition that will only be created if Librarian beanit exists :Library bean

package com.example.demo.configuration; 

import com.example.demo.bean.Librarian; 
import com.example.demo.bean.Library; 
import com.example.demo.condition.LibrarianCondition; 
import org.springframework.context.annotation .Bean; 
import org.springframework.context.annotation.Conditional; 
import org.springframework.context.annotation.Configuration; 

@Configuration 
public class LibraryConfiguration { 

    /** 
     * Change the existence of Librarian bean by commenting or uncommenting librarian method , so as to observe the impact on the creation of the Library bean. 
     * 
     * @return 
     */ 
    @Bean 
    public Librarian librarian() { 
        return new Librarian(); 
    } 

    @Bean
    @Conditional(LibrarianCondition.class)
    public Library library() {
        return new Library("The Great Library");
    }
}

In the above code, an annotation Library Beanis added to the created method @Conditional(LibrarianCondition.class), specifying that it will be created only when it returns . We can then comment or uncomment methods to change the state of existence to observe its effect on creation. LibrarianCondition  true Library bean  librarian()  Librarian bean  Library bean 

Finally, in the main program, we initialize Springthe context and Libraryget bean:

package com.example.demo;

import com.example.demo.configuration.LibraryConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class DemoApplication {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(LibraryConfiguration.class);
        context.refresh();

        System.out.println("IOC容器是否有librarian?" + context.containsBean("librarian"));
        System.out.println("IOC容器是否有library?" + context.containsBean("library"));
    }
}

In this example, Librarythe will beanonly be created if Librarianthe also beanexists.

When Librarianpresent, the output is:

image.png

When Librariannot present, the output is:

image.png

3.2 Application of @Conditional in Spring Boot

Spring Boot It is used in many places to achieve conditional configuration, let's take a look at it separately. @Conditional 

3.2.1 @ConditionalOnBean 和 @ConditionalOnMissingBean

@ConditionalOnBean and are a pair of conditional annotations provided for conditional creation , which can check whether a specific container exists . If such is present (or absent) , then the corresponding configuration will be enabled (or ignored). @ConditionalOnMissingBean  Spring Boot  Spring Beans Spring beanbean

Specifically:

  • @ConditionalOnBean : When the specified type exists in the container , the currently annotated one will be created. Spring  Bean  Bean 

  • @ConditionalOnMissingBean : When the specified type does not exist in the container , the currently annotated one will be created. Spring  Bean  Bean 

Here we select @ConditionalOnBeanannotations for explanation. Modify our configuration class just now, we delete Conditionthe condition judgment class that implements the interface LibrarianCondition, and @Conditional change it to@ConditionalOnBean

package com.example.demo.configuration; 

import com.example.demo.bean.Librarian; 
import com.example.demo.bean.Library; 
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; 
import org.springframework.context .annotation.Bean; 
import org.springframework.context.annotation.Configuration; 

@Configuration 
public class LibraryConfiguration { 

    /** 
     * By commenting or uncommenting the librarian method, change the existence status of the Librarian bean, so as to observe the impact on the creation of the Library bean . 
     * 
     * @return 
     */ 
    @Bean 
    public Librarian librarian() { 
        return new Librarian(); 
    } 

    @Bean 
    @ConditionalOnBean(Librarian. class)
    public Library library() {
        return new Library("The Great Library");
    }
}

As shown below:

image.png

Next, change the main program Spring Bootto restart

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class);

        System.out.println("IOC容器是否有librarian?" + context.containsBean("librarian"));
        System.out.println("IOC容器是否有library?" + context.containsBean("library"));
    }
}

The result of the operation is as follows:

When Librarianpresent, the output is:

image.png

When Librariannot present, the output is:

image.png

Some people may wonder, is it possible to register later, so that this condition will be considered Librarian non -existent?Library Librarian

The answer is no. Spring When processing a class, all methods are pre-resolved, all definition information is collected , and these are instantiated according to dependencies . @Configuration  @Bean  Bean  Bean 

If it Librarian is not written in the configuration class, but modified by @Componentannotations, will the condition be judged as non-existent due to the order problem?

Even if the class definition is annotated and registered to the container through component scanning, dependencies can still be handled correctly, and it depends on the definition, not the instantiation. Librarian  @Component  Spring Spring  Bean  Bean 

When the container starts, it first scans all definitions and collects information, including those defined by class methods, as well as those registered through annotations such as , , and component scanning mechanisms. Spring  Bean  @Configuration  @Bean  @Component@Service@Repository

When the conditional judgment of or is executed , you already have a global vision and know all the definitions. Therefore, even if one is defined through annotations and registered by the component scanning mechanism, the judgment will not fail due to order problems. Similarly, conditional judgments will not have this problem. @ConditionalOnBean  @ConditionalOnMissingBean Spring  Bean  Bean  @Component @Conditional

In general, Spring it provides powerful dependency management and automatic assembly functions, which can ensure the judgment of various conditions, no matter how they are defined and registered. Bean  Bean 

3.2.2 @ConditionalOnProperty

This annotation indicates that only when one or more of the given properties have a specific value, only create with the annotation Bean.

@ConditionalOnPropertyIt is Spring Bootan annotation in , which is used to check whether a certain configuration property exists, or whether it has a specific value. Only when the conditions are met, the class or method marked by the annotation will be created or executed. This annotation can be used to enable or disable certain functions in different environments, or to adjust the behavior of functions.

In actual business, we may decide whether to enable a certain Beanfunction or not according to different configurations. Take the following code as an example:

@Configuration
public class MyConfiguration {

    @Bean
    @ConditionalOnProperty(name = "my.feature.enabled", havingValue = "true", matchIfMissing = true)
    public MyFeature myFeature() {
        return new MyFeature();
    }
}

In this example, MyFeaturethis will only be created if the value of the property Beanin the configuration file is . If there is no such property in the configuration file , it will still be created because of the value of the property .my.feature.enabledtruemy.feature.enabledmatchIfMissingtrueMyFeatureBean

In this way, we can flexibly enable or disable a certain function by modifying the configuration file without modifying the code. For example, we may have some features that behave differently in the development environment and the production environment, or some optional features that can be turned on or off according to needs. These functions can also be considered for use in actual development Apollo. You only need to configure the corresponding environment Apolloto obtain the corresponding attribute values, so as to realize different functions.

3.2.3 @ConditionalOnClass 和 @ConditionalOnMissingClass

These two annotations can be checked Classpathfor the presence or absence of a particular class.

For example, we may have a service that requires Classpatha certain class to work properly, we can configure it like this:

@Service
@ConditionalOnClass(name = "com.example.SomeClass")
public class MyService {
    // ...
}

In this example, if com.example.SomeClassexists Classpathin , MyServiceit will be created and added Springto ApplicationContext. If the class does not exist, it MyServicewill not be created.

Similarly, we can also use annotations to create a certain class when it does not exist , just replace the above code with . @ConditionalOnMissingClass ClasspathBean @ConditionalOnClass  @ConditionalOnMissingClass 

This 2annotation is rarely used in actual business development, because it is mainly used to deal with some general logic of the underlying framework or library. But it is really useful in the development of frameworks or libraries, so that the framework or library can be more flexibly adapted to different usage environments and configurations.

For example, in , many auto-configuration classes use conditional assembly. For example, this class is responsible for automatically configuring the database connection pool. It uses annotations to determine whether there is a related database driver class in the database. Only when there is a related database driver class, it will be automatically configured. Spring Boot  DataSourceAutoConfiguration  @ConditionalOnClass  Classpath 

For another example, we may have developed a powerful logging library that can log to the database, but if the user's project does not include a driver, then our library should degenerate to only log to the file. At this time, it can be used to check whether there is a driver, if it exists, create a log record to the database , otherwise create a log record to a file . JDBC  @ConditionalOnClass  JDBC  Bean Bean

Click to follow and learn about Huawei Cloud's fresh technologies for the first time~

Clarification about MyBatis-Flex plagiarizing MyBatis-Plus Arc browser officially released 1.0, claiming to be a substitute for Chrome OpenAI officially launched Android version ChatGPT VS Code optimized name obfuscation compression, reduced built-in JS by 20%! LK-99: The first room temperature and pressure superconductor? Musk "purchased for zero yuan" and robbed the @x Twitter account. The Python Steering Committee plans to accept the PEP 703 proposal, making the global interpreter lock optional . The number of visits to the system's open source and free packet capture software Stack Overflow has dropped significantly, and Musk said it has been replaced by LLM
{{o.name}}
{{m.name}}

Guess you like

Origin my.oschina.net/u/4526289/blog/10092230