1 SpringBoot简介

  • SpringBoot简化Spring应用开发,约定大于配置,去繁从简,just run就能创建一个独立的,产品级别的应用。
  • 背景:
    • J2EE笨重的开发、繁多的配置、低下的开发效率、复杂的部署流程、第三方技术集成难度大。
  • 解决:
    • “Spring全家桶”时代。
    • SpringBoot-->J2EE一站式解决方案。
    • SpringCloud-->分布式整体解决方案。  
  • 优点:
    • 快速创建独立运行的Spring项目以及与主流框架集成。
    • 使用嵌入式的Servlet容器,应用无需打成war包。
    • starters自动依赖和版本控制。
    • 大量的自动配置,简化开发,也可以修改默认值。
    • 无需配置XML,无代码生成,开箱即用。
    • 准生产环境的运行时应用监控。
    • 与云计算的天然集成。  

2 微服务简介

  • 2014年,Martin Fowler与James Lewis共同提出。
  • 微服务是一种架构风格(服务微化)。
  • 一个应用应该是一组小型服务,可以通过HTTP的方式进行互通。
  • 单体应用:ALL IN ONE。
  • 微服务:每一个功能元素最终都是一个可独立替换和独立升级的软件单元。

3 环境准备

  • JDK1.8。
  • Maven 3.x。
  • IntelliJ IDEA 2019.3。
  • SpringBoot 1.5.9.RELEASE。
  • Maven设置:
  • 给maven的settings.xml配置文件的profiles标签添加如下信息:
<profile>
<id>jdk‐1.8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>

4 SpringBoot-HelloWorld

4.1 创建Maven项目

  • 略。

4.2 导入SpringBoot相关的依赖

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

4.3 编写主程序,用来启动SpringBoot应用

  • 示例:
  • HelloWorldMainApplication.java
package com.sunxiaping;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication //标注一个主程序类,说明这是一个SpringBoot应用
public class HelloWorldMainApplication {
public static void main(String[] args) {
//SpringBoot应用启动起来
SpringApplication.run(HelloWorldMainApplication.class,args);
}
}

4.3 编写相关的Controller

  • 示例:
  • HelloWorldController.java
package com.sunxiaping.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody; @Controller
public class HelloWorldController { @RequestMapping(value = "/hello")
@ResponseBody
public String hello() {
return "helloWorld";
} }

4.4 运行主程序测试

  • 略。

4.5 简化部署

  • 在当前项目的pom.xml中添加如下的配置:
<!-- 这个插件,可以将应用打包成一个可执行的jar包-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
  • 将这个应用打成jar包,然后通过java -jar xxx.jar的命令进行执行。

5 HelloWorld探究

5.1 pom文件

5.1.1 父项目

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent> 其父项目是 <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent> 它是真正管理SpringBoot应用中的所有依赖版本,可以称之为SpringBoot的版本仲裁中心。
所以以后我们导入依赖默认是不需要写版本的,但是如果版本仲裁中心没有的,当然需要写版本号了。

5.1.2 启动器

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
  • spring-boot-starter:SpringBoot的场景启动器。
  • spring-boot-starter-web:帮助我们导入了web模块正常运行所依赖的组件。
  • SpringBoot将所有的功能场景都抽取出来,做成一个个的starters(启动器),所以我们只需要在项目里引入这些starter,相关场景的所有依赖都会导入进来。
  • 要用什么功能就导入什么场景的启动器。

5.2 主程序类、主入口

  • 示例:
package com.sunxiaping;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication //标注一个主程序类,说明这是一个SpringBoot应用
public class HelloWorldMainApplication {
public static void main(String[] args) {
//SpringBoot应用启动起来
SpringApplication.run(HelloWorldMainApplication.class,args);
}
}
  • @SpringBootApplication注解标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot就能运行这个类的main方法来启动SpringBoot应用。
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.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
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, attribute = "exclude")
Class<?>[] exclude() default {}; @AliasFor(annotation = EnableAutoConfiguration.class, attribute = "excludeName")
String[] excludeName() default {}; @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {}; @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {}; }
  • @SpringBootConfiguration注解:标注在某个类上,就表明这是一个SpringBoot的配置类,其源码如下所示:
