SpringBoot学习(一)第一个SpringBoot项目

SpringBoot简介

Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而不再需要定义样板化的配置。

SpringBoot优点有哪些?

在以往搭建一个Spring Web项目,都需要经过一下流程:

  • 配置web.xml,加载Spring、SpringMVC
  • 配置数据库、配置Spring事务
  • 配置加载配置文件的读取,开启注解
  • 配置日志文件
  • ...
  • 部署Tomcat调试

从上面的步骤可以看出,要搭建一个Spring Web项目步骤非常繁琐,在使用Spring Boot,仅仅需要将需要的依赖放入,以及非常少的配置便可以搭建一个Web项目,也就是说,Spring Boot的优点简单解释如下:

  • 快速搭建项目,极大地提高了开发、部署效率。

  • 对xml配置没有要求。

  • 内嵌servlet容器,无需部署。

  • 提供starter简化maven配置。

SpringBoot快速入门

Spring官方推荐使用Spring Initializr来创建Maven项目,通过这种方式创建的Maven项目,已经帮生成了启动类和单元测试模块,并且能很好支持IDE,给开发者带来极大的便利。

1)项目搭建

1590643209520

1590643221222

1590643236781

1590647052789

点击Finish,Idea会自动下载项目所需要的依赖,创建好的项目结构如下所示:

1590647189326

2)项目文件说明

  • src
    • main
      • java(项目Java代码在这里编写)
      • resource(静态资源、配置类文件夹)
        • static(存放静态资源,例如css、js等)
        • templat(存放html模板等)
        • application.properties(spring boot核心配置文件)
      • test(用于测试)
      • pom.xml(Maven构建说明文件)

3)测试

编写一个helloController.java,测试项目能否运行。

HelloController.java

@RestController
public class HelloController {
    @GetMapping("helloSpringBoot")
    public String helloSpringBoot() {
        return "Hello,Spring Boot!";
    }
}

运行结果:

1590650604374

SpringBoot项目解析

1)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 https://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.3.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

首先,是 标签,这个是Spring Boot的父级依赖,通过添加这个依赖,可以将项目创建为Spring Boot项目,其中,spring-boot-starter-parent提供了相关Maven的默认依赖。

在pom.xml文件中,有两个核心的模块,一个是spring-boot-starter,另一个是spring-boot-starter-test,在这里由于引入了Spring Web,因此spring-boot-starter变成spring-boot-starter-web,点进spring-boot-starter-web,可以看到其实它是依赖于spring-boot-starter的。

1590651175106

除此之外,另一个核心模块spring-boot-starter-test,这个是测试模块,包括了junit、hamcrest、mockito等等。

1590651354607

2)DemoApplication.java解析

DemoApplication.java是Spring Boot项目的启动类:

@SpringBootApplication
public class DemoApplication {

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

}

该启动类含有一个注解,@SpringBootApplication,该注解是Spring Boot项目的核心注解,打开这个注解,可以看到该注解又包含了三个比较重要的注解:

1590651772638

  • SpringBootConfiguration:继承@Configuration,标注当前类为配置类。
  • EnableAutoConfiguration:启用Spring自动加载配置。
  • ComponentScan:用于类或接口上主要是指定扫描路径。

@EnableAutoConfiguration原理分析

像上面所说,@EnableAutoConfiguration的作用就是启用Spring自动加载配置,Spring Boot一个最大的优点便是节省了开发者的配置时间,那么,@EnableAutoConfiguration又是如何实现自动配置?

面试题:SpringBoot自动配置的原理是什么?

打开@EnableAutoConfiguration,可以看到如下代码:

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
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

从上面的代码中,我们可以看到一个注解@Import,在这个注解中导入了一个类,AutoConfigurationImportSelector,而自动注入配置的功能就是依赖于这个对象。

点进这个类中,可以找到一个getCandidateConfigurations()方法,如下所示:

    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        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;
    }

从这里可以看到是使用了Spring中的工具类SpringFactories中的loadFactoryNames()方法来加载配置文件,扫描的路径是 META-INF/spring.factories。

1590656518223

    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 {
                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);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
                        String factoryTypeName = ((String)entry.getKey()).trim();
                        String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        int var10 = var9.length;

                        for(int var11 = 0; var11 < var10; ++var11) {
                            String factoryImplementationName = var9[var11];
                            result.add(factoryTypeName, factoryImplementationName.trim());
                        }
                    }
                }

                cache.put(classLoader, result);
                return result;
            } catch (IOException var13) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
            }
        }
    }

在SpringFactoriesLoader这个类中有一个loadSpringFactories()的方法,该方法返回了一个数据结构是map类型的result,而这个result实际上就是META-INF/spring.factories对应的Map数据结构,这个Map保存了整个Spring中配置类的全类名,获取到对应类的全名的第一步,就是加载一个类,而具体加载方式由SpringBootApplication完成,这里不仔细介绍。

在spring.factories中可以看到如下内容:

1590657068316

随便点开一个配置类看看里面的内容:

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnProperty(
    prefix = "spring.aop",
    name = {"auto"},
    havingValue = "true",
    matchIfMissing = true
)
public class AopAutoConfiguration {

其中,@ConditionalOnProperty作用是从spring的配置中加载指定前缀的配置,并自动设置到对应的成员变量上。也正是通过这种方式,真正实现了配置的自动注入。

总结:

@EnableAutoConfiguration的流程大致是:

@EnableAutoConfiguration->AutoConfigurationImportSelector->spring.factories->EnableAutoConfiguration->AopAutoConfiguration(具体的配置类)->@EnableConfigurationProperties->AopProperties(具体的配置类)->@ConditionalOnProperty(prefix = "spring.aop")

3)HelloController.java解析

@RestController
public class HelloController {
    @GetMapping("helloSpringBoot")
    public String helloSpringBoot() {
        return "Hello,Spring Boot!";
    }
}

@RestController注解等价于@Controller+@ResponseBody的结合,使用这个注解的类里面的方法都以json格式输出。

猜你喜欢

转载自www.cnblogs.com/isKylin/p/12984633.html