如何搭建SpringBoot项目

如何搭建一个SpringBoot项目

 

步骤

1、创建一个普通maven项目:SpringBootDemo

2、在pom.xml文件设置项目打包方式

<packaging>jar</packaging>

3、在pom.xml文件导入SpringBoot父项目

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.3</version>
    <relativePath/>
</parent>

4、在pom.xml文件导入Web项目依赖

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

5、编写普通Controller类

/**
 * 控制层
 */
@Controller
public class HelloController {
    @RequestMapping("hello")
    public Object hellp(){
        return "Hello SpringBoot!";
    }
}

6、编写启动类,启动SpringBoot项目

/**
 * SpringBoot项目启动类
 */
@SpringBootApplication
public class SpringBootDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootDemoApplication.class,args);
    }
}

7、浏览器访问测试: http://localhost:8080/hello

问题

  1. Web打包不应该是war,为什么是jar?

  2. pom.xml文件中继承的spring-boot-starter-parent有什么用?

  3. pom.xml文件中导入的依赖spring-boot-starter-web又有什么用?

  4. 启动类SpringBootDemoApplication头顶上的@SpringBootApplication注解做了什么?

  5. 没有配置tomcat,没有设置端口服务器怎么来,又怎么启动的?

  6. main方法中SpringApplication.run(..)又是什么情况?

分析

问题1:Web打包不应该是war,为什么是jar

SpringBoot默认的打包方式就是jar,传统的外接tomcat或插件式tomcat与web项目是相互独立,相互对接时必须满足一定规则,war包结构项目就是规则约定之一。而SpringBoot项目采用的是内嵌式(简单理解为编码方式)tomcat,项目与tomcat融为一体,部署,启动,运行一体化,就没有各种条条框框的约束了。

问题2:pom.xml文件中继承的spring-boot-starter-parent有啥用

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.3</version>
    <relativePath/>
</parent>

spring-boot-starter-parent其实是SpringBoot提供了工具工程,工程收集了市面上常用各种第三方jar依赖,并对这些jar依赖进行了版本管理。当我们的项目继承这个项目工程,就自动成为SpringBoot项目,并无偿继承了这些第三方jar依赖。后续项目中需要某个第三方依赖,只需要引入依赖坐标即可, 不需要关系依赖版本。比如:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

一个拓展:

继承是 Maven 中很强大的一种功能,继承可以使得子POM可以获得 parent 中的部分配置(groupId,version,dependencies,build,dependencyManagement等),可以对子pom进行统一的配置和依赖管理。

  • parent项目中的dependencyManagement里的声明的依赖 , 只具有声明的作用,并不实现引入,因此子项目需要显式的声明需要用的依赖。如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,可以不指定具体版本,会从父项目中继承该项,并且version和scope都读取自父pom;另外如果子项目中指定了版本号,那么会使用子项目中指定的jar版本

  • parent项目中的dependencies里声明的依赖会被所有的子项目继承

问题3:pom.xml文件中导入的依赖spring-boot-starter-web又有啥用

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

问题2中说了,SpringBoot收集了很多常用的第三方jar依赖,为了进一步提高用户体验感,SpringBoot根据jar依赖特点,对这些依赖进一步分类,整合,再封装,形成一个新的依赖工具集, 每个工具集都解决特定领域的依赖问题。SpringBoot将这些依赖工具称为:启动器(组件),命名规则: spring-boot-starter-xxx。 如果是非SpringBoot定制的启动器, 一般命名规则:xxx-spring-boot-starter

入门案例中导入的spring-boot-starter-web 就是用于解决web项目依赖的工具集(启动器)

常用的启动器(starter)还有很多:

spring-boot-starter: 核心启动器 , 提供了自动配置,日志和YAML配置支持

spring-boot-starter-aop: 支持使用 Spring AOPAspectJ 进行切面编程。

spring-boot-starter-freemarker: 支持使用 FreeMarker 视图构建Web 应用

spring-boot-starter-test: 支持使用 JUnit, 测试 Spring Boot 应用

spring-boot-starter-web: 支持使用 Spring MVC 构建 Web 应用,包括 RESTful 应用,使用 Tomcat 作为默认的嵌入式容器。