package org.springframework.boot;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import org.springframework.context.annotation.Configuration; @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration { }
  • @Configuration注解,表明这是一个配置类,相当于原来xml格式的applicationContext.xml文件。配置类也是容器中的一个组件,其实@Configuration注解就是@Component注解,其源码如下所示:
package org.springframework.context.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration { String value() default ""; }
  • @EnableAutoConfiguration注解:开启自动配置功能。以前我们需要配置的东西,SpringBoot帮我们自动配置。@EnableAutoConfiguration注解告诉SpringBoot开启自动配置功能,这样自动配置才能生效。其源码如下:
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.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.support.SpringFactoriesLoader; @SuppressWarnings("deprecation")
@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 {}; }
  • 其中,@AutoConfigurationPackage注解,是自动配置包的意思,其源码如下:
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
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage { }
  • 从源码中,我们可以看出@AutoConfigurationPackage注解会导入AutoConfigurationPackages.Registrar.class组件,其源码如下:
    static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

        @Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
       //将当前标注注解类的包下的所有组件注册到Spring容器中 
register(registry, new PackageImport(metadata).getPackageName());
} @Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.<Object>singleton(new PackageImport(metadata));
} }
  • 所以,@SpringBootApplication注解的作用就是将其所在包以及子包下的所有组件都注册到SpringBoot中。
  • 其中,@Import(AutoConfigurationPackages.Registrar.class)将给容器中导入组件,其源码如下所示:
package org.springframework.boot.autoconfigure;

import org.springframework.context.annotation.DeferredImportSelector;
import org.springframework.core.type.AnnotationMetadata; @Deprecated
public class EnableAutoConfigurationImportSelector
extends AutoConfigurationImportSelector { @Override
protected boolean isEnabled(AnnotationMetadata metadata) {
if (getClass().equals(EnableAutoConfigurationImportSelector.class)) {
return getEnvironment().getProperty(
EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class,
true);
}
return true;
} }
  • 从上面的源码中,我们可以看到EnableAutoConfigurationImportSelector类继承了AutoConfigurationImportSelector,我们知道xxxImportSelector将会将所有需要导入的组件以全类名的方式返回,而这些组件就会被添加到容器中,我们需要查看AutoConfigurationImportSelector的源代码,如下所示:
