spring-boot-start原理分析

2022-06-19 13:37:34

源码分析github地址原文链接

了解springboot的都知道启动类上经常又个@SpringBootApplication注解,这个注解点进去看下是包括一个自动配置很关键的注解,那就是@EnableAutoConfiguration注解。我们看下源码

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
	Class<?>[] exclude() default {};
	String[] excludeName() default {};
}

可以从源码看出关键功能是@import注解导入自动配置功能类AutoConfigurationImportSelector类,主要方法getCandidateConfigurations()使用了SpringFactoriesLoader.loadFactoryNames()方法加载META-INF/spring.factories的文件(spring.factories声明具体自动配置)。

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;
	}

starter常用的条件注解

@ConditionalOnBean 当容器里有指定的Bean的条件下。
@ConditionalOnClass 当类路径下有指定的类的条件下。
@ConditionalOnProperty 指定的属性是否有指定的值。

自定义starter

模拟公司获取密码的组件写一个demo-starter

依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.yyl</groupId>
    <artifactId>password-spring-starter</artifactId>
    <version>1.0-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.8.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
</project>

服务类

package com.yyl.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;

/**
 * author:yangyuanliang Date:2019-10-15 Time:13:32
 **/
public class PasswordService {
    private String key;
    @Autowired
    //模拟的第三方系统service
    private ThirdPartyService thirdPartyService;
    public String getSystemPassword(String objectKey,String originalPassord){
        if(StringUtils.isEmpty(objectKey)){
            return  originalPassord;
        }
        //从第三方系统获取密码
        String password= thirdPartyService.getPassword(objectKey);
        //返回密码
        return password!=null?password:originalPassord;
    }
}
public class ThirdPartyService {
    public String getPassword(String objectKey){
        //返回一个32位随机数
        return UUID.randomUUID().toString();
    }
}

属性配置类

package com.yyl.properties;

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

/**
 * author:yangyuanliang Date:2019-10-15 Time:13:34
 **/
@ConfigurationProperties(prefix = "spring.starter.password")
public class BaseServiceProperties {
    private String serviceName;
    private String serviceVersion;

    public String getServiceName() {
        return serviceName;
    }

    public void setServiceName(String serviceName) {
        this.serviceName = serviceName;
    }

    public String getServiceVersion() {
        return serviceVersion;
    }

    public void setServiceVersion(String serviceVersion) {
        this.serviceVersion = serviceVersion;
    }
}

配置使用类

public class BaseStarterService {

    public void addServiceName(BaseServiceProperties baseServiceProperties){
        System.out.println("serviceName:"+baseServiceProperties.getServiceName()+"----"+"serviceVersion"+baseServiceProperties.getServiceVersion());
    }
}

自动配置类

@Configuration
//自动加载配置文件属性值
@EnableConfigurationProperties(BaseServiceProperties.class)
@Import(BeanConfiguration.class)
//判断当前环境是否为windows
@Conditional(MacCondition.class)
//判断属性spring.project.ThirdPartySystemService.isPassword是否等于true
@ConditionalOnProperty(prefix = "spring.project.ThirdPartySystemService",value = "enablePassword", havingValue = "true",matchIfMissing = true)
public class AutoConfigurationPassoword {
    @Autowired
    private BaseServiceProperties baseServiceProperties;
    @Autowired
    private BaseStarterService baseWindowsService;

    //加载第三方系统service
    @Bean("thirdPartySystemService")
    public ThirdPartyService thirdPartySystemService(){
        baseWindowsService.addServiceName(baseServiceProperties);
        return new ThirdPartyService();
    }
    @Bean
    //判断IOC容器中是否存在ThirdPartySystemService类,存在则创建PasswordService bean
    @ConditionalOnClass(ThirdPartyService.class)
    public PasswordService passwordService(){
        baseWindowsService.addServiceName(baseServiceProperties);
        return new PasswordService();
    }
}

条件类

package com.yyl.condition;

import com.yyl.service.BaseStarterService;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

/**
 * author:yangyuanliang Date:2019-10-15 Time:13:37
 **/
public class MacCondition implements Condition {
    private final static String WINDOWS="Windows";
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        //获取当前环境变量
        Environment environment=conditionContext.getEnvironment();
        //获取bean注册器
        BeanDefinitionRegistry registry = conditionContext.getRegistry();
        //能获取到ioc使用的beanfactory
        ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
        //获取环境变量中操作系统
        String property = environment.getProperty("os.name");
        //判断操作系统是否为windows
        if(!property.contains(WINDOWS)){
            //判断是否存在baseWindowsSevice类,不存在则进行bean注册
            boolean isWindowsSevice = registry.containsBeanDefinition("baseStarterService");
            if(!isWindowsSevice){
                //指定Bean定义信息;(Bean的类型,Bean的一系列信息)
                RootBeanDefinition beanDefinition = new RootBeanDefinition(BaseStarterService.class);
                //注册一个Bean,指定bean名
                registry.registerBeanDefinition("baseStarterService", beanDefinition);
                BaseStarterService windowsSevice = (BaseStarterService)beanFactory.getBean("baseStarterService");
            }
            return true;
        }
        return false;
    }
}

注册配置

在resource下新建META-INF文件夹新建spring.factories文件

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.yyl.autoconf.AutoConfigurationPassoword

完成并测试

 <dependencies>
        <dependency>
				 <groupId>com.yyl</groupId>
			    <artifactId>password-spring-starter</artifactId>
			    <version>1.0-SNAPSHOT</version>
     </dependency>
    </dependencies>

application.properties属性

spring.starter.password.serviceName=aaa
spring.starter.password.serviceVersion=1
spring.project.ThirdPartyService.enablePassword=true

总结

  • SpringBoot启动时会自动搜索包含spring.factories文件的JAR包;
  • 根据spring.factories文件加载自动配置类AutoConfiguration;
  • 通过AutoConfiguration类,加载满足条件(@ConditionalOnXxx)的bean到Spring IOC容器中;
  • 使用者可以直接使用自动加载到IOC的bean。
  • 作者:杨园亮
  • 原文链接:https://blog.csdn.net/cccfire/article/details/102564132
    更新时间:2022-06-19 13:37:34