集思吧网站怎么做问卷,指数函数和对数函数,能做视频的软件有哪些,公司网站怎样做维护SpringBootApplication Spring Boot应用标注 SpringBootApplication 注解的类说明该类是Spring Boot 的主配置类#xff0c;需要运行该类的main方法进行启动 Spring Boot 应用 SpringBootConfiguration 该注解标注表示标注的类是个配置类
EnableAutoConfiguration 直译#…SpringBootApplication Spring Boot应用标注 SpringBootApplication 注解的类说明该类是Spring Boot 的主配置类需要运行该类的main方法进行启动 Spring Boot 应用 SpringBootConfiguration 该注解标注表示标注的类是个配置类
EnableAutoConfiguration 直译开启自动配置 AutoConfigurationPackage 将当前配置类所在的包保存在 basePackages 的Bean 中提供给Spring 使用 Import(AutoConfigurationPackages.Registrar.class) 注册一个保存当前配置类所在包的Bean
Import(AutoConfigurationImportSelector.class) 使用Import注解完成导入AutoConfigurationImportSelector类 的功能。AutoConfigurationImportSelector 实现了DeferredImportSelector类
注在解析ImportSelector时所导入的配置类会被直接解析而DeferredImportSelector导入的配置类会延迟进行解析延迟在其他配置类都解析完之后 Spring容器在解析Import时会去执行DeferredImportSelector 的 selectImports方法:
/*** Return the {link AutoConfigurationEntry} based on the {link AnnotationMetadata}* of the importing {link Configuration Configuration} class.* param annotationMetadata the annotation metadata of the configuration class* return the auto-configurations that should be imported*/protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return EMPTY_ENTRY;}AnnotationAttributes attributes getAttributes(annotationMetadata);// 从META-INF/spring.factories中获得候选的自动配置类ListString configurations getCandidateConfigurations(annotationMetadata, attributes);//去重configurations removeDuplicates(configurations);//根据EnableAutoConfiguration注解中exclude、excludeName属性、//spring.autoconfigure.exclude 配置的排除项SetString exclusions getExclusions(annotationMetadata, attributes);checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);// 通过读取spring.factories 中 // OnBeanCondition\OnClassCondition\OnWebApplicationCondition进行过滤configurations getConfigurationClassFilter().filter(configurations);fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationEntry(configurations, exclusions);} springboot应用中都会引入spring-boot-autoconfigure依赖spring.factories文件就在该包的META-INF下面。spring.factories文件是KeyValue形式多个Value时使用“”逗号进行分割该文件中定义了关于初始化、监听器、过滤器等信息而真正使自动配置生效的key是org.springframework.boot.autoconfigure.EnableAutoConfiguration如下所示 Spring Boot 提供的自动配置类 https://docs.spring.io/spring-boot/docs/current/reference/html/auto-configuration-classes.html#appendix.auto-configuration-classes
Spring Boot 常用条件注解 ConditionalOnBean是否存在某个某类或某个名字的Bean ConditionalOnMissingBean是否缺失某个某类或某个名字的Bean ConditionalOnSingleCandidate是否符合指定类型的Bean只有一个 ConditionalOnClass是否存在某个类 ConditionalOnMissingClass是否缺失某个类 ConditionalOnExpression指定的表达式返回的是true还是false ConditionalOnJava判断Java版本 ConditionalOnWebApplication当前应用是不是一个Web应用 ConditionalOnNotWebApplication当前应用不是一个Web应用 ConditionalOnPropertyEnvironment中是否存在某个属性 我们也可以使用Conditional注解进行自定义条件注解 条件注解可以写在类和方法上如果某个xxxCondition条件注解写在自动配置类上那该自动配置类会不会生效就要看当前条件是否符合条件或者条件注解写在某个Bean修饰的方法上那么Bean生不生效也要看当前的条件是否符条件。 Spring容器在解析某个自动配置类时会先判断该自动配置类上是否有条件注解如果有则进一步判断条件注解所指定的条件当前情况是否满足如果满足则继续解析该配置类如果不满足则不进行解析该配置类于是配置类所定义的Bean也都得不到解析那么在Spring容器中就不会存在该Bean。 同理Spring在解析某个Bean的方法时也会先判断方法上是否有条件注解然后进行解析如果不满足条件则该Bean也不会生效。 Spring Boot提供的自动配置实际上就是Spring Boot源码中预先写好准备了一些常用的配置类预先定义好了一些Bean在用Spring Boot时这些配置类就已经在我们项目的依赖中了而这些自动配置类或自动配置Bean是否生效就需要看具体指定的条件是否满足。 下面代码就是根据 Conditional 确定是否应跳过忽略
/*** Determine if an item should be skipped based on {code Conditional} annotations.* param metadata the meta data* param phase the phase of the call* return if the item should be skipped*/public boolean shouldSkip(Nullable AnnotatedTypeMetadata metadata, Nullable ConfigurationPhase phase) {if (metadata null || !metadata.isAnnotated(Conditional.class.getName())) {return false;}if (phase null) {if (metadata instanceof AnnotationMetadata ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);}return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);}ListCondition conditions new ArrayList();for (String[] conditionClasses : getConditionClasses(metadata)) {for (String conditionClass : conditionClasses) {Condition condition getCondition(conditionClass, this.context.getClassLoader());conditions.add(condition);}}AnnotationAwareOrderComparator.sort(conditions);for (Condition condition : conditions) {ConfigurationPhase requiredPhase null;if (condition instanceof ConfigurationCondition) {requiredPhase ((ConfigurationCondition) condition).getConfigurationPhase();}if ((requiredPhase null || requiredPhase phase)
// 重点判断
!condition.matches(this.context, metadata)) {return true;}}return false;} 以ConditionalOnBean底层工作原理为示例 OnBeanCondition类继承了FilteringSpringBootConditionFilteringSpringBootCondition类又继承SpringBootCondition而SpringBootCondition实现了Condition接口matches()方法也是在 SpringBootCondition这个类中实现的
public abstract class SpringBootCondition implements Condition {private final Log logger LogFactory.getLog(getClass());Overridepublic final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 获取当前解析的类名或方法名String classOrMethodName getClassOrMethodName(metadata);try {
// 进行具体的条件匹配ConditionOutcome表示匹配结果ConditionOutcome outcome getMatchOutcome(context, metadata);
//日志记录匹配结果logOutcome(classOrMethodName, outcome);recordEvaluation(context, classOrMethodName, outcome);
// 返回匹配结果 true/falsereturn outcome.isMatch();}catch (NoClassDefFoundError ex) {throw new IllegalStateException(Could not evaluate condition on classOrMethodName due to ex.getMessage() not found. Make sure your own configuration does not rely on that class. This can also happen if you are ComponentScanning a springframework package (e.g. if you put a ComponentScan in the default package by mistake), ex);}catch (RuntimeException ex) {throw new IllegalStateException(Error processing condition on getName(metadata), ex);}}
//....public abstract ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata);} 具体的条件匹配逻辑在getMatchOutcome方法中实现的而SpringBootCondition类中的 getMatchOutcome方法是一个抽象方法具体的实现逻辑就在子类OnBeanCondition
Overridepublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {ConditionMessage matchMessage ConditionMessage.empty();MergedAnnotations annotations metadata.getAnnotations();// 如果存在ConditionalOnBean注解if (annotations.isPresent(ConditionalOnBean.class)) {SpecConditionalOnBean spec new Spec(context, metadata, annotations, ConditionalOnBean.class);MatchResult matchResult getMatchingBeans(context, spec);// 如果某个Bean不存在if (!matchResult.isAllMatched()) {String reason createOnBeanNoMatchReason(matchResult);return ConditionOutcome.noMatch(spec.message().because(reason));}// 所有Bean都存在matchMessage spec.message(matchMessage).found(bean, beans).items(Style.QUOTE, matchResult.getNamesOfAllMatches());}// 如果存在ConditionalOnSingleCandidate注解if (metadata.isAnnotated(ConditionalOnSingleCandidate.class.getName())) {SpecConditionalOnSingleCandidate spec new SingleCandidateSpec(context, metadata, annotations);MatchResult matchResult getMatchingBeans(context, spec);if (!matchResult.isAllMatched()) {return ConditionOutcome.noMatch(spec.message().didNotFind(any beans).atAll());}SetString allBeans matchResult.getNamesOfAllMatches();if (allBeans.size() 1) {matchMessage spec.message(matchMessage).found(a single bean).items(Style.QUOTE, allBeans);}else {ListString primaryBeans getPrimaryBeans(context.getBeanFactory(), allBeans,spec.getStrategy() SearchStrategy.ALL);if (primaryBeans.isEmpty()) {return ConditionOutcome.noMatch(spec.message().didNotFind(a primary bean from beans).items(Style.QUOTE, allBeans));}if (primaryBeans.size() 1) {return ConditionOutcome.noMatch(spec.message().found(multiple primary beans).items(Style.QUOTE, primaryBeans));}matchMessage spec.message(matchMessage).found(a single primary bean primaryBeans.get(0) from beans).items(Style.QUOTE, allBeans);}}// 存在ConditionalOnMissingBean注解if (metadata.isAnnotated(ConditionalOnMissingBean.class.getName())) {SpecConditionalOnMissingBean spec new Spec(context, metadata, annotations,ConditionalOnMissingBean.class);MatchResult matchResult getMatchingBeans(context, spec);if (matchResult.isAnyMatched()) {String reason createOnMissingBeanNoMatchReason(matchResult);return ConditionOutcome.noMatch(spec.message().because(reason));}matchMessage spec.message(matchMessage).didNotFind(any beans).atAll();}return ConditionOutcome.match(matchMessage);}protected final MatchResult getMatchingBeans(ConditionContext context, Spec? spec) {ClassLoader classLoader context.getClassLoader();ConfigurableListableBeanFactory beanFactory context.getBeanFactory();boolean considerHierarchy spec.getStrategy() ! SearchStrategy.CURRENT;SetClass? parameterizedContainers spec.getParameterizedContainers();if (spec.getStrategy() SearchStrategy.ANCESTORS) {BeanFactory parent beanFactory.getParentBeanFactory();Assert.isInstanceOf(ConfigurableListableBeanFactory.class, parent,Unable to use SearchStrategy.ANCESTORS);beanFactory (ConfigurableListableBeanFactory) parent;}MatchResult result new MatchResult();SetString beansIgnoredByType getNamesOfBeansIgnoredByType(classLoader, beanFactory, considerHierarchy,spec.getIgnoredTypes(), parameterizedContainers);for (String type : spec.getTypes()) {CollectionString typeMatches getBeanNamesForType(classLoader, considerHierarchy, beanFactory, type,parameterizedContainers);typeMatches.removeIf((match) - beansIgnoredByType.contains(match) || ScopedProxyUtils.isScopedTarget(match));if (typeMatches.isEmpty()) {result.recordUnmatchedType(type);}else {result.recordMatchedType(type, typeMatches);}}for (String annotation : spec.getAnnotations()) {SetString annotationMatches getBeanNamesForAnnotation(classLoader, beanFactory, annotation,considerHierarchy);annotationMatches.removeAll(beansIgnoredByType);if (annotationMatches.isEmpty()) {result.recordUnmatchedAnnotation(annotation);}else {result.recordMatchedAnnotation(annotation, annotationMatches);}}for (String beanName : spec.getNames()) {if (!beansIgnoredByType.contains(beanName) containsBean(beanFactory, beanName, considerHierarchy)) {result.recordMatchedName(beanName);}else {result.recordUnmatchedName(beanName);}}return result;} getMatchingBeans方法中会利用BeanFactory去获取指定类型的Bean如果没有指定类型的Bean则会将该类型记录在MatchResult对象的unmatchedTypes集合中如果有该类型的Bean则会把该Bean的beanName记录在MatchResult对象的matchedNames集合中所以MatchResult对象中记录了哪些类没有对应的Bean哪些类有对应的Bean。 大概流程如下 Spring在解析某个配置类或某个Bean定义时如果发现它们上面用到了条件注解就会取出所有的条件注解并生成对应的条件对象比如OnBeanCondition对象 依次调用条件对象的matches方法进行条件匹配看是否符合条件 条件匹配逻辑中会拿到ConditionalOnBean等条件注解的信息判断哪些Bean存在 然后利用BeanFactory来进行判断 最后只有所有条件注解的条件都匹配那么当前Bean定义才算符合条件生效 自定义Spring Boot Starter SpringBoot 最强大的功能就是把我们常用的业务场景抽取成了一个个starter场景启动器我们通过引入SpringBoot 提供的这些场景启动器再进行少量的配置就能使用相应的功能。但是SpringBoot 不能囊括我们所有的业务使用场景往往我们需要自定义starter来简化我们对springboot的使用。 下面是自定义starter的示例代码地址
lp-springboot-start: 自定义Spring Boot Start