SpringBoot核心,my-springboot-start实战

申屠喜
2023-12-01

一、SpringBoot 作用

  • 可以以jar形式独立运行
  • 内置tomcat容器
  • 自动配置spring
  • 约定大于配置,无代码生成

二、@Conditional注解

  • Config配置类
/**
 * 创建PersonEntity,根据条件不同,注入不同的对象
 */
@Configuration
public class Config {
    
    @Bean
    @Conditional(ConditionDev.class)
    public PersonEntity personDepEntity(){
        PersonEntity entity = new PersonEntity();
        entity.setName("personDepEntity create");
        return entity;
    }

    @Bean
    @Conditional(ConditionTest.class)
    public PersonEntity personTestEntity(){
        PersonEntity entity = new PersonEntity();
        entity.setName("personTestEntity create");
        return entity;
    }
}
  • ConditionDep条件类
public class ConditionDep implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //注解对应的类名
        String className = ((StandardMethodMetadata) metadata).getDeclaringClassName();
        //注解对应的方法名
        String methodName = ((StandardMethodMetadata) metadata).getMethodName();
        //注解对应其他注解的属性,可以获得其他注解的信息
        MultiValueMap<String, Object> annotationAttributes =
                metadata.getAllAnnotationAttributes("org.springframework.context.annotation.Bean");
        System.out.println(className);
        System.out.println(methodName);
        System.out.println(annotationAttributes);
        //spring工厂类。可以获取bean
        System.out.println(context.getBeanFactory().getClass());
        //返回值决定,条件是否成功
        return true;
    }
}
  • ConditionTest条件类
public class ConditionTest implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return false;
    }
}
  • 测试类
public class Main {
   public static void main(String[] args) {
       AnnotationConfigApplicationContext context =
               new AnnotationConfigApplicationContext(Config.class);
       //输出注入对象
       System.out.println(context.getBean(PersonEntity.class));
   }
}
  • 运行结果
//注解对应的类名
com.moon.condition.Config
//注解对应方法名
personDepEntity
//指定注解的信息
{name=[[Ljava.lang.String;@68be2bc2], value=[[Ljava.lang.String;@68be2bc2], initMethod=[], autowire=[NO], destroyMethod=[(inferred)]}
//工厂对象的真是类型
class org.springframework.beans.factory.support.DefaultListableBeanFactory
//注入的对象为personDepEntity 
PersonEntity{name='personDepEntity create', age=null, workEntity=null}
------------------------------------------------------------------------
//修改ConditionDep 的返回值为false,修改ConditionTest 的返回值为true
com.moon.condition.Config
personDepEntity
{name=[[Ljava.lang.String;@68be2bc2], value=[[Ljava.lang.String;@68be2bc2], initMethod=[], autowire=[NO], destroyMethod=[(inferred)]}
class org.springframework.beans.factory.support.DefaultListableBeanFactory
//此时的注入对象为personTestEntity 
PersonEntity{name='personTestEntity create', age=null, workEntity=null}
----------------------------------------------------------------------
结论:@Conditional(类)的类,实现Condition接口的类,返回的布尔值,决定对象是否注入

三、SpringBoot工作原理

  • Main方法入口
@SpringBootApplication
public class SpringbootsourceApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootsourceApplication.class, args);
    }
}
  • @SpringBootApplication核心注解
@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 {
}
  • @EnableAutoConfiguration自动配置
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage//保存自动配置类以供之后的使用,如jpa的@Entity注解
@Import(AutoConfigurationImportSelector.class)// 配置筛选!!!!!!!!!!!
public @interface EnableAutoConfiguration {
}
  • AutoConfigurationImportSelector自动配置选择
public class AutoConfigurationImportSelector
		implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
		BeanFactoryAware, EnvironmentAware, Ordered {
		
	@Override
	public void process(AnnotationMetadata annotationMetadata,
			DeferredImportSelector deferredImportSelector) {
		Assert.state(
				deferredImportSelector instanceof AutoConfigurationImportSelector,
				() -> String.format("Only %s implementations are supported, got %s",
						AutoConfigurationImportSelector.class.getSimpleName(),
						deferredImportSelector.getClass().getName()));
		//核心方法				
		AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
				.getAutoConfigurationEntry(getAutoConfigurationMetadata(),
						annotationMetadata);
		this.autoConfigurationEntries.add(autoConfigurationEntry);
		for (String importClassName : autoConfigurationEntry.getConfigurations()) {
			this.entries.putIfAbsent(importClassName, annotationMetadata);
		}
	}
	
	protected AutoConfigurationEntry getAutoConfigurationEntry(
			AutoConfigurationMetadata autoConfigurationMetadata,
			AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		//核心方法
		List<String> configurations = getCandidateConfigurations(annotationMetadata,
				attributes);
		configurations = removeDuplicates(configurations);
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		configurations = filter(configurations, autoConfigurationMetadata);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
			AnnotationAttributes attributes) {
		//进入SpringFactoriesLoader这个类
		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;
	}
}
  • SpringFactoriesLoader
	public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
	
	public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
		String factoryClassName = factoryClass.getName();
		//核心方法
		return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
	}
	private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
		MultiValueMap<String, String> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		try {
			Enumeration<URL> urls = (classLoader != null ?
					//核心方法
					//加载FACTORIES_RESOURCE_LOCATION资源
					//public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
					classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			result = new LinkedMultiValueMap<>();
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryClassName = ((String) entry.getKey()).trim();
					for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
						result.add(factoryClassName, factoryName.trim());
					}
				}
			}
			cache.put(classLoader, result);
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
	}
  • 找到META-INF/spring.factories配置文件
    该文件在org.springframework.boot:spring:spring-boot-autoconfigure的META-INF/spring.factories
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener

# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.rest.RestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityRequestMatcherProviderAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration

# Failure analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\
org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer

# Template availability providers
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider
  • 以QuartzAutoConfiguration的配置文件为例
@Configuration
@ConditionalOnClass({ Scheduler.class, SchedulerFactoryBean.class,
		PlatformTransactionManager.class })
@EnableConfigurationProperties(QuartzProperties.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class,
		HibernateJpaAutoConfiguration.class })
public class QuartzAutoConfiguration {

	@Bean//注入Quartz的工厂对象SchedulerFactoryBean
	@ConditionalOnMissingBean//在一定条件下进行注入
	public SchedulerFactoryBean quartzScheduler() {
		SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
		SpringBeanJobFactory jobFactory = new SpringBeanJobFactory();
		jobFactory.setApplicationContext(this.applicationContext);
		schedulerFactoryBean.setJobFactory(jobFactory);
		if (this.properties.getSchedulerName() != null) {
			schedulerFactoryBean.setSchedulerName(this.properties.getSchedulerName());
		}
		schedulerFactoryBean.setAutoStartup(this.properties.isAutoStartup());
		schedulerFactoryBean
				.setStartupDelay((int) this.properties.getStartupDelay().getSeconds());
		schedulerFactoryBean.setWaitForJobsToCompleteOnShutdown(
				this.properties.isWaitForJobsToCompleteOnShutdown());
		schedulerFactoryBean
				.setOverwriteExistingJobs(this.properties.isOverwriteExistingJobs());
		if (!this.properties.getProperties().isEmpty()) {
			schedulerFactoryBean
					.setQuartzProperties(asProperties(this.properties.getProperties()));
		}
		if (this.jobDetails != null && this.jobDetails.length > 0) {
			schedulerFactoryBean.setJobDetails(this.jobDetails);
		}
		if (this.calendars != null && !this.calendars.isEmpty()) {
			schedulerFactoryBean.setCalendars(this.calendars);
		}
		if (this.triggers != null && this.triggers.length > 0) {
			schedulerFactoryBean.setTriggers(this.triggers);
		}
		customize(schedulerFactoryBean);
		return schedulerFactoryBean;
	}
}
  • @ConditionalOnMissingBean//在缺失bean的条件下执行
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)//实现功能的类
public @interface ConditionalOnMissingBean {
}
  • OnBeanCondition 条件类
