从零开始学习 Spring Boot

SpringBoot基础

概述

SpringBoot是Spring提供的一个子项目,用于快速构建Spring应用程序。

SpringBoot特性

1.起步依赖

本质上就是一个Maven坐标,整合了完成一个功能需要的所有坐标。就是通过一个依赖,可以代替所有所需的依赖。

2.自动配置

遵循约定大于配置的原则,在boot程序启动后,一些bean对象会自动注入到ioc容器,不需要手动声明,简化开发。

3.其他特性

内嵌Tomcat、Jetty

外部化配置

不需要XML配置(properties/yml)

SpringBoot入门

案例需求:

使用SpringBoot开发一个web应用,浏览器发起请求/hello后,给浏览器返回字符串"hello world ~"

过程

  1. 创建Maven工程
  2. 导入spring-boot-stater-web起步依赖
  3. 编写Controller
@RestControllerpublic class HelloController {    @RequestMapping("/hello")    public String hello() {        System.out.println("Hello World ~");        return "Hello World ~";    }}
  1. 提供启动类

手动创建SpringBoot工程

  1. 创建Maven工程
  2. 引入依赖
  3. 提供启动类

配置文件

properties配置文件 (application.properties)

springboot的所有配置文件的位置:

https://docs.spring.io/spring-boot/appendix/application-properties/index.html

properties配置文件中内容的格式

spring.application.name=demo1server.port=9090server.servlet.context-path=/start1

yml配置文件(application.yml)

yml使用方式:

书写三方技术配置信息,书写自定义配置信息

yml的配置信息书写:

值前面必须有空格,作为分隔符

使用空格作为缩进表示层级关系,相同的层级左侧对齐

#发件人的相关信息email:  user: "**********"  code: "afdas"  host:  faff.com  auth: true

yml的配置信息获取:

使用@Value("${键名}")

public class EmailPerperties{ @Value("${email.user}") public String user;}

使用@ConfigrationPropperties(prefix="前缀"),但要保证实体类的成员变量名与配置文件中的键名保持一致。

整合MyBatis

导入MyBatis的起步依赖和mysql的依赖

<dependency>            <groupId>com.mysql</groupId>            <artifactId>mysql-connector-j</artifactId>            <version>8.0.33</version>        </dependency>        <dependency>            <groupId>org.mybatis.spring.boot</groupId>            <artifactId>mybatis-spring-boot-starter</artifactId>            <version>3.0.3</version>        </dependency>

编写application.yml配置信息

spring:  datasource:    driver-class-name: com.mysql.cj.jdbc.Driver    url: jdbc:mysql://localhost:3306/mybatis?useSSL=false&serverTimezone=UTC    username: root    password: 123456

业务代码的实现

Bean对象管理

1.Bean扫描

SpringBoot默认扫描启动类所在的包及其子包;

其他的Bean,可以用@ComponentScan(basePackages="org.example")即可将该包下及其子包所需的Bean注册到ioc容器中

2.Bean注册

相关注解

@Component 声明bean的基础注解

@Controller @Component的衍生注解,标注在控制器类上

@Serivce @Component的衍生注解,标注在业务类上

@Repository @Component的衍生注解,标注在数据访问类上 (由于与mybatis整合,用的少)

关于三方jar包中的类对应的Bean,使用@Bean和Import

@Bean

在启动类或者配置类(@Configuration)中创建一个方法,在该方法里创建一个对象。在该方法上注解一个@Bean就可以了。

如果方法内部需要使用到ioc容器中已经存在的bean对象,那么只需要在方法上声明即可,spring会自动的注入。

@Import

一般导入配置类或导入ImportSelector接口实现类

可以通过一个配置类,在配置类中创建方法,在方法内部创建多个类的多个Bean。之后在启动类上加一个@Import(配置类的class)

@Import(CommonConfig.class)

可以通过ImportSelector接口实现类,在重写的方法中加入多个配置类的全限定名,之后在启动类上加一个@Import(该类的class),之后就能导入配置类,导入配置类中的多个Bean。

@Import(CommonImportSelector.class)public class CommonImportSelector implements ImportSelector {    @Override    public String[] selectImports(AnnotationMetadata importingClassMetadata) {        List<String> imports = new ArrayList<>();        InputStream res = CommonImportSelector.class.getClassLoader().getResourceAsStream("common.imports");        /*````````*/        BufferedReader br = new BufferedReader(new InputStreamReader(res));        String line=null;        try {            while((line=br.readLine())!=null){                imports.add(line);            }        } catch (IOException e) {            throw new RuntimeException(e);        } finally {            if (br != null) {                try {                    br.close();                } catch (IOException e) {                    throw new RuntimeException(e);                }            }        }        /*````````*/        return imports.toArray(new String[0]);    }}

可以自定义注解,封装@Import注解

