• SpringBoot——入门及原理


    SpringBoot用来简化Spring应用开发,约定大于配置,去繁从简,是由Pivotal团队提供的全新框架。其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置(有特殊需求可以添加自己的配置覆盖默认配置),从而使开发人员不再需要定义样板化的配置。SpringBoot可以看成是J2EE的一站式解决方案。

    一、SpringBoot 的优点

    【1】快速创建独立运行的Spring项目以及与主流框架集成。
    【2】使用嵌入式的Servlet容器,应用无需打成war包,可以打成jar包,通过java -jar的方式直接运行。
    【3】starters(启动器)自动依赖与版本控制。
    【4】大量的自动配置,简化开发,也可以修改默认值。
    【5】无需配置XML,无代码生成,开箱即用。
    【6】准生产环境的运行时应用监控。
    【7】与云计算的天然集成。

    二、解决微服务部署和运维难的问题:Spring Boot

     如上的流程依次为: 搭建项目 构建连接 批处理

    三、Spring Boot 入门项目

    HelloWorld(也可以参考五,快速创建一个 SpringBoot项目)

    【1】准备环境:Mavensettings.xml配置文件的profiles标签添加如下信息:

    <profile>
    <id>jdk-1.8id>
    <activation>
        <activeByDefault>trueactiveByDefault>
        <jdk>1.8jdk>
    activation>
    <properties>
        <maven.compiler.source>1.8maven.compiler.source>
        <maven.compiler.target>1.8maven.compiler.target>
        <maven.compiler.compilerVersion>1.8maven.compiler.compilerVersion>
    properties>
    profile>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    【2】将IDEAMaven更换为我们自己本地安装的Maven。(自行百度更换)创建一个maven工程[jar],在pom.xml中导入如下依赖:

    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.0.0.RELEASEversion>
    parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    【3】编写一个主程序,启动SpringBoot应用

    @SpringBootApplication
    public class Hello {
       public static void main(String[] args) throws Exception {
           //启动spring应用
           SpringApplication.run(Hello.class, args);
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    【4】编写相关的ControllerService

    @Controller
    public class HelloController {
       @ResponseBody
       @RequestMapping("/hello")
       public String hello(){
           return "hello world!";
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    【5】运行主测试程序。简化部署应用<可以将应用打包成一个可执行的jar包>:通过Maven Projects中 的package(双击)即可。生成jar的位置:默认在项目的target目录下的“项目名称.jar”文件。运行jar:在命令行可以通过 “java -jar jar文件名.jar” 命令运行项目。

    <build>
       <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
       plugins>
    build>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    四、Hello World 探究(POM文件)

    【1】父项目[spring-boot-starter-parent]:

    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.0.0.RELEASEversion>
    parent>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    【2】进入spring-boot-starter-parent发现它还有一个父项目 :

    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-dependenciesartifactId>
        <version>2.0.0.RELEASEversion>
        <relativePath>../../spring-boot-dependenciesrelativePath>
    parent>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    【3】进入spring-boot-dependencies后,发现如下信息,与之前我们创建的分布式项目继承的Maven父项目功能是一样的,用来管理所有jar包依赖的版本。称为SpringBoot的版本仲裁中心,以后我们导入依赖默认是不需要写版本;(没有在dependencies里面管理的依赖,需要声明版本号)

    <properties>
        <activemq.version>5.15.3activemq.version>
        <antlr2.version>2.7.7antlr2.version>
        <appengine-sdk.version>1.9.62appengine-sdk.version>
        <artemis.version>2.4.0artemis.version>
        <aspectj.version>1.8.13aspectj.version>
        <assertj.version>3.9.1assertj.version>
        <... 此处省略 .../>
    properties>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    【4】启动器[spring-boot-starter-web]

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4

    spring-boot-starter-webspring-boot-starterspring-boot场景启动器;进入官网可以到有许多场景启动器,简单点说就是通过此功能将相关jar包给组合在起来,我们使用时只需要引入一个Web Starter就可以轻松搞定。Spring Boot将所有的功能场景都抽取出来,做成一个个的 starters(启动器),只需要在项目里面引入这些starter相关场景,所有依赖都会导入进来。要用什么功能就导入什么场景启动器。

    点击web右边的pom可以看到SpringBoot为我们依赖的其它jar包,帮我们导入了web模块正常运行所依赖的所有组件。如下:

    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starterartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-tomcatartifactId>
        dependency>
        <dependency>
            <groupId>org.hibernategroupId>
            <artifactId>hibernate-validatorartifactId>
        dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.coregroupId>
            <artifactId>jackson-databindartifactId>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-webartifactId>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-webmvcartifactId>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    【5】主程序类(Java类):@SpringBootApplication:此注解声明的类,是SpringBoot的主配置类,SpringBoot就应该运行这个类的main方法来启动SpringBoot

    //@ImportResource(locations={"classpath:bean.xml"})
    //@SpringBootApplication 来标注一个主程序类,说明这是一个SpringBoot应用
    @SpringBootApplication
    public class HellowordQuickStartApplication {
    
        public static void main(String[] args) {
            /*SpringBoot应用启动项
            HellowordQuickStartApplication.class 参数必须是用@SpringBootApplication注解修饰的类
            */
            SpringApplication.run(HellowordQuickStartApplication.class, args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    @SpringBootApplication(主要由:@SpringBootConfiguration/@EnableAutoConfiguration/@ComponentScan组成)

    @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 {
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    @SpringBootConfiguration:标注在某个类上,表示此类是一个SpringBoot的配置类。由以下注解组合形成:配置类 == 配置文件,配置类也是容器的一个组件,底层由@Component等等组成。

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Configuration //表示此类是一个配置类  是spring的一个组件
    public @interface SpringBootConfiguration {
    
    • 1
    • 2
    • 3
    • 4
    • 5

    @EnableAutoConfiguration:开启自动配置功能。也是一个组合注解,由以下注解组成(部分重要注解):

    @AutoConfigurationPackage
    @Import(AutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {
    
    • 1
    • 2
    • 3

    @AutoConfigurationPackage:自动依赖相关的配置包,也是一个组合注解,主要由@import等注解组合

    @Import({Registrar.class})//给容器中导入一个组件;导入的组件由此组建决定。
    public @interface AutoConfigurationPackage {
    
    • 1
    • 2

    进入@Import(Registrar.class)中的Registrar类中,通过断点,可以查看到我注释的一些信息。

    static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
        Registrar() {
        }
        //registerBeanDefinitions方法中的metadata可以查看到我们启动类使用的注解 @SpringBootApplication
        public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            AutoConfigurationPackages.register(registry, new String[]{(new AutoConfigurationPackages.PackageImport(metadata)).getPackageName()});
        }
        //new AutoConfigurationPackages.PackageImport(metadata) 可以解析出我们当前主启动所在的package包
        public Set<Object> determineImports(AnnotationMetadata metadata) {
            return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    @Import(Registrar.class)作用:将主配置类的所在包以及下边所有子包里面的所有组件扫描到Spring容器中。这也就能理解为什么会自动扫描我们写的@Controller类了。

    @Import(AutoConfigurationImportSelector.class):进入AutoConfigurationImportSelector.class类中,查看如下方法:

    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if(!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            try {
                AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
                AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
                // 主要用到的是 这个 configurations 后面会有重点说明
                List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
                configurations = this.removeDuplicates(configurations);
                configurations = this.sort(configurations, autoConfigurationMetadata);
                Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
                this.checkExcludedClasses(configurations, exclusions);
                configurations.removeAll(exclusions);
                configurations = this.filter(configurations, autoConfigurationMetadata);
                this.fireAutoConfigurationImportEvents(configurations, exclusions);
                return StringUtils.toStringArray(configurations);
            } catch (IOException var6) {
                throw new IllegalStateException(var6);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    这是导入组件的选择器方法,将所有需要导入的组件以全类名的方式返回,这些组件最终被添加到容器中。其中List configurations会给容器中导入非常多的自动配置类[xxxAutoConfiguration],就是给容器中导入这个场景需要的所有组件,并配置好这些组件。有了自动配置类,免去了我们手动编写配置注入功能组件等的工作;自动配置类共109个,如下部分所示:

    ☹ 那么我们就有疑问,这些自动配置类都是从哪里来的?
    进入这个方法:this.getCandidateConfigurations(annotationMetadata, attributes)

    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        // *** 后边需要了解的方法 ***
        //SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,classLoader);
        List<String> 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    进入SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,classLoader)方法,具体注释说明:

    public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
        //org.springframework.context.ApplicationContextInitializer
        String factoryClassName = factoryClass.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }
    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if(result != null) {
            return result;
        } else {
            try {
                //通过类加载器(classLoader获取)META-INF/spring.factories(也就是配置了109个自动配置类的文件) 资源
                Enumeration<URL> urls = classLoader != null?classLoader.getResources("META-INF/spring.factories"):ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();
    
                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    //将urls 当做一个properties配置文件
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();
    
                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
                        //将META-INF/spring.factories文件中的EnableAutoConfiguration下的配置进行加载   如下图所示
                        List<String> factoryClassNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray((String)entry.getValue()));
                        result.addAll((String)entry.getKey(), factoryClassNames);
                    }
                }
    
                cache.put(classLoader, result);
                return result;
            } catch (IOException var9) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var9);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    我们进入其中一个自动配置类中看看SpringBoot是不是真的帮我们已经配置好了一些属性[WebMvcAutoConfiguration]:

    //这里我就摘出一些重要的配置,来帮我我们观察即可。
    @Configuration
    public class WebMvcAutoConfiguration {
        @Bean
        @ConditionalOnMissingBean
        /** 视图解析器 , SpringBoot中的所有配置文件都是.java形式,方法的名字,就是以前xml中的id。
            等等都是用注解表示的,这个我们后面会重点说明,这里就先了解一下*/
        //我们可以看到SpringBoot已经帮我们配置好了视图解析器 等等一些功能 我们直接使用就好
        public InternalResourceViewResolver defaultViewResolver() {
            InternalResourceViewResolver resolver = new InternalResourceViewResolver();
            resolver.setPrefix(this.mvcProperties.getView().getPrefix());
            resolver.setSuffix(this.mvcProperties.getView().getSuffix());
            return resolver;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    总结: SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作。如此一来,就具有我们在SSM等环境下写了一大堆配置文件后才具有的功能。而这些所有配置文件都在spring-boot-autoconfigure-2.0.0.RELEASE.jar 中。

    五、使用 Spring Initializer 快速创建 Spring Boot 项目

    注意:Artifact中不能大小写混合使用。

    通过需求选择starts,例如选择Web

    我们就会发现pom.xml文件中,就会自动配置了我们引入的starts

    
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.0.0.RELEASEversion>
        <relativePath/> 
    parent>
    
    <properties>
        <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
        <java.version>1.8java.version>
    properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
    
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
    
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-configuration-processorartifactId>
            <optional>trueoptional>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    添加controller层: 新注解@RestController == @ResponseBody@Controller的合体;

    //这个类的所有方法返回的数据直接写给浏览器(如果是对象转为JSON)
    //@ResponseBody@Controller
    @RestController
    public class HelloWordController {
        @RequestMapping("/hello")
        public String hello(){
            return "hell";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    优点: 默认生成的SpringBoot项目,我们只需要编写自己的逻辑。默认生成的Resources配置文件的目录结构:
    【1】static:保存所有的静态资源。 [js/css/image]
    【2】templates:保存所有的模板页面[SpringBoot默认jar包使用嵌入式的 Tomcat,默认不支持JSP页面]但可以使用模板引擎。(freemarkerthymeleaf
    【3】application.propertiesSpringBoot应用的配置文件。默认的配置都在此文件可以修改。

  • 相关阅读:
    Django项目实现对外POST接口
    数据库——集群与读写分离 <--->设计优化【补】
    eigen C++报错 EIGEN_STATIC_ASSERT
    2020 MIT6.s081 Lab Locks
    深度学习图像分割标签onehot
    打击勒索病毒:防御.kat6.l6st6r勒索病毒的最佳策略
    Allegro172版本Shape避让方形盘不出现弧形操作指导
    神经网络初始化实例化的维度与调用输入数据的维度
    labview技术交流-判断两个数组的元素是否完全相同
    CVPR 2022 Best Paper -- Learning to Solve Hard Minimal Problems
  • 原文地址:https://blog.csdn.net/zhengzhaoyang122/article/details/134494028