package org.springframework.boot.autoconfigure;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.Aware;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.DeferredImportSelector;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils; public class AutoConfigurationImportSelector
implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
BeanFactoryAware, EnvironmentAware, Ordered { private static final String[] NO_IMPORTS = {}; private static final Log logger = LogFactory
.getLog(AutoConfigurationImportSelector.class); private ConfigurableListableBeanFactory beanFactory; private Environment environment; private ClassLoader beanClassLoader; private ResourceLoader resourceLoader; @Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
try {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
configurations = removeDuplicates(configurations);
configurations = sort(configurations, autoConfigurationMetadata);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return configurations.toArray(new String[configurations.size()]);
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
} protected boolean isEnabled(AnnotationMetadata metadata) {
return true;
} protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
String name = getAnnotationClass().getName();
AnnotationAttributes attributes = AnnotationAttributes
.fromMap(metadata.getAnnotationAttributes(name, true));
Assert.notNull(attributes,
"No auto-configuration attributes found. Is " + metadata.getClassName()
+ " annotated with " + ClassUtils.getShortName(name) + "?");
return attributes;
} protected Class<?> getAnnotationClass() {
return EnableAutoConfiguration.class;
} 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;
} protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
} private void checkExcludedClasses(List<String> configurations,
Set<String> exclusions) {
List<String> invalidExcludes = new ArrayList<String>(exclusions.size());
for (String exclusion : exclusions) {
if (ClassUtils.isPresent(exclusion, getClass().getClassLoader())
&& !configurations.contains(exclusion)) {
invalidExcludes.add(exclusion);
}
}
if (!invalidExcludes.isEmpty()) {
handleInvalidExcludes(invalidExcludes);
}
} protected void handleInvalidExcludes(List<String> invalidExcludes) {
StringBuilder message = new StringBuilder();
for (String exclude : invalidExcludes) {
message.append("\t- ").append(exclude).append(String.format("%n"));
}
throw new IllegalStateException(String
.format("The following classes could not be excluded because they are"
+ " not auto-configuration classes:%n%s", message));
} protected Set<String> getExclusions(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
Set<String> excluded = new LinkedHashSet<String>();
excluded.addAll(asList(attributes, "exclude"));
excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
excluded.addAll(getExcludeAutoConfigurationsProperty());
return excluded;
} private List<String> getExcludeAutoConfigurationsProperty() {
if (getEnvironment() instanceof ConfigurableEnvironment) {
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(
this.environment, "spring.autoconfigure.");
Map<String, Object> properties = resolver.getSubProperties("exclude");
if (properties.isEmpty()) {
return Collections.emptyList();
}
List<String> excludes = new ArrayList<String>();
for (Map.Entry<String, Object> entry : properties.entrySet()) {
String name = entry.getKey();
Object value = entry.getValue();
if (name.isEmpty() || name.startsWith("[") && value != null) {
excludes.addAll(new HashSet<String>(Arrays.asList(StringUtils
.tokenizeToStringArray(String.valueOf(value), ","))));
}
}
return excludes;
}
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(getEnvironment(),
"spring.autoconfigure.");
String[] exclude = resolver.getProperty("exclude", String[].class);
return (Arrays.asList(exclude == null ? new String[0] : exclude));
} private List<String> sort(List<String> configurations,
AutoConfigurationMetadata autoConfigurationMetadata) throws IOException {
configurations = new AutoConfigurationSorter(getMetadataReaderFactory(),
autoConfigurationMetadata).getInPriorityOrder(configurations);
return configurations;
} private List<String> filter(List<String> configurations,
AutoConfigurationMetadata autoConfigurationMetadata) {
long startTime = System.nanoTime();
String[] candidates = configurations.toArray(new String[configurations.size()]);
boolean[] skip = new boolean[candidates.length];
boolean skipped = false;
for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
invokeAwareMethods(filter);
boolean[] match = filter.match(candidates, autoConfigurationMetadata);
for (int i = 0; i < match.length; i++) {
if (!match[i]) {
skip[i] = true;
skipped = true;
}
}
}
if (!skipped) {
return configurations;
}
List<String> result = new ArrayList<String>(candidates.length);
for (int i = 0; i < candidates.length; i++) {
if (!skip[i]) {
result.add(candidates[i]);
}
}
if (logger.isTraceEnabled()) {
int numberFiltered = configurations.size() - result.size();
logger.trace("Filtered " + numberFiltered + " auto configuration class in "
+ TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)
+ " ms");
}
return new ArrayList<String>(result);
} protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class,
this.beanClassLoader);
} private MetadataReaderFactory getMetadataReaderFactory() {
try {
return getBeanFactory().getBean(
SharedMetadataReaderFactoryContextInitializer.BEAN_NAME,
MetadataReaderFactory.class);
}
catch (NoSuchBeanDefinitionException ex) {
return new CachingMetadataReaderFactory(this.resourceLoader);
}
} protected final <T> List<T> removeDuplicates(List<T> list) {
return new ArrayList<T>(new LinkedHashSet<T>(list));
} protected final List<String> asList(AnnotationAttributes attributes, String name) {
String[] value = attributes.getStringArray(name);
return Arrays.asList(value == null ? new String[0] : value);
} private void fireAutoConfigurationImportEvents(List<String> configurations,
Set<String> exclusions) {
List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
if (!listeners.isEmpty()) {
AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this,
configurations, exclusions);
for (AutoConfigurationImportListener listener : listeners) {
invokeAwareMethods(listener);
listener.onAutoConfigurationImportEvent(event);
}
}
} protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class,
this.beanClassLoader);
} private void invokeAwareMethods(Object instance) {
if (instance instanceof Aware) {
if (instance instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) instance)
.setBeanClassLoader(this.beanClassLoader);
}
if (instance instanceof BeanFactoryAware) {
((BeanFactoryAware) instance).setBeanFactory(this.beanFactory);
}
if (instance instanceof EnvironmentAware) {
((EnvironmentAware) instance).setEnvironment(this.environment);
}
if (instance instanceof ResourceLoaderAware) {
((ResourceLoaderAware) instance).setResourceLoader(this.resourceLoader);
}
}
} @Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
Assert.isInstanceOf(ConfigurableListableBeanFactory.class, beanFactory);
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
} protected final ConfigurableListableBeanFactory getBeanFactory() {
return this.beanFactory;
} @Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
} protected ClassLoader getBeanClassLoader() {
return this.beanClassLoader;
} @Override
public void setEnvironment(Environment environment) {
this.environment = environment;
} protected final Environment getEnvironment() {
return this.environment;
} @Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
} protected final ResourceLoader getResourceLoader() {
return this.resourceLoader;
} @Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE - 1;
} }
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
try {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
configurations = removeDuplicates(configurations);
configurations = sort(configurations, autoConfigurationMetadata);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return configurations.toArray(new String[configurations.size()]);
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}

  • 从上面的截图中,我们可以看到会给容器中注册非常多的自动配置类(xxxAutoConfiguration),换言之,就是给容器中导入这个场景所需要的所有组件,并配置好这些组件,有了自动配置了,就免去了我们手动编写配置注入功能组件等工作。
  • 其中,查看下面的代码:
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
    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;
}
    protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
    public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
