This is the 31st day of my participation in the August Text Challenge.More challenges in August

1 Understanding Spring Boot automatic configuration

The Spring framework provides several ways to configure a Bean object,XML configuration, annotation configuration, and JavaConfig configuration classes. As Spring projects add functionality, the configuration gets bigger and harder to manage. Therefore, automatic configuration is adopted in Spring Boot to solve the problem of excessive configuration management in the Spring framework.

1 the Java configuration

Solutions to simplify XML configuration in Spring include:

  • Component Scan: Spring automatically discovers beans created in the application context.

  • AutoWired: Spring automatically creates dependencies between beans.

  • Java code configuration beans are implemented in JavaConfig mode.

Use a custom configuration class for columns:

@Configuration
public class WebConfigurer implements WebMvcConfigurer {

    /** * to register interceptors, our own interceptors need to be registered here to take effect *@param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        / / column, such as
        // addPathPatterns("/**") intercepts all requests
        ExcludePathPatterns ("/login", "/register") indicate things other than login and registration
        registry.addInterceptor(this.getMyInterceptor()).addPathPatterns("/ * *").excludePathPatterns("/login"."/register");
    }
    
        @Bean
    public MyInterceptor getMyInterceptor(a) {
        return new MyInterceptor();
    }

    /** * used to configure static resources such as HTML, JS, CSS, etc., columns such as when using swagger document *@param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {}}Copy the code

The 1@Configuration annotation marks this class as Spring’s Configuration class.

2 Hand over the interceptor class to the Spring container for management via the @Bean annotation tag

2 conditional beans

Spring Boot can control Bean registration to the container depending on different conditions.

1 annotations @ Conditional

Conditional annotations can do different Bean object injection based on different conditions. Similar to state patterns in design patterns.

Common notes:

Conditions of annotation Conditions that
@ConditionalOnBean A Bean is instantiated only when an object exists in context
@ConditionalOnClass A Bean is instantiated only when the class is on the classpath
@ConditionalOnExpression A Bean is instantiated only when the expression is True
@ConditionalOnMissingBean A Bean is instantiated only when there is no object in the context
@ConditionalOnMissingClass A Bean is instantiated when a class does not exist on the classpath
@ConditionalOnNotWebApplication A Bean is instantiated only if it is not a Web application

Conditional annotations use case columns

Goal:

The target Bean object is created when the password configuration item exists in application.properties and the value is true.

password=123456
Copy the code

The custom class implements the Condition interface

public class MyController implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

        Environment environment = context.getEnvironment();
        if (environment.containsProperty("password")) {
            String password = environment.getProperty("password");
            System.out.println("Password = =" + password);
            return "123456".equals(password);
        }

        return false; }}Copy the code

ConditionContext, the first parameter, is a context interface. The source code is as follows

public interface ConditionContext {

	/** Returns the BeanDefinitionRegistry object for the Bean definition, which can be checked with BeanDefinitionRegistry */
	BeanDefinitionRegistry getRegistry(a);

	/ * * returns ConfigurableListableBeanFactory object, used to check whether B diamine, and check the Bean properties * /
	@Nullable
	ConfigurableListableBeanFactory getBeanFactory(a);

	/** Return Environment to check if the Environment variable exists and read its value */
	Environment getEnvironment(a);

	/** Read and check the resources loaded by the ResourceLoader it returns */
	ResourceLoader getResourceLoader(a);

	/** Returns a ClassLoader object to load and check if the class exists */
	@Nullable
	ClassLoader getClassLoader(a);

}
Copy the code

The second parameter AnnotatedTypeMetadata.

public interface AnnotatedTypeMetadata {
    MergedAnnotations getAnnotations(a);

    // Determine if the @bean annotated method has other specific annotations
    default boolean isAnnotated(String annotationName) {
        return this.getAnnotations().isPresent(annotationName);
    }

    @Nullable
    default Map<String, Object> getAnnotationAttributes(String annotationName) {
        return this.getAnnotationAttributes(annotationName, false);
    }

