SpringBoot2笔记01 简介,入门案例,自动配置原理,开发小技巧

SpringBoot简介

Spring能做什么?

Spring的能力

微服务(Microservices):当一个项目模块众多,每一个模块都可能会成长为一个大型应用,将项目中的所有功能拆分成一个个微小的功能模块,称为微服务。

响应式编程(Reactive):基于异步非阻塞的方式,在整个应用之间构建一个异步数据流。允许占用服务器的少量线程、cpu、线程资源,构建一个高吞吐量的应用。

分布式云开发(Cloud):将一个大型应用全部拆分成微小模块(分布式应用)的相关解决方案。

web应用(Web apps):web开发,例如SpringMVC接收请求,返回json数据,响应页面。

无服务开发(Serverless):简单快速开发一个函数式服务。

事件驱动(Event Driven):将整个分布式系统(用基于事件的方式)构建出一个实时的数据流。

批处理(Batch):批处理。

Spring的生态

覆盖了:web开发,数据访问,安全控制,分布式,消息服务,移动开发,批处理...

Spring5的重大升级

响应式编程

响应式编程是一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。

例如,对于 a=b+c 这个表达式的处理,在命令式编程中,会先计算 b+c 的结果,再把此结果赋值给 变量a,因此 b,c 两值的变化不会对 变量a 产生影响。但在响应式编程中,变量a 的值会随时跟随 b,c 的变化而变化。

电子表格程序就是响应式编程的一个例子。单元格可以包含字面值或类似"=B1+C1"的公式,而包含公式的单元格的值会依据其他单元格的值的变化而变化。

响应式编程最初是为了简化交互式用户界面的创建和实时系统动画的绘制而提出来的一种方法,但它本质上是一种通用的编程范式。

例如,在MVC软件架构中,响应式编程允许将相关模型的变化自动反映到视图上,反之亦然。

内部源码设计

基于Java的一些新特性,如:接口默认实现,重新设计源码架构

为什么用SpringBoot?

为了快速创建出生产级别的Spring应用。

SpringBoot优点

创建独立Spring应用

Create stand-alone Spring applications

内嵌web服务器

Embed Tomcat,Jetty or Undertow directly(no need to deploy WAR files)

自动starter依赖,简化构建配置

Provide opinionated ‘starter’ dependencies to simplify your build configuration

自动配置Spring以及第三方功能

Automatically configure Spring and 3rd party libraries whenever possible

提供生产级别的监控,健康检查及外部化配置

Provide production-ready features such as metric,health checks,and externalized configuration

无代码生成,无需编写XML

Absolutely no code generation and no requirement for XML configuration

SpringBoot是整合Spring技术栈的一站式框架

SpringBoot是简化Spring技术栈的快速开发脚手架

SpringBoot缺点

迭代快(也是优点)

封装太深,内部原理复杂,不容易精通

时代背景

微服务

James Lewis and Martin Fowler在2014年提出微服务完整概念。

简而言之,微服务架构风格是一种将单个应用程序开发为一套小型服务的方法,每个服务都在自己的进程中运行并与轻量级机制(通常是HTTP资源API)进行通信,这些服务是围绕业务能力构建的,并且可以通过完全自动化的部署机制独立部署。这些服务的集中管理是最低限度的(去中心化,服务自治),这些服务可以用不同的编程语言编写,并使用不同的数据存储技术。

In short,the microservice architectual style is an approach to developing a single application as a suite of small services,each running in its own process and communicating with lightweight mechanisms,often an HTTP resource API,These services are built around business capablities and independently deployable by fully automated deployment machinery.There is a bare minimum of centralized management of these services,which may be written in different programming languages and use different data storage technologies.

分布式

分布式的困难

远程调用

服务发现

负载均衡

服务容错

配置管理

服务监控

链路追踪

日志管理

任务调度

......

分布式的解决

SpringBoot+SpringCloud

云原生

原生应用如何上云,Cloud Native

上云的困难

服务自愈

弹性伸缩

服务隔离

自动化部署

灰度发布

流量治理

......

上云的解决

如何学习SpringBoot

官网文档架构

入门案例

版本与课程版本一致(2.3.4)避免不必要的麻烦。

系统要求

Java 8+,Maven 3.3+

HelloWorld

需求:浏览器发送/hello请求,响应Hello,Spring Boot2

创建maven工程

引入依赖

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
    </parent>


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

编写主程序类

作为程序的入口(在spring.gyq.boot包下)

//告诉SpringBoot这是一个springBoot应用
@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class, args);
    }
}

编写业务

spring.gyq.boot.controller包下

@RestController
public class HelloController {
    @RequestMapping("/hello")
    public String handle01() {
        return "Hello,Spring Boot 2";
    }
}

运行项目

不需要使用Tomcat,直接运行主程序类的main方法

简化配置

所有配置都抽取到application.properties中

更改Tomcat端口号

简化部署

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

把项目打成jar包直接在目标服务器执行即可

