SpringBoot 开发总结思考(一)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 从面向对象的角度理解XML,是以类和对象作为XML的配置SpringBoot 使用的是配置类加上普通/常规配置的形式,参数不是直接固定在配置类中,而可以写在配置文件中,例如application.properties

SpringBoot 开发总结思考(一)


1、Spring、SpringMVC与SpringBoot的关系与区别


Spring 全称:Spring Framework,当谈论及Spring 的时候,实际上是使用Spring Framework + Mybatis 进行编程,而SpringMvc 是Spring Framework 中专门用于Web的模块


Spring 有两层意义:


.Spring 家族下所有的产品,是一个泛称

.特指 Spring Framework


20200401140646610.jpg


2、Spring Framework 与 SpringBoot 之间的关系


SpringBoot 是新的产品,但它里面用的很多东西还是 Spring Framework,例如 @Component等


Spring 是 SpringBoot 的基础/应用


两者之间的区别肯定是有的,但更多的是上下的关系,SpringBoot是利用SpringFrameWork抽象出来的更好用的一个上层的框架


3、SpringBoot 相对于 SpringFramework 最核心的优势是什么?(自动配置)


自动配置(http://blog.didispace.com/spring-boot-disable-autoconfig/


4、SpringBoot最基础的编程模式@Component+@Autowired


把对象注入到容器的方式有N多种,大体上分为两种


.XML


.注解(Stereotype annotations)


@Component(最基础、用的最多的):在一个类上加此注解,就会被SpringBoot扫描之后,加入到容器当中并负责类的实例化,然后在代码中需要的时候就可以提取出了


.编程方式(但需要结合注解,所以更多时候主要归结到注解)


@Component 示例


新建Diana 类


@Component
public class Diana {
    public void q() {
        System.out.println("Camille 释放了 Q 技能");
    }
    public void w() {
        System.out.println("Camille 释放了 W 技能");
    }
    public void e() {
        System.out.println("Camille 释放了 E 技能");
    }
    public void r() {
        System.out.println("Camille 释放了 R 技能");
    }
}


需要的时候使用属性注入


@Autowired
private Diana diana;
@RestController
@RequestMapping("banner")
public class BannerController {
    @Autowired
    private Diana diana;
    @GetMapping("test")
    public String test(){
        diana.e();
        return "";
    }
}


使用构造函数注入


@RestController
@RequestMapping("banner")
public class BannerController {
    //@Autowired(required = false)
    //private Diana diana;
    public BannerController(Diana diana){
        this.diana = diana;
    }
    @GetMapping("test")
    public String test(){
        diana.e();
        return "";
    }
}


使用Setter注入


@RestController
@RequestMapping("banner")
public class BannerController {
    //@Autowired
    private Diana diana;
    @Autowired
    public void setDiana(Diana diana) {
        this.diana = diana;
    }
    @GetMapping("test")
    public String test(){
        diana.e();
        return "";
    }
}


5、Stereotype Annotations 模式注解(以@Component为基础)


@Component:把一个组件/类/bean 加入到 IOC 中


.@Service

.@Controller

.@Repository

.以上三个注解其实在功能上,目前版本与@Component没什么区别

.如果不是一个服务可以使用@Component,如果是则


@Configuration:把一个组件/类/bean加入到容器的方式与上面的有所区别(未完待续)


6、Spring的实例化和依赖注入时机与延迟实例化


1.使用@AutoWired可以注入一个Bean,但是如果容器中没有这个Bean,程序会报错


.在默认情况下,Spring 无法在容器中找到要注入的Bean,则会报错

.在注入时允许为空,@Autowired(required = false),调用Bean时则会报错


1.IOC 容器的注入时机(IOC是什么时候实例化对象,并且把对象给注入到代码片段中的)


.应用启动时实例化(立即/提前实例化)

.不仅是启动时实例化,并且还会将对象注入到代码片段中(默认机制)


@Lazy 延迟实例化


但在启动时依然会实例化对象,因为Bean不是一个单独的对象,在其他类(例如Controller)中被引用了,也即Controller 依赖于该Bean


所以如果不在依赖方(Controller)加@Lazy ,Bean依然会是默认的实例化流程


7、@Autowired按类型注入,被动推断注入与主动选择注入


Diana


@Component
public class Diana implements ISkill{
    public Diana() {
        System.out.println("Hello, phubing");
    }
    @Override
    public void q() {
        System.out.println("Diana 释放了 Q 技能");
    }
    @Override
    public void w() {
        System.out.println("Diana 释放了 W 技能");
    }
    @Override
    public void e() {
        System.out.println("Diana 释放了 E 技能");
    }
    @Override
    public void r() {
        System.out.println("Diana 释放了 R 技能");
    }
}


Irelia


@Component
public class Irelia implements ISkill{
    public Irelia() {
        System.out.println("Hello, phubing");
    }
    @Override
    public void q() {
        System.out.println("Irelia 释放了 Q 技能");
    }
    @Override
    public void w() {
        System.out.println("Irelia 释放了 W 技能");
    }
    @Override
    public void e() {
        System.out.println("Irelia 释放了 E 技能");
    }
    @Override
    public void r() {
        System.out.println("Irelia 释放了 R 技能");
    }
}


ISkill


public interface ISkill {
    void q();
    void w();
    void e();
    void r();
}


测试类


@RestController
@RequestMapping("banner")
public class BannerController {
    @Autowired(required = false)
    private ISkill diana;
    @GetMapping("test")
    public String test(){
        diana.e();
        return "";
    }
}


此时,程序运行是没问题的,但规范来讲,应该将 ISkill diana; 改为 ISkill iSkill ,这个时候程序运行就会出错


但变量名应该是由开发者定义的,而 Spring 的特点是约定大于配置,所以命名也有可能对代码的正确性造成影响


变量的名字对注入的 bean 是有影响的,如果定义为 ISkill diana 则会注入 Diana 这个类,优先级的规则是什么?


@Autowired 被动注入的方式


by type


.按照类型注入,默认注入形式,

.适用于接口只有一个实现类的情况

.找不到实现该接口的实现类,则会报错

.如果有多个类实现了接口,使用by type 方式注入失败的情况下,会根据命名推断进行注入

.根据类型推断到底应该从容器中注入哪个实现了该接口的 Bean


by name


.按照名字注入


以上都是SpringBoot 被动的进行判断,无论是 by type 还是 by name 都没有显式的指定注入的 Bean


使用  @Qualifier("diana")  显式(主动)指定注入的 Bean


@RestController
@RequestMapping("banner")
public class BannerController {
    @Autowired
    @Qualifier("diana")
    private ISkill iSkill;
    @GetMapping("test")
    public String test(){
        iSkill.e();
        return "";
    }
}


8、面向对象中变化的应对方案


1.指定一个接口,由多个类实现,然后这些类都有共同的接口(策略模式)

2.只有一个实现类,通过更改类的属性来适应变化(类似项目中定义的常量、配置文件)


9、@Configuration 配置类


对于没有明确指向/意义的 Bean 推荐使用@Component


在7的基础上增加一个类  Camille


public class Camille  implements ISkill{
    public Camille() {
        System.out.println("Hello, phubing");
    }
    @Override
    public void q() {
        System.out.println("Camille 释放了 Q 技能");
    }
    @Override
    public void w() {
        System.out.println("Camille 释放了 W 技能");
    }
    @Override
    public void e() {
        System.out.println("Camille 释放了 E 技能");
    }
    @Override
    public void r() {
        System.out.println("Camille 释放了 R 技能");
    }
}


新增一个 HeroConfiguration 配置类


@Configuration
public class HeroConfiguration {
    @Bean
    public ISkill camille(){
        return new Camille();
    }
}


每一个@Bean注解下的方法都要求方法返回一个Bean


测试类


@RestController
@RequestMapping("banner")
public class BannerController {
    @Autowired
    private ISkill camille;
    @GetMapping("test")
    public String test(){
        camille.e();
        return "";
    }
}


10、@Configuration表面意义上的解释(标注了此注解的类称之为  配置类)


已经有了@Component、@Service、@Repository ,Spring 为什么还要增加 @Configuration?


对于一个类来说,除了行为之外,还有特征


.行为:类中的方法就体现了类的行为

.特征:类中定义的属性都是要被赋值的,@Component 只是将Bean加入IOC而不能对属性进行赋值,因为实例化并不是本身去实例化的,所以没办法对属性进行赋值


@Configuration 中是自行实例化的,在实例化时可以传入相关参数,并且可以有多个@Bean


11、@Configuration 是用来替换 bean 的 xml 配置


以前 Spring 使用XML实例化Bean的方式


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                  http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 装配Studnt对象到IOC容器中 -->
    <bean id="student" class="com.demo.domain.Student"/>
</beans>


12、为什么Spring 热衷于配置?


OCP 是为了解决变化,变化是不能消除的,只能隔离,或者反映到配置文件中(配置文件中的改动不算变化)


使用@Configuration 和 @Bean注入,改动这个配置类的代码算不算违反OCP?


.如果将配置类看做是以前的xml文件的替代品,那么改动代码是不会违反OCP


为什么要把变化隔离到配置文件里?


.配置文件具有集中性

.配置文件比较清晰,不包含业务逻辑


13、@Configuation和@Bean的真实作用


从面向对象的角度理解XML,是以类和对象作为XML的配置


SpringBoot 使用的是配置类加上普通/常规配置的形式,参数不是直接固定在配置类中,而可以写在配置文件中,例如application.properties


新建一个MySQL类


public class MySQL implements IConnect{
    private String ip;
    private Integer port;
    @Override
    public void connct() {
        System.out.println(this.ip + ", " + this.port);    
    }
    public MySQL(String ip, Integer port) {
        this.ip = ip;
        this.port = port;
    }
    public MySQL() {
    }
    public String getIp() {
        return ip;
    }
    public void setIp(String ip) {
        this.ip = ip;
    }
    public Integer getPort() {
        return port;
    }
    public void setPort(Integer port) {
        this.port = port;
    }
}


新建一个IConnect 接口


public interface IConnect {
    void connct();
}


新建一个 DatabaseConfiguration 配置类


@Configuration
public class DatabaseConfiguration {
    @Value("#{mysql.ip}")
    private String ip;
    @Value("#{mysql.port}")
    private Integer port;
    @Bean
    public IConnect mysql(){
        return new MySQL(this.ip, this.port);
    }
}


在 application.properties 配置文件中配置 IP 和 PORT


mysql.port=3306
mysql.ip=127.0.0.1


14、@Configuration 的意义


1.在IOC容器启动时,有选择/有条件地注入某一个Bean


2.对于某一个方向的业务问题,不一定只有一个Bean,可能具有多个Bean,此时就可以通过配置类,把所有需要的配置都导入到IOC容器中,而不是分散到各个Bean


15、几种注入方式


@Autowired :字段/成员变量注入


Setter 注入


构造函数注入


16、属性,到底是什么意思?


面向对象中的一个概念,对于Java来讲,严格意义上是不存在属性这样的一个概念


@Autowired
private ISkill camille;


这种最合适的应该称之为成员变量/字段


17、POJO 与 Bean


https://www.cnblogs.com/aiyowei/p/10443161.html


18、@ComponentScan包扫描机制


注解的基本原理是通过反射机制来实现的,通过反射可以读取到注解的信息


SpringBoot启动时只能扫描当前包以及子包下的类


有些组件/Bean需要复用时,可能是以jar的形式导入的,此时可以在启动类增加@ComponentScan 并指定扫描位置


19、策略模式的几种实现方案


1、切换 Bean 的name


2、使用@Qualifier 注解指定注入的Bean


3、有选择地只注入一个Bean,注释掉某个Bean上的@Component注解


4、使用@Primary注解 提高Bean注入的优先级


20、条件注解@Conditional


顾名思义,当满足某种条件的时候,IOC 才会加载Bean


通过@Conditional + Condition 可以完成条件注解


将 9 中的 HeroConfiguration  更改一下


@Configuration
public class HeroConfiguration {
    @Bean
    public ISkill diana(){
        return new Diana("Diana", 1);
    }
    @Bean
    public ISkill irelia(){
        return new Irelia();
    }
}


Irelia


//@Component
public class Irelia implements ISkill{
    public Irelia() {
        System.out.println("Hello, phubing");
    }
    @Override
    public void q() {
        System.out.println("Irelia 释放了 Q 技能");
    }
    @Override
    public void w() {
        System.out.println("Irelia 释放了 W 技能");
    }
    @Override
    public void e() {
        System.out.println("Irelia 释放了 E 技能");
    }
    @Override
    public void r() {
        System.out.println("Irelia 释放了 R 技能");
    }
}


Diana


@Data
//@Component
@AllArgsConstructor
public class Diana implements ISkill{
    private String name;
    private Integer age;
    public Diana() {
        System.out.println("Hello, phubing");
    }
    @Override
    public void q() {
        System.out.println("Diana 释放了 Q 技能");
    }
    @Override
    public void w() {
        System.out.println("Diana 释放了 W 技能");
    }
    @Override
    public void e() {
        System.out.println("Diana 释放了 E 技能");
    }
    @Override
    public void r() {
        System.out.println("Diana 释放了 R 技能");
    }
}


此时,如果不加条件,那么两个Bean都将加入到IOC中


@Conditional() 需要返回一个元类(条件类)


DianaCondition


public class DianaCondition implements Condition {
    /**
     * 此方法返回true时,满足条件的就会被加入到IOC中
     * @param conditionContext
     * @param annotatedTypeMetadata
     * @return
     */
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        return false;
    }
}