try {
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
List<String> result = new ArrayList<String>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
String factoryClassNames = properties.getProperty(factoryClassName);
result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
}
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
"] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
  • 我们可以知道,将会加载类路径下的META-INF/spring.factories文件中获取EnableAutoConfiguration指定的值,并将这些值作为自动配置类导入到容器中,自动配置类就生效,帮助我们自动配置工作。

  • 总而言之,J2EE的整体整合解决方案和自动配置都在spring-boot-autoconfigure-1.5.9.RELEASE.jar中。

最新文章

  1. winform控件在Enable=false的情况下改变它的字体颜色
  2. asp.net mvc 模型验证注解,表单提交
  3. (转)整体把握jQuery -jQuery 的原型关系图
  4. Windows Server 2008下asp+access无法登陆问题总结
  5. 网页闯关游戏(riddle webgame)--仿微信聊天的前端页面设计和难点
  6. jni
  7. Oracle 导入导出数据 imp/exp impdp/expdp
  8. char *a 与char a[] 的区别
  9. mysql学习笔记--第1天
  10. [iOS]C语言技术视频-15-指针变量高级用法练习一(函数指针完成动态排序)
  11. jQuery中的attr()和prop()使用
  12. SAP HANA中的SLT简介
  13. iOS屏幕适配-iOS笔记
  14. ps命令手册
  15. C/C++与C#之间类型的对应
  16. CRM/PLM/SCM/MES与ERP的联系与区别
  17. vhdl 边沿
  18. semantic ui框架学习笔记二
  19. spark组件笔记
  20. vue-cli 3.0 axios 跨域请求代理配置及生产环境 baseUrl 配置

热门文章

  1. python 生成excel,并下载到本地
  2. 分期花呗 账户交易通知:尾号6932客户,您的申请已通过,账户余额38139元,无手续费,点t.cn/Aijsx9vq取款,回T退订。
  3. Linq之旅:Linq入门详解(Linq to Objects)(转)
  4. 做筛选遍历时遇到的json字符串、json对象、json数组 三者之间的转换问题
  5. LeetCode.1047-重复删除字符串中的所有相邻重复项
  6. Layer 弹出层抖动问题
  7. 使用ocelot作为api网关
  8. Angular5 父组件获取子组件实例( ViewChildren、ViewChild用法)
  9. ansible-playbook 案例
  10. Python 类的私有属性与私有方法