在jar包所在目录里直接在命令行java -jar jar包名就可以了

如果不行取消掉cmd的快速编辑模式

了解自动配置原理

SpringBoot特点

依赖管理

父项目做依赖管理

    <!--依赖管理-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
    </parent>
    
    <!--它的父项目-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>2.3.4.RELEASE</version>
    </parent>

几乎声明了所有开发中常用的依赖的版本号,自动版本仲裁

spring-boot-dependencies中

......

若需要自定义版本,或引入非版本仲裁的jar

在properties标签中自定义在父工程的父工程中表示该依赖版本的标签(就近原则)


开发导入starter场景启动器

我们会见到很多spring-boot-starter-* :*就指某种场景(web)

只要引入starter,这个场景的所有常规我们需要的依赖我们都自动导入

*-spring-boot-starter:第三方为我们提供的简化开发的场景启动器(druid-spring-boot-starter)

所有场景启动器最底层的依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>2.3.4.RELEASE</version>
            <scope>compile</scope>
        </dependency>

自动配置

spring-boot-starter-web帮我们引入的依赖

  

自动配好Tomcat

1、引入Tomcat依赖

2、配置Tomcat

自动配好SpringMVC

1、引入SpringMVC全套组件

2、自动配好SpringMVC常用组件

自动配置好Web常用功能,如:字符编码问题

SpringBoot帮我们配置好了所有web开发的常见场景

查看IOC容器里面的组件

部分结果

默认的包结构

主程序所在包及其下面所有子包里面的组件都会被默认扫描进来

无需以前的包扫描配置

想要改变扫描路径,@SpringBootApplication(scanBasePackages="com.gyq")或者@ComponentScan指定扫描路径

@SpringBootApplication

等同于

@SpringBootConfiguration

@EnableAutoConfiguration

@ComponentScan("com.gyq.boot")

各种配置拥有默认值

默认配置最终都是映射到某个类上,如:MultipartProperties

配置文件的值最终会绑定到某个类上,这个类会在容器中创建对象

按需加载所有自动配置项

非常多的starter

引入了哪些场景这个场景的自动配置才会开启

SpringBoot所有的自动配置功能都早spring-boot-autoconfigure包里面

.......

容器功能

组件添加

@Configuration

//告诉SpringBoot这是一个配置类,作用等同于配置文件
//配置类本身也是一个组件
//proxyBeanMethods:代理bean的方法,默认值为true
//  Full(全模式):@Configuration(proxyBeanMethods = true)确保每个@Bean方法被调用多少次返回的组件都是单实例
//  Lite(轻量级模式):@Configuration(proxyBeanMethods = false)每个@Bean方法被调用多少次返回的组件都是新创建的
//组件依赖必须使用Full模式,方法会调用得到之前单例组件
//无依赖关系用Lite模式加速容器启动过程,减少判断
@Configuration(proxyBeanMethods = true)
public class MyConfig {
    //给容器添加组件,以方法名作为组件的id,
    //返回类型就是组件类型,返回值就是组件在容器中的实例
    @Bean
    public User user01() {
        User GYQ = new User("GYQ", 18);
        //user组件依赖了Pet组件
        GYQ.setPet(tomcatPet());
        return GYQ;
    }

    //指定组件的id
    @Bean("tom")
    public Pet tomcatPet() {
        return new Pet("tomcat");
    }
}

测试

//告诉SpringBoot这是一个springBoot应用
@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        //返回我们的IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

        //从容器中获取组件
        //默认是单例的,两对象为同一个
        Pet tom1 = (Pet) run.getBean("tom");
        Pet tom2 = run.getBean("tom", Pet.class);
        System.out.println(tom1 == tom2);

        //配置类也是一个组件
        MyConfig bean = run.getBean(MyConfig.class);
        //com.gyq.boot.config.MyConfig$$EnhancerBySpringCGLIB$$ebae5a48@7c0da600
        //如果@Configuration(proxyBeanMethods = true)代理对象调用方法
        //SpringBoot总会检查这个组件是否在容器中有,确保获取到的是单个实例
        System.out.println(bean);
        User user1 = bean.user01();
        User user2 = bean.user01();
        System.out.println(user1 == user2);


        User user01 = run.getBean("user01", User.class);
        Pet tom = run.getBean("tom", Pet.class);
        System.out.println("用户的宠物:" + (user01.getPet() == tom));
    }
}

@Bean,@Component,@Controller,@Service,@Repository

用这些注解标识组件

@ComponentScan,@Import

@Import标识在容器组件上(配置类,controller.......)

测试

//告诉SpringBoot这是一个springBoot应用
@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        //获取组件
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
        String[] names = run.getBeanNamesForType(User.class);
        for (String name : names) {
            System.out.println(name);
        }

        DBHelper bean1 = run.getBean(DBHelper.class);
        System.out.println(bean1);
    }
}

@Conditional

条件装配:满足Conditional指定的条件,则进行组件注入