    @Nullable
    default Map<String, Object> getAnnotationAttributes(String annotationName, boolean classValuesAsString) {
        MergedAnnotation<Annotation> annotation = this.getAnnotations().get(annotationName, (Predicate)null, MergedAnnotationSelectors.firstDirectlyDeclared());
        return! annotation.isPresent() ?null : annotation.asAnnotationAttributes(Adapt.values(classValuesAsString, true));
    }

    @Nullable
    default MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName) {
        return this.getAllAnnotationAttributes(annotationName, false);
    }

    @Nullable
    default MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName, boolean classValuesAsString) {
        Adapt[] adaptations = Adapt.values(classValuesAsString, true);
        return (MultiValueMap)this.getAnnotations().stream(annotationName).filter(MergedAnnotationPredicates.unique(MergedAnnotation::getMetaTypes)).map(M ergedAnnotation::withNonMergedAttributes).collect(MergedAnnotationCollectors.toMultiValueMap((map) -> {return map.isEmpty() ? null: map; }, adaptations)); }}Copy the code

Spring4 deploys profiles for multiple environments using the ProfileCondition class

class ProfileCondition implements Condition {

	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
		if(attrs ! =null) {
			for (Object value : attrs.get("value")) {
				if (context.getEnvironment().acceptsProfiles(Profiles.of((String[]) value))) {
					return true; }}return false;
		}
		return true; }}Copy the code

3 ConditionalConfig

Use the @conditionnal annotation method to specify conditions in value. The Bean is instantiated only when the Spring container meets the criteria, otherwise the Bean is not registered.

4 Combination notes

A composite annotation is a combination of existing annotations to produce a new annotation. Using this new annotation is equivalent to using all the annotations in the composite annotation.

Such as the @spring BootApplication annotation on the boot class.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
    ...
Copy the code

3 Spring Boot Automatic configuration process

Spring Boot automatic configuration relies on the @enableAutoConfiguration annotation

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
Copy the code

@ EnableAutoConfiguration annotations in the main is @ Import (AutoConfigurationImportSelector. Class) annotations, use the Enable – AutoConfigurationImportSelector , @enableAutoConfiguration, and The Spring Boot application loads all the qualified @Configuration classes into the current Spring container.

1 @enableAutoConfiguration Remarks

Spring Boot automatically by the @ EnableAutoConfiguration start Spring application context configuration, import a AutoConfigurationImportSelector class, AutoConfigurationImportSelector reads Fetch the fully qualified name of the class whose key is EnableAutoConfiguration under spring.factories.

Partial source code:

	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());
		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
				+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}
Copy the code

The main purpose of the spring-factories setup is to tell Spring Boot which *AutoConfiguration classes the stareter needs to load, which are the beans or functions you really want to automatically register. Then, we implement a spring.factories class annotated with @Configuration, and the starter definition is complete.

The getSpringFactoriesLoaderFactoryClass () method returns the directly EnableAutoConfiguration class.

	protectedClass<? > getSpringFactoriesLoaderFactoryClass() {return EnableAutoConfiguration.class;
	}
Copy the code

So getCandidateConfigurations () method can filter out the key for org. Springframework. Boot. Autoconfigure. EnableAutoConfiguration the fully qualified name of the corresponding values.

The SpringFactoriesLoader is used to query all implementation classes specified in the meta-INF/Spring. factories properties configuration

2 Spring. factories file

The SpringFactoriesLoader class loads the Spring. factories file,

It will judge whether to load according to @conditionalonclass and other conditions in the AutoConfiguration file

The SpringFactoriesLoader loads meta-INF/Spring. factories files in all JAR files in the classpath. The code to load the spring.factories file is in the loadFactoryNames () method.

4 summarizes

Automatic configuration in Spring Boot simplifies configuration and makes using the Spring framework more flexible and convenient. It is also useful to use annotations to control whether a class is registered in a container. In the actual use, can realize the author’s greatness more.