spring-boot-starter-actuator: 支持使用 Spring Boot Actuator 提供生产级别的应用程序监控和管理功能。

spring-boot-starter-logging: 提供了对日志的支持 , 默认使用Logback

问题4:启动类App头顶上的@SpringBootApplication注解做了什么

要回答这个问题, 就必须讲清楚springboot的自动配置原理(也称自动装配)

springboot的精髓就在这个注解里。

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

先回顾一下以前使用SpringMVC搭建web项目时, 我们是怎么做的

1>导入Web, Spring, SpringMVC依赖

2>在web.xml文件配置前端控制器:DispatcherServlet

3>编写controller类

4>配置controller扫描包路径

5>部署到tomcat并启动

从上面步骤上看,刚刚入门案例不需要我们去做的有几步?

1:不需要配置前端控制器

2:不需要配置包扫描路径

3:不需要部署tomcat这步

这些步骤我们都没做,项目却跑起来,那肯定有人帮我们做了,那会是谁?所有问题关键就是这个:@SpringBootApplication注解。

@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 {
    ......
}

注解上面又有一堆注解,核心的有3个:

  • @SpringBootConfiguration

  • @EnableAutoConfiguration

  • @ComponentScan

这里注意:注解头顶又贴有注解(非元注解),表示当前注解为复合注解,当前注解也拥有所贴注解功能。

@ComponentScan

功能:spring组件扫描注解,扫描所贴的类所在包及其子包所有贴有版型注解的类,并创建对象交给spring容器管理。

入门案例中, 我们将@SpringBootApplication 注解贴在App类里面,那么它会扫描App类所有包及其子包里面所有贴有版型注解的类,并创建实例, 那么controller包下的HelloController类就可以被扫描到。

一个注意点: 一般贴有@SpringBootApplication注解的类称之为启动类,建议放置在根包下。

@SpringBootConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
    ....
}

该注解头顶贴了@Configuration注解, 前面Javaconfig讲过贴有@Configuration类为配置类

@SpringBootApplication   头顶贴有  @SpringBootConfiguration  
@SpringBootConfiguration 头顶贴有  @Configuration        

根据上面注解关系推导下:入门案例中贴有@SpringBootApplication注解的App类就是一个项目配置类。

一个注意点:一般springboot项目只有唯一一个启动类,启动类都是配置类。

@EnableAutoConfiguration

@EnableAutoConfiguration的作用,告诉SpringBoot基于你所添加的依赖,去“猜测”你想要如何配置Spring。比如当我们引入了spring-boot-starter-web这个启动器,spring会解析这个启动器,推测当前项目为web项目,根据启动器默认配置要求自动配置web及SpringMVC相关对象创建与管理。比如:前端控制的创建,比如前端控制的路径映射等。

SpringBoot对自带启动器与第三方启动器进行了大量的默认配置,这些配置是否生效,是否加载到spring容器中使用,取决于我们项目是否引入了对启动器依赖,如果有那么默认配置就会生效。

那么

  • 这些默认配置是在哪里定义的呢?

  • 为何依赖引入就会触发配置生效呢?

看源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    ...
}

@EnableAutoConfiguration注解import导入了一个AutoConfigurationImportSelector自动配置类选择器,该类可以实现配置类批量载入 spring容器。其核心方法是getCandidateConfigurations

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;
}

getCandidateConfigurations方法作用是委托SpringFactoriesLoader去读取jar包中的META-INF/spring.factories文件, 并加载里面配置的自动配置对象,其中包括: AOP / PropertyPlaceholder / FreeMarker / HttpMessageConverter / Jackson / DataSource / DataSourceTransactionManager / DispatcherServlet / WebMvc 等等。

一个注意点:不管是spring定制的启动器,还是第三方定制的启动器,都需要编写META-INF/spring.factories,里面指定启动器的自动配置类

接上面分析, spring.factories文件中配置很多自动配置类,哪些会生效(加载到Spring容器并跑起来)呢, 此时需要满足这些启动类生效条件才会自动装配。

以我们熟悉SpringMVC为例子:

在spring.factories找WebMvcAutoConfiguration自动配置类

org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration

点进去看源码

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ 
        DispatcherServletAutoConfiguration.class, 
        TaskExecutionAutoConfiguration.class,
        ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
    ...
}

我们看到这个类上的4个注解:

  • @Configuration:声明这个类是一个配置类

  • @ConditionalOnWebApplication(type = Type.SERVLET)

    ConditionalOn,翻译就是在某个条件下,此处就是满足项目的类是是Type.SERVLET类型,我们现在的项目就满足了, 就是一个web服务(web项目)

  • @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })

    这里的条件是OnClass,也就是满足以下类存在:Servlet、DispatcherServlet、WebMvcConfigurer。这里就是判断你是否引入了SpringMVC相关依赖,引入依赖后该条件成立,当前类的配置才会生效!

  • @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)

    这个条件与上面不同,OnMissingBean,是说环境中没有指定的Bean这个才生效。其实这就是自定义配置的入口,也就是说,如果我们自己配置了一个WebMVCConfigurationSupport的bean, 代表容器里已经存在该bean了,那么这个默认配置就会失效!这里允许我们定制自己的bean替换spring默认的。

接着,我们查看WebMvcAutoConfiguration该类中定义了什么:(如果它生效了,会创建什么对象并载入容器进行管理)

视图解析器:

@Bean
@ConditionalOnMissingBean
public InternalResourceViewResolver defaultViewResolver() {
   InternalResourceViewResolver resolver = new InternalResourceViewResolver();
   resolver.setPrefix(this.mvcProperties.getView().getPrefix());
   resolver.setSuffix(this.mvcProperties.getView().getSuffix());
   return resolver;
}
​
@Bean
@ConditionalOnBean(View.class)
@ConditionalOnMissingBean
public BeanNameViewResolver beanNameViewResolver() {
   BeanNameViewResolver resolver = new BeanNameViewResolver();
   resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);
   return resolver;
}

WebMvcAutoConfiguration中使用了@AutoConfigureAfter注解, 意为指定的类加载完了后,再加载本类

@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class })

而DispatcherServletAutoConfiguration中又做了很多事情, 比如配置了前端控制器

@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
    DispatcherServlet dispatcherServlet = new DispatcherServlet();
    dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
    dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
    dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.
                                                        isThrowExceptionIfNoHandlerFound());
    dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
    dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());
    return dispatcherServlet;
}

总结:

@SpringBootApplication注解内部是3大注解功能的集成

  • @ComponentScan: 开启组件扫描

  • @SpringBootConfiguration: 作用等同于@Configuration注解,也是用于标记配置类

  • @EnableAutoConfiguration: 内部导入AutoConfigurationImportSelector,该类中有个getCandidateConfigurations方法, 读取jar包中META-INF/spring.factories文件中配置类, , 再根据条件进行加载和配置, 比如: AOP / PropertyPlaceholder / FreeMarker / HttpMessageConverter / Jackson / DataSource / DataSourceTransactionManager / DispatcherServlet / WebMvc 等等

问题5:没有配置tomcat,没有设置端口服务器怎么来,又怎么启动的

SpringBoot使用嵌入式tomcat,编程实现,默认端口是8080,后续可以通过application.properties文件进行修改

问题6:main方法中SpringApplication.run(..)又是什么情况

SpringApplication.run(..)的作用:

  • 启动SpringBoot应用

  • 加载自定义的配置类,完成自动配置功能

  • 把当前项目部署到嵌入的Tomcat服务器

  • 启动Tomcat服务器跑项目

总结

SpringBoot项目完整结构

SpringBoot优缺点

优点:

  1. 创建独立运行的Spring应用程序 ;

  2. 嵌入的Tomcat,无需部署war文件;

  3. 简化Maven配置 ;

  4. 自动配置Spring ;

  5. 提供生产就绪型功能,如:日志,健康检查和外部配置等;

  6. 不要求配置 XML;

  7. 非常容易和第三方框架集成起来。

缺点:

  1. 版本更新较快,可能出现较大变化;

  2. 因为约定大于配置,所以经常会出现一些很难解决的问题。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半晴Miko

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值