标注在类上,当容器中有tom组件才会添加该配置类添加的组件

标注在方法上,当容器中有tom组件才会将该方法表示的组件添加到容器中,如果和tom在同一个配置类中,需要tom在它前面才会添加

ConditionalOnMissingBean注解表示没有该bean时添加

原生配置文件引入

@ImportResource

这样配置文件中配置的bean也会添加到容器中

配置绑定

如何使用Java读取到properties文件中的内容,并且把它封装到JavaBean中,以供随时使用

配置文件

@Component+@ConfigurationProperties

实体类

将其导入到容器中,并将配置文件中的配置和类的属性绑定 

测试

另一种方法👇

@EnableConfigurationProperties+@ConfigurationProperties

在配置类上开启Car的配置绑定功能,并自动将组件导入容器中

指定配置文件中属性前缀

自动配置原理入门

引导加载自动配置类

@SpringBootConfiguration:代表当前是一个配置类

@ComponentScan("xxx"):注解扫描,指定扫描哪些包

@EnableAutoConfiguration


@AutoConfigurationPackage:利用Register给容器导入指定包(main程序所在包)下一系列组件

    static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
        Registrar() {
        }

        public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
        }

        public Set<Object> determineImports(AnnotationMetadata metadata) {
            return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
        }
    }

其中方法中参数AnnotationMetadata表示@AutoConfigurationPackage这个注解的元信息,包含该注解标识的位置等信息。

registerBeanDefinitions方法获取到当前主配置类所在的包名,并将其封装到数组中

将该包(MainApplication所在包)下的组件批量注册到容器中


@Import({AutoConfigurationImportSelector.class})

1.利用getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件

2.调用List<String> configurations=getCandidateConfigurations(annotationMetadata,attributes)获取到所有需要导入到容器中的配置类

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

3.上面的方法利用工厂加载 Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件

    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        String factoryTypeName = factoryType.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
    }

4.从META-INF/spring.factories位置来加载一个文件。
    默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
    spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories

文件里面写死了一些spring-boot一启动就要给容器中加载的所有配置类

按需开启自动配置项

虽然我们127个场景的所有自动配置启动的时候默认全部加载

按照条件装配规则(@Conditonal注解),最终会按需配置

AopAutoConfiguration配置类

@Configuration表示这是一个配置类,轻量模式(非单例)

@ConditionalOnProperty表示判断配置文件中是否存在spring.aop.auto=true

matchIfMissing=true,表示没配默认也是这样配的

此时没有导入AOP场景,aspectj下的Advice是没有的,这个配置类是不生效的

下面还有一个配置类

它是在没有下面的类时生效

又接着判断你是否在配置文件中配置了下面的配置,如果没配,也默认认为是这样配的

此时开启的是简单的aop功能,必须有接口有实现类,才能帮你创建代理对象

修改默认配置

        @Bean
		@ConditionalOnBean(MultipartResolver.class)  //容器中有这个类型组件
		@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) //容器中没有这个名字 multipartResolver 的组件
		public MultipartResolver multipartResolver(MultipartResolver resolver) {
            //给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找。
            //SpringMVC multipartResolver。防止有些用户配置的文件上传解析器不符合规范
			// Detect if the user has created a MultipartResolver but named it incorrectly
			return resolver;
		}
给容器中加入了文件上传解析器;

当自己配置的MultipartResolver名字不是multipartResolver时也能找到该组件

总结:

SpringBoot默认会在底层配好所有的组件,但是如果用户自己配置了以用户的优先

SpringBoot先加载所有的自动配置类 xxxAutoConfiguration

每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值,xxxProperties里面拿,xxxProperties和配置文件进行了绑定

生效的配置类就会给容器中装配很多组件

只要容器中有这些组件,相当于这些功能就有了

定制化配置

        用户直接自己@Bean替换底层的组件

    @Bean
    public CharacterEncodingFilter filter() {
        return null;
    }

        用户去看这个组件是获取的配置文件什么值就去修改配置文件即可,不需要自定义组件

xxxAutoConfiguration->组件->xxxProperties里面拿值->application.properties

实践

引入场景依赖

Developing with Spring Boot

查看自动配置了哪些

        自己分析,引入场景对应的自动配置一般都生效了

        配置文件中末尾添加debug=true开启自动配置报告,Negative(不生效)\Positive(生效)

是否需要修改

        参照文档修改配置项

                Common Application Properties

                自己分析,xxxProperties绑定了配置文件的哪些

        自定义加入或者替换组件

                @Bean,@Component

        自定义器 XXXCustomizer

开发小技巧

Lombok

引入依赖

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

简化JavaBean开发

简化日志开发

dev-tools

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

项目或者页面修改以后:Ctrl+F9     重新编译之后dev-tools帮我们加载(重新启动)

JRebel插件,热更新

Spring Initializr

选择需要的开发场景

自动依赖引入

自动创建项目结构

static静态资源,templates页面,配置文件

自动编写好主配置类

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值