HeroConfiguration


@Configuration
public class HeroConfiguration {
    @Bean
    @Conditional(DianaCondition.class)
    public ISkill diana(){
        return new Diana("Diana", 1);
    }
    @Bean
    public ISkill irelia(){
        return new Irelia();
    }
}


此时运行就不会有问题了,因为Diana不满足,直接返回的false


21、Condition 接口的 ConditionContext 参数


新增一个Condition:IreliaCondition


public class IreliaCondition implements Condition {
    /**
     * 此方法返回true时,满足条件的就会被加入到IOC中
     * @param conditionContext
     * @param annotatedTypeMetadata
     * @return
     */
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        return true;
    }
}


application.properties


hero.condition = irelia


通过 ConditionContext  可以获取非常丰富的信息,例如所有的配置信息、所有的Bean、资源加载的信息


IOC 在加载容器的时候并非直接把Bean实例化,当IOC要去加载Bean的时候,首先要生成一个Bean定义,通过Bean定义再来实例化Bean


DianaCondition
public class DianaCondition implements Condition {
    /**
     * 此方法返回true时,满足条件的就会被加入到IOC中
     * @param conditionContext
     * @param annotatedTypeMetadata
     * @return
     */
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        String name = conditionContext.getEnvironment().getProperty("hero.condition");
        return "diana".equalsIgnoreCase(name);
    }
}


