SpringBoot 开发总结思考(一)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 从面向对象的角度理解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接口实现类)

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
打赏
0
0
0
0
1
分享
相关文章
SpringBoot入门(8) - 开发中还有哪些常用注解
SpringBoot入门(8) - 开发中还有哪些常用注解
111 0
基于Java+Springboot+Vue开发的鲜花商城管理系统源码+运行
基于Java+Springboot+Vue开发的鲜花商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的鲜花商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。技术学习共同进步
260 7
飞算 JavaAI:革新电商订单系统 Spring Boot 微服务开发
在电商订单系统开发中,传统方式耗时约30天,需应对复杂代码、调试与测试。飞算JavaAI作为一款AI代码生成工具,专注于简化Spring Boot微服务开发。它能根据业务需求自动生成RESTful API、数据库交互及事务管理代码,将开发时间缩短至1小时,效率提升80%。通过减少样板代码编写,提供规范且准确的代码,飞算JavaAI显著降低了开发成本,为软件开发带来革新动力。
Java 21 与 Spring Boot 3.2 微服务开发从入门到精通实操指南
《Java 21与Spring Boot 3.2微服务开发实践》摘要: 本文基于Java 21和Spring Boot 3.2最新特性,通过完整代码示例展示了微服务开发全流程。主要内容包括:1) 使用Spring Initializr初始化项目,集成Web、JPA、H2等组件;2) 配置虚拟线程支持高并发;3) 采用记录类优化DTO设计;4) 实现JPA Repository与Stream API数据访问;5) 服务层整合虚拟线程异步处理和结构化并发;6) 构建RESTful API并使用Springdoc生成文档。文中特别演示了虚拟线程配置(@Async)和StructuredTaskSco
72 0
ERP系统源码,基于SpringBoot+Vue+ElementUI+UniAPP开发
这是一款专为小微企业打造的 SaaS ERP 管理系统,基于 SpringBoot+Vue+ElementUI+UniAPP 技术栈开发,帮助企业轻松上云。系统覆盖进销存、采购、销售、生产、财务、品质、OA 办公及 CRM 等核心功能,业务流程清晰且操作简便。支持二次开发与商用,提供自定义界面、审批流配置及灵活报表设计,助力企业高效管理与数字化转型。
210 2
ERP系统源码,基于SpringBoot+Vue+ElementUI+UniAPP开发
|
4月前
|
基于SpringBoot的Redis开发实战教程
Redis在Spring Boot中的应用非常广泛,其高性能和灵活性使其成为构建高效分布式系统的理想选择。通过深入理解本文的内容,您可以更好地利用Redis的特性,为应用程序提供高效的缓存和消息处理能力。
257 79
20分钟上手DeepSeek开发:SpringBoot + Vue2快速构建AI对话系统
本文介绍如何使用Spring Boot3与Vue2快速构建基于DeepSeek的AI对话系统。系统具备实时流式交互、Markdown内容渲染、前端安全防护等功能,采用响应式架构提升性能。后端以Spring Boot为核心,结合WebFlux和Lombok开发;前端使用Vue2配合WebSocket实现双向通信,并通过DOMPurify保障安全性。项目支持中文语义优化,API延迟低,成本可控,适合个人及企业应用。跟随教程,轻松开启AI应用开发之旅!
SpringBoot是如何简化Spring开发的,以及SpringBoot的特性以及源码分析
Spring Boot 通过简化配置、自动配置和嵌入式服务器等特性,大大简化了 Spring 应用的开发过程。它通过提供一系列 `starter` 依赖和开箱即用的默认配置,使开发者能够更专注于业务逻辑而非繁琐的配置。Spring Boot 的自动配置机制和强大的 Actuator 功能进一步提升了开发效率和应用的可维护性。通过对其源码的分析,可以更深入地理解其内部工作机制,从而更好地利用其特性进行开发。
181 6
【潜意识Java】javaee中的SpringBoot在Java 开发中的应用与详细分析
本文介绍了 Spring Boot 的核心概念和使用场景,并通过一个实战项目演示了如何构建一个简单的 RESTful API。
116 5
Java后端开发-使用springboot进行Mybatis连接数据库步骤
本文介绍了使用Java和IDEA进行数据库操作的详细步骤,涵盖从数据库准备到测试类编写及运行的全过程。主要内容包括: 1. **数据库准备**:创建数据库和表。 2. **查询数据库**:验证数据库是否可用。 3. **IDEA代码配置**:构建实体类并配置数据库连接。 4. **测试类编写**:编写并运行测试类以确保一切正常。
235 2
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问