@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Import(CommonImportSelector.class)public @interface EnableCommonConfig {}

3.注册条件

关于Bean注册后所有属性字段为null问题,不能写死的话,可以通过配置信息获取,在application.yml中配置。

@Configurationpublic class CommonConfig {    @Bean    public Country country(@Value("${country.name}") String name, @Value("${country.system}") String system){        Country country = new Country();        country.setName(name);        country.setSystem(system);        return country;    }}

问题:

如果application.yml中配置所需信息就注入,没有就不注入,但是不能报错。

SpringBoot提供了设置注册生效条件的注解@Conditional,但是使用起来复杂,所以使用它的衍生注解

@ConditionalOnProperty

配置文件中存在对应的属性,才注入该bean;不存在就不注入

@Configuration
public class CommonConfig {    @ConditionalOnProperty(prefix = "country",name = {"name","system"})    @Bean    public Country country(@Value("${country.name}") String name, @Value("${country.system}") String system){        Country country = new Country();        country.setName(name);        country.setSystem(system);        return country;    }    @Bean    public Province province(){        return new Province();    }}
@ConditionalOnMissingGBean

当不存在当前类型的bean时,才注入该bean;如果不存在Country,就注入Province。

@ConditionalOnMissingBean(Country.class)    @Bean    public Province province(){        return new Province();    }
@ConditionalOnClass

当前环境存在指定的这个类时,才注入该bean

@ConditionalOnClass(name="org.springframework.web.servlet.DispatcherServlet")    @Bean    public Province province(){        return new Province();    }

自动配置

自动配置:

遵循约定大于配置的原则,在boot程序启动后,起步依赖中的一些bean对象会自动注入到ioc容器。

SpringBoot自动配置,提供一个自动配置类,把该类类名写到指定的配置文件中。

第三方jar包中的Bean自动配置

当Spring Boot应用程序启动时,Spring Boot会扫描并加载所有在.import文件中配置的自动配置类,而配置类被自动配置类用@Import导入,这样该配置类中的所有Bean对象根据条件都会被注入ioc容器中。

通过这种方式,Spring Boot在启动时会自动配置自动配置类,并通过@Import注解被动地导入配置类,从而将配置类中的Bean对象注入到Spring容器中。这种机制使得配置更加模块化和灵活,便于管理和复用。

  1. 有配置类CommonConfig,用来配置Bean对象
public class CommonConfig {    public CommonConfig() {    }    @ConditionalOnProperty(        prefix = "country",        name = {"name", "system"}    )    @Bean    public Country country(@Value("${country.name}") String name, @Value("${country.system}") String system) {        return new Country(name, system);    }    @Bean    public Province province() {        return new Province();    }}
  1. 有自动配置类,带2个注解@AutoConguration用来标识该类是自动配置的,
@Import(CommonConfig.class)导入配置类@AutoConfiguration@Import({CommonConfig.class})public class CommonAutoConfig {    public CommonAutoConfig() {    }}
  1. 有.import配置文件,在该文件中写入自动配置类的全限定名。
cn.itcast.config.CommonAutoConfig

SpringBoot自动配置原理

  • 在主启动类上添加了SpringBootApplication注解,这个注解组合了EableAutoConfiguration注解。
  • EnableAutoConfiguration注解又组合了AutoConfigurationImportSelector类
  • 实现selectImports方法,这个方法经过层层调用,最终会读取META-INF目录下的后缀名为.import文件(boot2.7以前版本读取的是spring.factories文件)
  • 读取到全类名了之后,就会解析注册条件,也就是@Conditional及其衍生注解把满足注册条件的Bean对象自动注册到ioc容器中。

自定义stater

在实际开发中,经常会定义一些组件,提供给各个项目团队使用。而在Spring Boot的项目中,一般会将这些公共组件封装为SpringBoot的starter。

起步依赖会由两个工程组成

xxx-autoconfigure:提供自动配置功能

xxx-starter:提供依赖管理功能

需求:自定义mybatis的starter

步骤:

1.创建 dmybatis-spring-boot-autoconfigure模块,提供自动配置功能,并自定义配置文件 META-INF/spring/xxx.imports
引入相关依赖
<dependencies>    <dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter</artifactId>      <version>3.3.4</version>    </dependency>    <dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter-data-jdbc</artifactId>      <version>3.3.1</version>    </dependency>    <dependency>      <groupId>org.mybatis</groupId>      <artifactId>mybatis</artifactId>      <version>3.5.14</version>    </dependency>    <dependency>      <groupId>org.mybatis</groupId>      <artifactId>mybatis-spring</artifactId>      <version>3.0.3</version>    </dependency>    <dependency>      <groupId>junit</groupId>      <artifactId>junit</artifactId>      <version>3.8.1</version>      <scope>test</scope>    </dependency>  </dependencies>
自动配置类Configure
@AutoConfiguration  //表示当前类是一个自动配置类public class MyBatisAutoConfig {    //SqlSessionFactoryBean    @Bean    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();        sqlSessionFactoryBean.setDataSource(dataSource);        return sqlSessionFactoryBean;    }    //MapperScannerConfigurer    @Bean    public MapperScannerConfigurer mapperScannerConfigurer(BeanFactory beanFactory) {        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();        //扫描的包:启动类所在的包及其子包        List<String> packages = AutoConfigurationPackages.get(beanFactory);        String p = packages.get(0);        mapperScannerConfigurer.setBasePackage(p);        //扫描的注解:        mapperScannerConfigurer.setAnnotationClass(Mapper.class);        return mapperScannerConfigurer;    }}
创建org.springframework.boot.autoconfigure.AutoConfiguration.imports文件

创建.imports文件导入自动配置类的全类名,文件所在位置

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

,不能变!!!

2.从创建dmybatis-spring-boot-starter 模块,在starter中引入自动配置模块

引入我们创建的autoconfigure

最好在引入dmybatis-spring-boot-autoconfigure所需的依赖

<dependencies>    <dependency>      <groupId>org.example</groupId>      <artifactId>dmybatis-spring-boot-autoconfigure</artifactId>      <version>1.0-SNAPSHOT</version>    </dependency>    <dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter</artifactId>      <version>3.3.4</version>    </dependency>    <dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter-data-jdbc</artifactId>      <version>3.3.1</version>    </dependency>    <dependency>      <groupId>org.mybatis</groupId>      <artifactId>mybatis</artifactId>      <version>3.5.14</version>    </dependency>    <dependency>      <groupId>org.mybatis</groupId>      <artifactId>mybatis-spring</artifactId>      <version>3.0.3</version>    </dependency>    <dependency>      <groupId>junit</groupId>      <artifactId>junit</artifactId>      <version>3.8.1</version>      <scope>test</scope>    </dependency>  </dependencies>
取代mybatis-spring-boot-starter成功!!!
<!--        <dependency>--><!--            <groupId>org.mybatis.spring.boot</groupId>--><!--            <artifactId>mybatis-spring-boot-starter</artifactId>--><!--            <version>3.0.3</version>--><!--        </dependency>-->        <!--   自定义的mybatis起步依赖     -->        <dependency>            <groupId>org.example</groupId>            <artifactId>dmybatis-spring-boot-starter</artifactId>            <version>1.0-SNAPSHOT</version>        </dependency>
注:

如果编译不成功,你的Maven工程可能默认是JDK5,太低不支持了,需要将所配置的dmybatis-spring-boot-autoconfigure和dmybatis-spring-boot-starter,这两个Maven项目中的pom文件中导入编译插件。

<build>    <plugins>      <plugin>        <groupId>org.apache.maven.plugins</groupId>        <artifactId>maven-compiler-plugin</artifactId>        <version>3.13.0</version>        <configuration>          <source>17</source>          <target>17</target>        </configuration>      </plugin>    </plugins>  </build>
#Java##SpringBoot##Java后端#
Java面试题 文章被收录于专栏

本专栏汇总了大量的Java面试题和Java面经,希望对大家有所帮助!

全部评论

相关推荐