IreliaCondition


public class IreliaCondition implements Condition {
    /**
     * 此方法返回true时,满足条件的就会被加入到IOC中
     * @param conditionContext
     * @param annotatedTypeMetadata
     * @return
     */
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        String name = conditionContext.getEnvironment().getProperty("hero.condition");
        return "irelia".equalsIgnoreCase(name);
    }
}


任何@Component 、@Configuration 以及其衍生类都可以追加条件注解


22、@ConditionalOnProperty成品条件注解


更新一下:HeroConfiguration,Diana 与 Irelia 的@Component 需要加上


@Configuration
public class HeroConfiguration {
    @Bean
    @ConditionalOnProperty(value = "hero.condition", havingValue = "diana")
    //@Conditional(DianaCondition.class)
    public ISkill diana(){
        return new Diana("Diana", 1);
    }
    @Bean
    @ConditionalOnProperty(value = "hero.condition", havingValue = "irelia")
    //@Conditional(IreliaCondition.class)
    public ISkill irelia(){
        return new Irelia();
    }
}


matchIfMissing 参数:如果Condition 没有读取到对应值(并非条件不成立),那么该参数为true的Bean将会被注入到IOC中,也即指定一个默认值


23、@ConditionalOnBean


当SpringIOC容器内存在指定的Bean的条件


