Article directory
1. Conditional assembly
1.1 Understand conditional assembly and its important role in Spring
In Spring
the framework, conditional assembly ( Conditional Configuration
) is a very important feature, which allows developers to dynamically Bean
register or create objects based on satisfied conditions. This allows you to create different instances based on different environments or configurations Bean
, which is very useful for creating configurable and modular applications.
Spring
A series of annotations are provided to implement conditional assembly, including:
-
@Profile : This is
Spring
the annotation. This annotation means that only when a specific profileProfile
is activated, an profile with this annotation will be createdBean
. We can set the activation profile in the application's configuration fileProfile
. -
@Conditional : This is
Spring
an annotation that accepts one or moreCondition
classes that need to implementCondition
the interface and override itsmatches
methods. Only when all methods ofCondition
the class return will the annotated ones be created.matches
true
@Conditional
Bean
The following annotations are Spring Boot
provided and are mainly used for automatic configuration functions:
-
@ConditionalOnProperty : This annotation indicates that an annotated property will only be created if one or more given properties have a specific value
Bean
. -
@ConditionalOnClass and @ConditionalOnMissingClass : These two annotations indicate that only
Classpath
when there (or not) a specific class is created with this annotationBean
. -
@ConditionalOnBean and @ConditionalOnMissingBean : These two annotations mean that only
Spring ApplicationContext
when there is (or is not) specificBean
, the annotation will be createdBean
.
By combining these annotations, developers can implement complex conditional assembly logic and flexibly control Spring
application configuration and behavior.
2. @Profile
In Spring
, Profile
it is used to address the need for different configurations in different environments. It can assemble applications according to the requirements of specific environments. For example, we may have one set of configurations for the development environment and another set of configurations for the production environment, Profile
which can be used to determine which environment is active at runtime and thus decide which ones to register bean
.
2.1 Practical application scenarios based on @Profile
For example, we might need to use a different database or a different service endpoint.
Here we can take database configuration as an example. The databases in the development environment, test environment and production environment may be different. We can @Profile
configure the databases of these environments respectively through annotations.
@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 Apollo
configurations. Apollo
The database connection configuration is written on it. There is no need for multiple codes for production and testing Bean
. You only need to load different Apollo
configurations to establish a database connection.
Apollo
It is a distributed configuration center open sourced by Ctrip Framework Department, which can centrally manage the configuration information of applications.Apollo
The main goal is to enable applications to dynamically adjust their configuration at runtime without the need for redeployment.
Apollo
and solve the same problem - how to manage the configuration of different environments, butSpring
provide more powerful functions, especially in large-scale and complex distributed systems. In addition, it also supports configuration version control, audit logs, permission management and other functions, providing a comprehensive solution for configuration management.Profile
Apollo
Apollo
2.2 Understand the working principle and purpose of @Profile
Let's use the library opening hours example and use Spring Profiles
to control the configuration of opening hours.
The entire code is as follows:
First, we need a class that represents 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 Library
class to hold this opening time:
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 8
and 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 10
morning and afternoon 4
.
Finally we run in the main program and Profile
change the library opening hours by selecting a different :
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 be wondering, why is there setActiveProfiles
still a method in the future?register
refresh
setActiveProfiles
The method is used to specify which ones Profile
are active, and just setting the active ones Profile
does not trigger Spring
the container to instantiate the corresponding ones bean
.
register
The method is to register the configuration class into Spring
the application context. It does not immediately create the configuration class declared in the application context bean
. These creation processes are performed bean
in the context phase. refresh
At this stage, Spring
the container will read all configuration classes and @Bean
parse the annotated methods in the configuration classes before creating and initializing them bean
.
So, if you refresh
try to get one of the configuration classes before calling the method bean
, you won't be able to find it because it bean
may not have been created yet. Only after the context is refreshed (that is, the method is called refresh
) are all bean
created and registered in Spring
the container, and then can they be obtained through the context bean
.
operation result:
If we choose "weekday" Profile
, the library's opening hours will be on weekdays; if we choose "weekend" Profile
, the library's opening hours will be on weekends.
Note:
register
Methods, @Component
, @Bean
, @Import
are all ways to register Bean
to Spring
the 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
@Configuration
annotations)Spring
intoApplicationContext
. This process adds the metainformation of the configuration class to the context, but it is not instantiated immediatelyBean
. The actualBean
instantiation process will occur atApplicationContext
refresh time (that is,refresh
when the method is called), and this process may be affected by conditional assembly annotations such as@Profile
.@Conditional
-
@Component : This is a general annotation that can be used to mark any class as
Spring
a component. If an annotated@Component
class isSpring
in the component scan path,Spring
the class will be automatically createdBean
and added to the container. -
@Bean : This annotation is usually used on methods in configuration classes. The annotated
@Bean
methods represent how to instantiate, configure, and initialize a newBean
object.Spring IoC
The container will be responsible for calling these methods at the appropriate time (duringApplicationContext
the refresh phase) to createBean
the instance. -
@Import : This annotation is used to import other configuration classes in a configuration class. By using this annotation, we can
Bean
spread the definition across multiple configuration classes for better modularity and organization.
In Spring
the framework, the above methods and annotations work together to provide powerful dependency injection and management capabilities, allowing us to create complex, modular applications.
In Spring
the framework, refresh
methods are used to start Spring
the life cycle of the application context, which dominates ApplicationContext
the Bean
parsing, creation, and initialization processes. The following are refresh
the main steps of the method in practice:
-
Read all registered configuration classes:
refresh
The method first scansApplicationContext
all registered configuration classes (usually@Configuration
classes marked with annotations).@Bean
It will look for all annotated methods in these configuration classes . -
Parsing
@Bean
method: For each@Bean
method, how to create and configure the corresponding method will be determinedSpring
based on the method's signature, return type, and possible other annotations (such as@Scope
,@Lazy
, etc.) .@Profile
Bean
-
Bean
Creation and dependency injection: Based on the parsed information,Spring IoC
the container will createBean
instances on demand. After instantiationBean
, this dependencySpring
will also be processed , that is, it will automatically inject other dependencies into its properties or constructor parameters.Bean
Bean
Bean
-
Initialization: If the interface
Bean
is implementedInitializingBean
or annotated methods are defined , these initialization methods will be called@PostConstruct
after all dependency injection is completed .Spring
Therefore, after calling refresh
the method, we can be sure that everything defined in the configuration class Bean
has been correctly parsed, created, and registered in the Spring
configuration class ApplicationContext
. This includes Bean
instantiation, dependency injection, and possibly initialization.
The above steps are not necessarily performed in order. In fact, Spring
the IoC
container may make some optimizations and adjustments when processing these steps. The specific processing order may be affected by the following factors:
-
Bean dependencies : If one
Bean A
depends on anotherBean B
, itSpring
needs to be created and initializedBean B
before it can be createdBean A
. This may result inBean
the objects being created in a different order than the order in which they are defined in the configuration class. -
Bean lifecycle and scope : For example, if a bean
Bean
is singleton (default scope), then it will usually be created when the container starts. But if it is prototyped, it will only be created when it is needed. -
Conditional annotations : Conditional annotations like
@Profile
and may also affect the creation of . If the condition is not met, the corresponding one will not be created.@Conditional
Bean
Bean
Although in general, the life cycle will be processed according to the steps of Spring
"reading configuration class - parsing @Bean
method - creation - dependency injection - initialization" , the specific processing process may be affected by the above mentioned The influence of various factors.Bean
Bean
Please remember this example of library opening hours. There are many examples that follow this example.
2.3 Why is there @Profile? Doesn’t application have configuration files for various environments?
application-dev.yml
, application-test.yml
and application-prod.yml
These configuration files can be used to specify different configuration parameters in different environments, such as database connection strings, service addresses, etc.
Compared with application
configuration files, @Profile
annotations Spring
provide a higher level of environmental differentiation control in applications. They can control the entire Bean
or configuration class, not just the configuration parameters. With this @Profile
, we can make the entire Bean
or configuration class only effective in a specific environment, which means we can use completely different Bean
implementations or different configuration methods depending on the environment.
For example, consider an email service. We may use a simulated email service in the development environment and simply print out the email content, while in the production environment we may need to use an actual email service. We can create two Bean
, one @Profile("dev")
annotated with and one @Profile("prod")
annotated with . In this way, we can choose which mail service to use according to the environment without changing other code.
In general, application-{profile}.yml
files and @Profile
annotations are Spring
environment difference management tools provided by . They are used to manage configuration parameters and Bean
/or configuration classes respectively, and can be selected according to the specific needs of the application.
2.4 How to determine the active Profile in Spring?
Spring
The current activity can be specified in a variety of ways Profile
, with priority ordering from high to low as follows:
- ConfigurableEnvironment.setActiveProfiles
- JVM's -Dspring.profiles.active parameter or environment variable SPRING_PROFILES_ACTIVE (only available with Spring Boot)
- SpringApplicationBuilder.profiles (available only with Spring Boot)
- SpringApplication.setDefaultProperties (available only with Spring Boot)
- Profile property spring.profiles.active
If there are configurations above, the one with higher priority will overwrite the configuration with lower priority.
Let's take a look at them separately. Here we use 2.1
the example in the section as the basis. We only modify the main program and do not put other repeated codes:
- ConfigurableEnvironment.setActiveProfiles:
This is Spring
a framework API
, so it can be Spring Boot
used not only in APP, but also in native applications. We can set the activity Spring
through the obtained environment .ApplicationContext
Profile
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:
Here you can see WeekdayLibraryConfiguration
that it has been created, but WeekendLibraryConfiguration
not created.
- JVM's -Dspring.profiles.active parameter and environment variable SPRING_PROFILES_ACTIVE (only available with Spring Boot)
Both of these are features, and there is no built-in support in Spring Boot
native applications. The main program we use here demonstratesSpring
Spring Boot
- Configuration-Dspring.profiles.active parameter
For example, when launching an Spring Boot
application, we can use the following command:
-Dspring.profiles.active=weekend
In this example, -Dspring.profiles.active=weekend
it is the part that sets the system properties, indicating that only those marked @Profile("weekend")
will Bean
be created and used.
Let’s use 2.1
the example in the above section to modify the code and set the system properties.
Or configure it like this
Spring Boot
Main 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());
}
}
Profile
There is only Wei weekend
's here bean
, but Profile
Wei weekday
's bean
has not been created. You can debug and verify it by yourself.
The running results are as follows:
- Configure the environment variable SPRING_PROFILES_ACTIVE
We can set it in the environment variables of the operating system SPRING_PROFILES_ACTIVE
.
In Unix/Linux
the 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 Windows
the system, we can use set
the command to set environment variables:
set SPRING_PROFILES_ACTIVE=dev
java -jar myapp.jar
- SpringApplicationBuilder.profiles (available only with 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:
- SpringApplication.setDefaultProperties (available only with Spring Boot)
SpringApplication.setDefaultProperties
The method is used to set default properties. It can set a series of default properties, including spring.profiles.active
properties. When spring.profiles.active
a property is set, Spring
it is considered the current activation 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:
- Profile property spring.profiles.active profile
In application.properties
or application.yml
files we can set spring.profiles.active
properties.
For example, in application.properties
the file we can add the following lines:
spring.profiles.active=weekday
In application.yml
the file we can add the following:
spring:
profiles:
active: weekday
3. @Conditional
3.1 @Conditional annotation and its uses
@Conditional
is Spring 4.0
a core annotation introduced in , used to Bean
associate the creation of with specific conditions. This feature Spring Boot
is used a lot in order to create and assemble when specific conditions are met Bean
.
@Conditional
The annotation accepts one or more classes that implement Condition
the interface as parameters. Condition
The interface has only one matches
method named which is required to return a boolean value to indicate whether the condition is met. If matches
the method returns ,true
the marked as will be created and assembled ; if it returns , this will not be created and assembled .Spring
@Conditional
Bean
false
Bean
@Conditional
The 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 @Configuration
classes. In addition, it can be used to mark @Bean
methods, or as meta-annotations to compose custom annotations.
If a @Configuration
class is marked with an annotation, then all methods @Conditional
associated 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 when the conditions are met.@Bean
@Import
@ComponentScan
@Conditional
Overall, @Conditional
this provides a powerful mechanism for controlling Bean
creation and assembly based on specific conditions. By using it, we can more flexibly control Spring
the configuration of the application to adapt to various operating environments and needs.
3.2 Use @Conditional to implement conditional assembly
Suppose we have a library application with two classes, Librarian
and Library
, and we want Librarian
the class to be created only if it exists Library
. This @Profile
is impossible to achieve at this time, because @Profile
it is impossible to check whether other bean
exists.
The entire code is as follows:
First, we create Librarian
the class:
package com.example.demo.bean;
public class Librarian {
}
Create Library
class
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 Librarian
if bean
the definition exists:
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");
}
}
A condition class named is defined here LibrarianCondition
, implements Condition
the interface and overrides matches
the method. In matches
the method, it was checked Spring
whether a definition named " librarian
" exists in the application context Bean
.
Then, we need to create a configuration class that defines a condition that will only be created if Librarian bean
it 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 {
/**
* 通过注释或取消注释librarian方法,来改变Librarian bean的存在状态,从而观察对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, annotations Library Bean
are added to the created method @Conditional(LibrarianCondition.class)
, specifying that it will only be created when it LibrarianCondition
returns . We can then change the existence state of the by annotating or uncommenting the method to observe its impact on the creation.true
Library bean
librarian()
Librarian bean
Library bean
Finally, in the main program, we initialize Spring
the context and Library
obtain 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, will be created Library
only if bean
also exists.Librarian
bean
When Librarian
present, the output is:
When Librarian
it does not exist, the output is:
3.2 Application of @Conditional in Spring Boot
Spring Boot
is used in many places @Conditional
to implement conditional configuration, let's take a look at them separately.
3.2.1 @ConditionalOnBean 和 @ConditionalOnMissingBean
@ConditionalOnBean
and @ConditionalOnMissingBean
are Spring Boot
a pair of conditional annotations provided for conditional creation Spring Beans
, which can check Spring
whether a specific object exists in the container bean
. If such one exists (or does not exist) bean
, then the corresponding configuration will be enabled (or ignored).
Specifically:
-
@ConditionalOnBean : When
Spring
the specified type exists in the containerBean
, the currently annotatedBean
will be created. -
@ConditionalOnMissingBean : When
Spring
the specified type does not exist in the containerBean
, the currently annotatedBean
will be created.
Here we will select @ConditionalOnBean
annotations for explanation. Modify our configuration class just now. We delete Condition
the conditional 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 {
/**
* 通过注释或取消注释librarian方法,来改变Librarian bean的存在状态,从而观察对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:
Then, change the main program Spring Boot
to 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 running results are as follows:
When Librarian
present, the output is:
When Librarian
it does not exist, the output is:
Some people may wonder, is it possible to register later, causing this condition to be considered to Librarian
not exist?Library
Librarian
The answer is no. Spring
When processing @Configuration
a class, all @Bean
methods will be parsed in advance, all definition information will be collected , and then these will be instantiated Bean
according to dependencies .Bean
If it Librarian
is not written in the configuration class, but modified by @Component
annotations, will the condition be judged to not exist due to order issues?
Even if Librarian
the definition of the class is @Component
decorated with annotations and registered to Spring
the container through component scanning, Spring
the dependency can still be handled correctly, it depends on Bean
the definition of , not Bean
the instantiation of .
When Spring
the container starts, it will first scan all Bean
definitions and collect information, including those defined by @Configuration
class methods, as well as those registered through , , and other annotations and component scanning mechanisms.@Bean
@Component
@Service
@Repository
When executing the conditional judgment of @ConditionalOnBean
or @ConditionalOnMissingBean
, Spring
you already have a global view and know all Bean
the definitions of . Therefore, even if a Bean
is defined through @Component
annotations and registered by the component scanning mechanism, the judgment will not fail due to order issues. Similarly, @Conditional
conditional judgment does not have this problem.
In general, Spring
it provides powerful dependency management and automatic assembly functions, which can ensure Bean
the judgment of various conditions, no matter Bean
how it is defined and registered.
3.2.2 @ConditionalOnProperty
This annotation indicates that an object with this annotation will only be created if one or more of the given properties have a specific value Bean
.
@ConditionalOnProperty
It is Spring Boot
an annotation in the class that is used to check whether a certain configuration attribute exists or 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 turn on or off certain features in different environments, or adjust the behavior of features.
In actual business, we may decide whether to enable a certain Bean
function or functions based on 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, MyFeature
this will only be created if the value of the property Bean
in the configuration file is . If this attribute does not exist in the configuration file , it will still be created because the attribute's value is .my.feature.enabled
true
my.feature.enabled
matchIfMissing
true
MyFeature
Bean
In this way, we can flexibly turn on or off a function by modifying the configuration file without modifying the code. For example, we might have features that behave differently in development and production environments, or optional features that can be turned on or off based on demand. These functions can also be considered for use in actual development Apollo
. You only need to configure the corresponding environment Apollo
to obtain the corresponding attribute values to achieve different functions.
3.2.3 @ConditionalOnClass 和 @ConditionalOnMissingClass
These two annotations can check Classpath
whether a specific class exists or not.
For example, we may have a service that requires Classpath
a specific 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.SomeClass
it exists Classpath
in , MyService
it will be created and added Spring
to ApplicationContext
. If the class does not exist, it MyService
will not be created.
Similarly, we can also use the annotation to create @ConditionalOnMissingClass
a specific class if it does not exist , just replace the with in the above code .Classpath
Bean
@ConditionalOnClass
@ConditionalOnMissingClass
This 2
annotation is rarely used in actual business development, because it is mainly used to handle some common logic of the underlying framework or library. But it is indeed very useful in the development of frameworks or libraries, allowing the framework or library to be more flexibly adapted to different usage environments and configurations.
For example, in Spring Boot
, many automatic configuration classes use conditional assembly. For example DataSourceAutoConfiguration
, class, this class is responsible for automatically configuring the database connection pool. It uses @ConditionalOnClass
annotations to determine Classpath
whether there is a relevant database driver class in the class. Automatic configuration will only occur when a relevant database driver class exists.
For another example, we may have developed a powerful logging library that can log to a database, but if the user's project does not include a driver, then JDBC
our library should degrade to only log to a file. At this time, you can use @ConditionalOnClass
to check whether JDBC
a driver exists. If it exists, create one that records logs to the database Bean
. Otherwise, create one that records logs to a file Bean
.
Welcome to the one-click triple connection~
If you have any questions, please leave a message, let's discuss and learn together
----------------------Talk is cheap, show me the code----- ------------------