-&nbsp;腾讯会议,没要求开视频##&nbsp;项目-&nbsp;没问项目,纯八股##&nbsp;八股-&nbsp;Mapreduce的工作原理&nbsp;&nbsp;-&nbsp;详细讲了三阶段-&nbsp;Zookeeper的选举原理&nbsp;&nbsp;-&nbsp;只讲了第一次启动,**忘了讲leader挂掉的情况**-&nbsp;Zookeeper一般用在哪里&nbsp;&nbsp;-&nbsp;HA,zookeeper负责监控HA里多个NN的情况(**ZKFC转换NN状态**),一旦NN发生故障,要启动自动故障转移,避免HA出现脑裂情况-&nbsp;HDFS读写流程-&nbsp;Spark算子&nbsp;&nbsp;-&nbsp;忘了讲两种算子的作用:&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;Transformation(转换算⼦,即从现有的数据集创建⼀个新的数据集)&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;Action(⾏动算⼦,即在数据集上进⾏计算后,返回⼀个值给&nbsp;Driver&nbsp;程序)&nbsp;&nbsp;-&nbsp;**还可以延申讲分别有哪些算子,自己用过的算子**-&nbsp;讲讲Spark的血缘关系&nbsp;&nbsp;-&nbsp;**讲血缘关系应该这样梳理**:&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;什么是血缘关系:依赖关系反映了&nbsp;RDD&nbsp;是如何从其他&nbsp;RDD&nbsp;转换而来的,而多个连续的&nbsp;RDD&nbsp;的依赖关系,称之为⾎缘关系&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;为什么要有血缘关系:每个&nbsp;RDD&nbsp;记录操作历史,可以根据依赖关系重计算丢失的分区;他是Spark&nbsp;实现容错和优化计算的重要基础,RDD的弹性一词的依仗也有他&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;怎么实现的重计算:往前找到宽依赖,宽依赖必有shuffle,有shuffle就有数据落盘,我们就可以避免从数据源开始重新执行计算(顺势提到宽窄依赖)&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;血缘关系中细分有哪两种:宽窄依赖,然后讲他们俩的区分(宽依赖的父RDD的一个分区的数据会被子RDD的多个分区所依赖,窄依赖的父RDD的一个分区只能被子RDD的一个分区依赖,这也导致窄依赖多分区可以并行计算,而宽依赖不行)&nbsp;&nbsp;-&nbsp;总结:血缘关系是Spark容错恢复的保障之一,也是优化计算的一种方式&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;有利于数据的重新分布和并⾏处理。通过宽依赖(本质上是通过shuffle),可以将数据按照特定的规则重新分配到不同的节点上进⾏处理,从⽽充分利⽤集群的计算资源。提⾼处理效率,具体而言是以下两点:&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;**满足特定计算需求**:在很多数据处理场景中,需要将具有相同特征的数据集中在一起进行处理。例如,在进行**分组聚合操作**时,需要将相同键的数据分到同一个分区,以便在每个分区内进行聚合计算。宽依赖通过&nbsp;Shuffle&nbsp;操作可以实现这种数据的重新分布,将分散在不同节点上的相同键的数据收集到一起,为后续的计算提供便利。&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;**优化数据布局(负载均衡)**:通过重新分布数据,可以使数据在集群中的分布更加均衡,避免某些节点负载过重而其他节点闲置的情况。例如,当数据初始分布不均匀时,通过宽依赖的操作进行&nbsp;Shuffle,可以将数据均匀地分配到各个节点上,提高集群资源的利用率。-&nbsp;Kafka原理&nbsp;&nbsp;-&nbsp;只知道使用,并不了解原理,准备和实时的Flink一起学习-&nbsp;**窗口函数**讲一讲:&nbsp;&nbsp;-&nbsp;排名函数&nbsp;&nbsp;-&nbsp;跨行取值&nbsp;&nbsp;-&nbsp;聚合类-&nbsp;**Hive中怎么做到⾏转列和列转⾏?**&nbsp;&nbsp;-&nbsp;一下卡住了没答,其实很简单-&nbsp;正则表达式知道吗&nbsp;&nbsp;-&nbsp;我只知道去边查边用,不会记规则
查看20道真题和解析
点赞 评论 收藏
分享
美团系统数据研发Java面经【一面】1.&nbsp;自我介绍不问实习和项目,上来就全八股2.&nbsp;为什么&nbsp;String&nbsp;不可变,StringBuilder3.&nbsp;synchronized&nbsp;和&nbsp;Reentranlock&nbsp;详细介绍,哪些情况优先使用后者,或者说为什么解决什么问题而存在4.&nbsp;上面锁的话,有什么注意事项5.&nbsp;join&nbsp;类型6.&nbsp;sql&nbsp;怎么优化7.&nbsp;查看执行计划8.&nbsp;explain&nbsp;的属性9.&nbsp;自动装配原理,流程10.&nbsp;设计模式应用,好处11.&nbsp;如何处理异常12.&nbsp;哪里会打印日志13.&nbsp;遇到性能瓶颈怎么解决核心代码模式,手撕旋转数组【二面】1.&nbsp;自我介绍2.&nbsp;实习相关3.&nbsp;实习里面,有个点有串行执行,为什么不改成并行4.&nbsp;如果这里成为系统的瓶颈,你怎么处理,异步失败了怎么处理5.&nbsp;线程池6.&nbsp;问我了不了解动态扩容的线程池(我说在看过美团技术的一个博客,讲解过,但自己没实现过)7.&nbsp;对于抢票这样的业务,忙的时候要死,闲的时候也要死,你对于数据库的读写方式有什么考虑8.&nbsp;mysql&nbsp;和&nbsp;redis&nbsp;的数据一致性问题(被打麻了,我记得看过的都是不存在强一致性的吧,都存在至少一点点时间的错误)内推链接:(务必填写内推码)https://zhaopin.meituan.com/m/campus?zp-from=hiring-campus-bole-elephant&amp;amp;staffSsoId=23765171内推码:RXB7BM8(务必填写内推码)#实习##技术##算法##春招##美团内推##内推##面经##面经java##java#
美团
|
校招
|
20个岗位
点赞 评论 收藏
分享
评论
1
2
分享

创作者周榜

更多
牛客网
牛客企业服务