更改 HeroConfiguration  


@Configuration
public class HeroConfiguration {
    @Bean
    @ConditionalOnBean(name = "mysql")
    public ISkill diana(){
        return new Diana("Diana", 1);
    }
    @Bean
    public ISkill irelia(){
        return new Irelia();
    }
}


如果IOC存在mysql这样一个Bean,那么Diana也会随之被加入到IOC中


24、与@ConditionalOnBean相反的注解:@ConditionalOnMissingBean


如果不存在该注解的value指定的Bean,则加了此注解的Bean将会被加入到IOC中


为了保证同一个实现只有一个相同类型的Bean


Bean与Bean之间很有可能存在依赖,比如常规的Controller类,加了RestController,而RestController中包含了@Component,那Controller类就会被当做一个Bean注入到IOC中;同时Controller类还会依赖别的Bean(例如Service接口实现类)

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
3天前
|
传感器 人工智能 前端开发
JAVA语言VUE2+Spring boot+MySQL开发的智慧校园系统源码(电子班牌可人脸识别)Saas 模式
智慧校园电子班牌,坐落于班级的门口,适合于各类型学校的场景应用,班级学校日常内容更新可由班级自行管理,也可由学校统一管理。让我们一起看看,电子班牌有哪些功能呢?
105 4
JAVA语言VUE2+Spring boot+MySQL开发的智慧校园系统源码(电子班牌可人脸识别)Saas 模式
|
3天前
|
Java 数据库连接 数据库
Springboot整合mybatisPlus开发
MyBatis-Plus是一个MyBatis的增强工具,旨在简化开发和提高效率。它在不修改原有MyBatis的基础上提供额外功能。要将MyBatis-Plus集成到SpringBoot项目中,首先通过Maven添加mybatis-plus-boot-starter和相应数据库驱动依赖,然后配置application.yml中的数据库连接信息,并指定Mapper类的扫描路径。Mapper接口可继承BaseMapper实现基本的CRUD操作。
|
3天前
|
前端开发 JavaScript Java
Springboot框架整合jsp开发【干货满满】
该文介绍了如何在Spring Boot中集成JSP,需包含`spring-boot-starter-web`、`tomcat-embed-jasper`和`jstl`三个依赖。配置Spring Boot寻找JSP的位置,设置`spring.mvc.view.prefix`为`/WEB-INF/jsp/`,`spring.mvc.view.suffix`为`.jsp`。JSP文件应放在`src/main/webapp/WEB-INF/jsp/`下。
|
3天前
|
Web App开发 前端开发 Java
SpringBoot配置HTTPS及开发调试
在实际开发过程中,如果后端需要启用https访问,通常项目启动后配置nginx代理再配置https,前端调用时高版本的chrome还会因为证书未信任导致调用失败,通过摸索整理一套开发调试下的https方案,特此分享
21 0
SpringBoot配置HTTPS及开发调试
|
3天前
|
IDE Java 开发工具
Spring Boot DevTools:加速开发的热部署工具
【4月更文挑战第28天】在Spring Boot的开发过程中,快速反馈和效率至关重要。Spring Boot DevTools是一个为开发者设计的模块,支持热部署(hot swapping),能够实现应用的快速重启和自动重载,极大地提高了开发效率。本篇博客将介绍Spring Boot DevTools的核心概念,并通过具体的实战示例展示如何在开发过程中利用这一工具。
24 0
|
3天前
|
Java Maven Kotlin
[AIGC] 请你写一遍博客介绍 “使用idea+kotinlin+springboot+maven 结合开发一个简单的接口“,输出markdown格式,用中文回答,请尽可能详细
[AIGC] 请你写一遍博客介绍 “使用idea+kotinlin+springboot+maven 结合开发一个简单的接口“,输出markdown格式,用中文回答,请尽可能详细
|
3天前
|
人工智能 前端开发 Java
Java语言开发的AI智慧导诊系统源码springboot+redis 3D互联网智导诊系统源码
智慧导诊解决盲目就诊问题,减轻分诊工作压力。降低挂错号比例,优化就诊流程,有效提高线上线下医疗机构接诊效率。可通过人体画像选择症状部位,了解对应病症信息和推荐就医科室。
198 10
|
3天前
|
Java 关系型数据库 MySQL
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
UWB (ULTRA WIDE BAND, UWB) 技术是一种无线载波通讯技术,它不采用正弦载波,而是利用纳秒级的非正弦波窄脉冲传输数据,因此其所占的频谱范围很宽。一套UWB精确定位系统,最高定位精度可达10cm,具有高精度,高动态,高容量,低功耗的应用。
35 0
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
|
3天前
|
开发框架 Java 测试技术
XwFast,我开发了一个基于SpringBoot和MyBatisPlus的敏捷开发框架!
XwFast,我开发了一个基于SpringBoot和MyBatisPlus的敏捷开发框架!
34 1
|
3天前
|
XML Java 开发者
【SpringBoot实战专题】「开发实战系列」全方位攻克你的技术盲区之SpringBoot整合众多日志管理系统服务starter-logging
【SpringBoot实战专题】「开发实战系列」全方位攻克你的技术盲区之SpringBoot整合众多日志管理系统服务starter-logging
51 1