@Order(Ordered.LOWEST_PRECEDENCE)
class OnBeanCondition extends FilteringSpringBootCondition
		implements ConfigurationCondition {
		
	private ConditionOutcome getOutcome(Set<String> requiredBeanTypes,
			Class<? extends Annotation> annotation) {
		List<String> missing = filter(requiredBeanTypes, ClassNameFilter.MISSING,
				getBeanClassLoader());
		if (!missing.isEmpty()) {
			ConditionMessage message = ConditionMessage.forCondition(annotation)
					.didNotFind("required type", "required types")
					.items(Style.QUOTE, missing);
			return ConditionOutcome.noMatch(message);
		}
		return null;
	}
	//最后返回ConditionOutcome对象,他抽象类是SpringBootCondition,最后实现了Condition 接口
	//是否能够匹配决定于outcome.isMatch();
	//正是现在封装的对象,经过逻辑判断是否需要进行注入,
	//逻辑就是@ConditionalOnMissingBean,工厂里面是否已经注入?已经注入,不进行操作,没有注入,使用默认对象进行注入
	public abstract class SpringBootCondition implements Condition {
	@Override
	public final boolean matches(ConditionContext context,
			AnnotatedTypeMetadata metadata) {
		String classOrMethodName = getClassOrMethodName(metadata);
		try {
			ConditionOutcome outcome = getMatchOutcome(context, metadata);
			logOutcome(classOrMethodName, outcome);
			recordEvaluation(context, classOrMethodName, outcome);
			return outcome.isMatch();
		}
	}		
}
  • 总结
    springboot提供了start,不同的start会注入不同的对象,如Quertz会注入SchedulerFactoryBean,现在用Quertz进行说明,启动框架,首先注入自己配置的对象,@ConditionalOnMissingBean会找到spring工厂的SchedulerFactoryBean的bean,没有的情况就讲默认的注入到工厂,有的情况不会再进行注入并使用默认配置,spring工程始终只有一个SchedulerFactoryBean对象。这样可以动态的实现默认配置

四、my-springboot-start实战

话不多说,我们自己写一个简单my-spring-start,模拟一下框架整合原理
项目一、third-framework(假设的第三方开源框架 ,核心对象假设为ThirdFrameworkFactory)
项目二、my-springboot-start(springboot整合 third-framework,实现默认配置)
项目三、test-my-start(测试一下结果)
!!!项目创建后mvn install到本地仓库,项目相互依赖比较方便!!!

  • third-framework
    ThirdFrameworkFactory 类
public class ThirdFrameworkFactory {
    //核心配置,假设只有一个config
    private String config;
    
    public String getConfig() {
        return config;
    }

    public void setConfig(String config) {
        this.config = config;
    }

    @Override
    public String toString() {
        return "ThirdFrameworkFactory{" +
                "config='" + config + '\'' +
                '}';
    }
}
  • my-springboot-start
    pom.xml
<?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.moon</groupId>
    <artifactId>my-springboot-start</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <!--导入第三方核心包-->
        <dependency>
            <groupId>com.moon</groupId>
            <artifactId>third-framework</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
            <version>2.1.3.RELEASE</version>
        </dependency>
        <!--spring相关包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.3.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>4.3.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.4.RELEASE</version>
        </dependency>
    </dependencies>
</project>

Config配置类,设置默认配置对象

@Configuration
public class Config {
    @Bean
    @Conditional(ConditionMissBean.class)
    public ThirdFrameworkFactory thirdFrameworkFactory(){
        ThirdFrameworkFactory thirdFrameworkFactory = new ThirdFrameworkFactory();
        //默认配置
        thirdFrameworkFactory.setConfig("default config");
        return thirdFrameworkFactory;
    }
}

ConditionMissBean条件选择配置类

@Component
public class ConditionMissBean implements Condition {
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //拿到方法名,方法名在默认配置下就是bean的名字
        String beanName = ((MethodMetadataReadingVisitor) metadata).getMethodName();
        //bean 工厂
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //spring工厂里面是否含有bean
        //有就不进行注入,没有就注入
        return !beanFactory.containsBean(beanName);
    }
}
  • test-my-start
    pom.xml
<?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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.moon</groupId>
    <artifactId>test-my-start</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>test-my-start</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <!--springboot依赖-->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <!--spring测试-->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <!--自己的start-->
            <groupId>com.moon</groupId>
            <artifactId>my-springboot-start</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>

ConfigTest配置类

@Configuration
public class ConfigTest {
//    @Bean  //注释bean不进行配置
    public ThirdFrameworkFactory thirdFrameworkFactory(){
        ThirdFrameworkFactory factory = new ThirdFrameworkFactory();
        factory.setConfig("new config");
        return factory;
    }
}

TestMyStartApplication启动类

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

TestMyStartTest测试类

@RunWith(SpringRunner.class)
@SpringBootTest
public class TestMyStartTest {

    @Resource
    private ThirdFrameworkFactory thirdFrameworkFactory;

    @Test
    public void contextLoads() {
        System.out.println(thirdFrameworkFactory);

    }
}

使用测试类进行测试--------》测试结果

ThirdFrameworkFactory{config='default config'}//输出值为默认配置
--------------------------------------------------------------------------
修改ConfigTest配置类,放开@Bean注解,将自定义bean注入
ThirdFrameworkFactory{config='new config'}//输出为新的配置

我们简单的实现了springboot核心,约定大于配置,
没有自定义对象就使用默认对象,自定义了对象就使用配置对象

 类似资料: