栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot自动配置的原理及实现

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot自动配置的原理及实现

SpringBoot的核心就是自动配置,自动配置是基于条件判断配置Bean

自动配置的源码在spring-boot-autoconfigure-2.2.13.RELEASE

SpringBoot运行原理

先看@SpringBootApplication

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.boot.autoconfigure;

import java.lang.annotation.documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.core.annotation.AliasFor;

@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 {
    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    Class[] exclude() default {};

    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    String[] excludeName() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackages"
    )
    String[] scanbasePackages() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackageClasses"
    )
    Class[] scanbasePackageClasses() default {};

    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}

主要关注的几个注解如下

@SpringBootConfiguration:标记当前类为配置类

@EnableAutoConfiguration:开启自动配置

@ComponentScan:扫描主类所在的同级包以及下级包里的Bean

关键是@EnableAutoConfiguration

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.boot.autoconfigure;

import java.lang.annotation.documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.import;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@documented
@Inherited
@AutoConfigurationPackage
@import({AutoConfigurationimportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class[] exclude() default {};

    String[] excludeName() default {};
}

最关键的要属@import(EnableAutoConfigurationimportSelector.class),借助EnableAutoConfigurationimportSelector,@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器:通过@import(AutoConfigurationimportSelector.class)导入的配置功能,

AutoConfigurationimportSelector中的方法getCandidateConfigurations,得到待配置的class的类名集合,这个集合就是所有需要进行自动配置的类,而是否配置的关键在于meta-INF/spring.factories文件中是否存在该配置信息

protected List getCandidateConfigurations(Annotationmetadata metadata, AnnotationAttributes attributes) {
        List configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
    }

打开,如下图可以看到所有需要配置的类全路径都在文件中,每行一个配置,多个类名逗号分隔,而表示忽略换行

样例讲解

以SpringApplicationAdminJmxAutoConfiguration类来看其主要构成部分

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.boot.autoconfigure.admin;

import java.util.Iterator;
import javax.management.MalformedObjectNameException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.admin.SpringApplicationAdminMXBeanRegistrar;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.jmx.export.MBeanExporter;

@Configuration(
    proxyBeanMethods = false
)
@AutoConfigureAfter({JmxAutoConfiguration.class})
@ConditionalOnProperty(
    prefix = "spring.application.admin",
    value = {"enabled"},
    havingValue = "true",
    matchIfMissing = false
)
public class SpringApplicationAdminJmxAutoConfiguration {
    private static final String JMX_NAME_PROPERTY = "spring.application.admin.jmx-name";
    private static final String DEFAULT_JMX_NAME = "org.springframework.boot:type=Admin,name=SpringApplication";

    public SpringApplicationAdminJmxAutoConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean
    public SpringApplicationAdminMXBeanRegistrar springApplicationAdminRegistrar(ObjectProvider mbeanExporters, Environment environment) throws MalformedObjectNameException {
        String jmxName = environment.getProperty("spring.application.admin.jmx-name", "org.springframework.boot:type=Admin,name=SpringApplication");
        if (mbeanExporters != null) {
            Iterator var4 = mbeanExporters.iterator();

            while(var4.hasNext()) {
                MBeanExporter mbeanExporter = (MBeanExporter)var4.next();
                mbeanExporter.addExcludedBean(jmxName);
            }
        }

        return new SpringApplicationAdminMXBeanRegistrar(jmxName);
    }
}

都能看到各种各样的条件判断注解,满足条件时就加载这个Bean并实例化

手动实现自动配置的demo

项目目录

1.XiaoServer文件

package com.xiao.configure;


public class XiaoServer {

    private String name;

    public String sayServerName(){
        return "I'm " + name + "! ";
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

2.XiaoServerProperties文件

package com.xiao.configure;

import org.springframework.boot.context.properties.ConfigurationProperties;


@ConfigurationProperties(prefix = "xiao")
public class XiaoServerProperties {

    private static final String NAME = "xiao_server0";

    private String name = NAME;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

3.XiaoServiceAutoConfiguration文件

package com.xiao.configure;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
@EnableConfigurationProperties(XiaoServerProperties.class)
@ConditionalOnClass(XiaoServer.class)//判断XiaoServer这个类在类路径中是否存在
@ConditionalOnProperty(prefix = "xiao",value = "enabled",matchIfMissing = true)
public class XiaoServiceAutoConfiguration {

    @Autowired
    private XiaoServerProperties mistraServiceProperties;

    @Bean(name = "xiaoServer")
    @ConditionalOnMissingBean(XiaoServer.class)//当容器中没有这个Bean时(XiaoServer)就自动配置这个Bean,Bean的参数来自于XiaoServerProperties
    public XiaoServer mistraService(){
        XiaoServer mistraService = new XiaoServer();
        mistraService.setName(mistraServiceProperties.getName());
        return mistraService;
    }

}

4.SpringbootAutoconfigureApplication文件

package com.xiao;

import com.xiao.configure.XiaoServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;

@SpringBootApplication
@RestController
public class SpringbootAutoconfigureApplication {

    @Autowired
    private XiaoServer xiaoService;

    public static void main(String[] args) {
        SpringApplication.run(SpringbootAutoconfigureApplication.class, args);
    }

    @RequestMapping("/")
    public Object index(){
        return "helll demo "+xiaoService.getName()+" "+new Date();
    }
}

5.spring.factories

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.xiao.configure.XiaoServiceAutoConfiguration

6.application.properties

xiao.name=test service

7.pom.xml



    4.0.0
    
    com.xiao
    springboot-autoconfigure
    0.0.1-SNAPSHOT
    springboot-autoconfigure
    Demo project for Spring Boot
    
        1.8
    
    
        
            org.springframework.boot
            spring-boot-starter
            2.5.0
        

        
            org.springframework.boot
            spring-boot-starter-web
            2.5.0
        

        
            org.springframework.boot
            spring-boot-starter-test
            2.2.13.RELEASE
            test
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    


运行结果:

总结:

一、什么是springBoot自动配置

SSM项目创建一次,需要写大量的配置文件,而springboot只需要写少量的配置,其他的都交给自动配置,按条件创建bean

二、springboot自动配置是怎么运行的

  1. 当SpringBoot项目启动时,会先去扫描所有jar包下的meta-INF/spring.factories配置文件

2.通过读取spring.factories配置文件得到所有自动配置类的全限定类名,并将这些自动配置类全部注入到IOC容器

3.那么多类是全部都注入进去?当然不是,在这些配置类中都有条件注解,这些条件注解会去判断是否要导入

4.经过以上步骤,就实现了自动配置的过程,当然详细的实现细节肯定不会这么简单

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/425166.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号