Java技术栈

概要

这个网站也不错
javaGuide
javase基础引用自知乎和哔哩哔哩
知乎:java学习框架
哔哩哔哩:狂神说java

整体架构流程

提示:这里可以添加技术整体架构

第一阶段:Java基础

1. Java SE基础
1.1abstract 抽象

在Java™编程语言中,“abstract”是一个用于类定义的关键字,它指定了一个类不应该被实例化,而是应该被其他类继承。一个抽象类可以拥有抽象方法,这些方法在抽象类中没有具体实现,而是在子类中实现。

形象的例子:可以把“abstract”理解为设计图纸。假设你要建造一系列的房子,这些房子在结构上都有共同之处(比如都需要基础设施:门、窗、屋顶),但在一些细节上各有不同(比如房子的样式、颜色或内部装潢)。在这种情况下,你可以创建一个“图纸”(抽象类),在这个图纸上定义所有房子共有的结构(抽象方法),但不具体指定每个结构的细节(即,方法的具体实现留给继承这个图纸的“子图纸”来完成)。每个具体的房子设计都是基于这个基础图纸,但根据自己的需求添加具体的实现细节。这样,每种房子的设计都保留了基本结构的同时,也有了自己的特色。

1.2 递归

递归:自己调用自己,用简单的程序来解决一些复杂的问题,将一个大型复杂的问题转化为一个与原问题相似的规模较小的问题来求解。要有递归头和方法体,递归头即什么时候不调用自身方法,如果没有头将陷入死循环。递归体即什么时候调用自己。
递归
方法的调用:静态方法(有static修饰)用方法名.直接调用。非静态方法需要new个对象后,用新创建的对象调用。

1.3 super

当在子类对象中,子类想访问父类的东西,可以使用“super.”的方式访问。例如:方法覆盖后,子类内部虽然重写了父类的方法,但子类也想使用一下父类的被覆盖的方法,此时可以使用“super.”的方式。当子类中出现和父类一样的属性或者方法,此时,你要想去调用父类的那个属性或者方法,此时“super.”不能省略。
this.”是一个实例对象内部为了区分实例变量和局部变量。
而“super.”是一个实例对象为了区分是子类的成员还是父类的成员。

1.4 算法 伪代码 程序

算法像食谱,程序是食谱的具体实现过程,伪代码介于二者之间,是一种描述
在这里插入图片描述
在这里插入图片描述

构造函数同时满足两个条件:1名称与类名相同:它的名称 Main 与类名完全相同。2无返回类型声明:构造函数没有返回类型声明,也不是 void。

1.5重载与构造相似之处:

构造方法和重载方法都可以存在于一个类中:它们都可以使用相同的名称(对于构造方法而言,这个名称是类名),但是它们的参数列表必须不同以区分不同的方法。
参数列表的重要性:无论是构造方法还是重载的普通方法,Java 都根据方法名称和参数列表(类型、数量、顺序)来区分不同的方法。
区别
调用时机和方式不同:
构造方法:当通过 new 关键字创建一个新的对象实例时自动调用,没有返回类型,也不能被显式调用。
重载方法:可以在任何时候被显式调用,必须指定返回类型(如果方法不返回任何值,则使用 void)。
方法名称:
构造方法的名称:必须与类名完全相同。
重载方法的名称:可以是任何有效的标识符,只要它们遵守Java的命名规则。
示例
你的示例很好地说明了构造方法和重载方法在实际使用中的应用:

public class Person {
    private String name;
    private int age;

    // 构造方法1:无参构造方法
    public Person() {
        this.name = "Unknown";
        this.age = 0;
    }

    // 构造方法2:带参数的构造方法
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 重载方法1:设置姓名
    public void setName(String name) {
        this.name = name;
    }

    // 重载方法2:设置年龄
    public void setAge(int age) {
        this.age = age;
    }
}

在这个 Person 类中:

构造方法:用于初始化新创建的对象的状态。这里有两个构造方法,一个无参,一个带有两个参数(name 和 age)。
重载方法:这些方法被用于在对象已经存在后修改对象的状态。例如,setName 和 setAge 允许在对象创建之后更改其 name 和 age 属性。
通过这些定义和使用,我们可以看到构造方法和重载方法各自的功能和重要性,以及它们如何共同作用来提高Java类的灵活性和功能性。

抽象类与接口:
Java
在Java中,接口(Interface)和抽象类(Abstract Class)都可以用来实现抽象化,但它们的用途和方式有所不同:

接口(Interface)

接口是一种完全抽象的类,它只能包含抽象方法(Java 8之前),这些方法默认是public且无实现(即没有方法体)。
从Java 8开始,接口可以包含默认方法和静态方法,这些方法有完整的实现。
接口主要用于定义一个可以被多个类实现的契约,强调的是行为的规范。
一个类可以实现多个接口,支持多重继承的行为规范。
抽象类(Abstract Class)

抽象类是不能被实例化的类,可以包含抽象方法(无实现的方法)和非抽象方法(有实现的方法)。
抽象类主要用于为一类对象提供一个通用的、概念性的基础状态和行为实现。
抽象类可以有构造函数,状态(属性)和完整的方法。
一个类只能继承一个抽象类,不支持多重继承。
因此,接口不能视为抽象类。接口提供了一种更加灵活的方式来定义公共API,而不必绑定于单一的继承结构。接口更多地关注于行为的规范,而抽象类则结合了行为与状态的定义。
在这里插入图片描述

生动形象解释Java中构造函数、重载和覆盖的区别
构造函数
构造函数是一种特殊类型的方法,用于初始化对象的状态。想象一下你在组装一辆汽车,构造函数就像是汽车组装过程中的装配线,负责给汽车安装必要的部件和初始化属性,以确保汽车可以正常运行。

举例:在Java中,构造函数的定义类似于以下代码:

public class Car {
    private String model;
    private int year;

    // 构造函数
    public Car(String model, int year) {
        this.model = model;
        this.year = year;
    }
}

重载
重载是指在同一个类中可以定义多个方法,它们具有相同的名称但参数列表不同的特性。想象一下你在玩积木,有不同形状和颜色的积木块,但它们都叫做“积木”,只是参数(形状、颜色等)不同。

举例:在Java中,可以定义多个重载的方法,例如:

public class MathOperations {
    // 重载的方法
    public int add(int a, int b) {
        return a + b;
    }

public double add(double a, double b) {       
	return a + b;
 	}
}

覆盖
覆盖是指子类重新定义父类中已有的方法,以适应子类的需求。想象一下你在画画,你可以根据需要对一幅已有的图案进行修改和润色,使得它更符合你的想法。

举例:在Java中,子类可以覆盖父类的方法,例如:

public class Animal {
    public void makeSound() {
        System.out.println("Animal makes a sound");
    }
}

public class Dog extends Animal {
    // 覆盖父类的方法
    @Override
    public void makeSound() {
        System.out.println("Dog barks");
    }
}

应用场景举例
构造函数:用于创建对象时进行初始化,确保对象的属性被正确设置。
重载:用于实现一组功能相似但参数类型或个数不同的方法。
覆盖:用于子类修改或扩展父类的行为,实现多态性。
通过理解和应用构造函数、重载和覆盖,我们可以更好地设计和组织Java类,使得代码更加灵活和易于维护。

1.6for循环三种跳出循环的方法(retrun、continue、break)

return:指的是跳出for循环,且不执行for循环之外的语句,直接跳出当前函数,返回return后的值。
三者区别

1.7超类和多态

假设你有一个宠物园。

超类(父类):

超类就像是宠物园的"动物"部分,它定义了所有动物的通用特征和行为。例如,所有动物都有一种共同的行为,那就是“发出声音”。所以,你的超类(父类)会定义一个通用的方法,比如makeSound()。
子类(派生类):

子类则是超类的具体化。在我们的宠物园里,有许多不同的动物,比如狗、猫、鸟、大象等等。每种动物都有自己独特的特征和行为,但它们也都继承了超类的通用特征。例如,狗可以被视为超类“动物”的子类,它继承了发出声音的方法,并可能有自己特有的方法,比如fetchStick()。
多态:

多态是指相同的方法调用可以在不同的对象上产生不同的行为。回到宠物园的例子,当你调用makeSound()方法时,不同种类的动物会发出不同的声音,因为每种动物都有自己独特的声音。这种灵活性就是多态的体现,同一个方法在不同的对象上表现出不同的行为。
通过这个比喻,我们可以理解超类和多态的概念:超类定义了通用特征,子类继承并扩展了这些特征,而多态则允许相同的方法在不同的对象上表现出不同的行为。

1.8uml中的泛化就是面向对象中的继承嘛?

是的,UML中的泛化关系可以理解为面向对象编程中的继承关系。在UML类图中,泛化关系用箭头表示,箭头指向父类,表示子类继承自父类。

继承是面向对象编程的一个基本概念,它允许子类继承父类的属性和方法,并且可以通过扩展、修改或添加新的特性来定义自己的行为。这种继承关系使得代码的重用变得更加容易,并且可以建立类之间的层次结构。

在UML中,泛化关系是一种特殊的关系类型,它描述了类之间的继承关系。超类(父类)被称为泛化的源,子类(派生类)被称为泛化的目标。泛化关系可以传递,即一个子类可以继承自另一个子类,形成多层次的继承结构。

通过使用泛化关系,我们可以在UML类图中清晰地表示类之间的继承关系,帮助我们理解和设计面向对象系统的结构。泛化关系还提供了代码重用和组织的好处,使得系统的设计更加灵活和可扩展。

1.9静态变量

这样理解对吗若不对给出正确的:静态变量属于类,在内存中只有一份且能被后续新建的对象共享。
您的理解是正确的。静态变量属于类,而不是属于类的实例(对象),在内存中只有一份,所有该类的实例共享这个静态变量。当类被加载时,静态变量就会被分配内存空间,而不是在每个实例被创建时都分配一次。

所以,无论创建了多少个类的实例,它们都会共享相同的静态变量。这也意味着,如果一个实例修改了静态变量的值,那么该变量的值对于所有其他实例也会发生改变,因为它们共享同一份静态变量。

这种特性使得静态变量非常适合用来表示类级别的信息,比如常量、全局配置等。同时,由于静态变量不与具体的实例相关联,它们可以在没有实例的情况下被访问和修改,通过类名直接访问,例如 ClassName.staticVariable。

1.10&非短路

在 Java 中,逻辑运算符 & 表示按位与操作,用于对两个布尔类型的操作数执行按位与操作。& 运算符会对两个操作数的每一个对应位执行与操作,无论其左边的操作数的值是什么,右边的操作数都会被计算。

而“非短路”表示逻辑与和逻辑或运算符不考虑后面的表达式的情况,无论后面的表达式的结果如何,都会继续对后面的表达式进行计算。在 Java 中,逻辑与运算符有两种形式:& 和 &&。其中,& 是非短路版本的逻辑与运算符,而 && 是短路版本的逻辑与运算符。

下面是它们的区别:

使用 & 运算符时,无论左边的表达式的结果是 true 还是 false,右边的表达式都会被计算。
使用 && 运算符时,如果左边的表达式的结果为 false,那么右边的表达式将不再被计算,因为整个逻辑与表达式的结果已经确定为 false。
这种短路行为使得在某些情况下,可以避免不必要的计算,提高程序的效率。

1.11类之间的关系

USES-A(依赖关系):这种关系表示一个类使用了另一个类,但并不拥有对其的控制权。A类需要使用B类的功能或者数据,所以A类中的某些方法可能会接受B类的实例作为参数,或者在方法中临时创建B类的实例。因此,A类依赖于B类,但这种关系是临时性的,B类的变化可能会影响到A类。在代码中的体现通常是A类方法中的参数包含了B类。

关联关系:这种关系表示一个类和另一个类之间的强依赖关系,通常是长期性的。A类的成员变量中含有B类的实例,这意味着A类拥有对B类对象的引用,并且对B类对象有直接的控制权。这种关系是比较强的,因为A类中的成员变量持有B类的实例,任何对B类实例的操作都会直接影响到A类的状态。

HAS-A(聚合关系):这种关系表示整体和部分之间的关系,是关联关系的一种特例。比如鸟群和鸟的关系就是聚合关系,鸟群是由多个鸟组成的,每个鸟是鸟群的一部分。在代码中,这种关系通常表现为一个类中包含另一个类的实例作为成员变量。

IS-A(继承关系):这表示父类与子类之间的继承关系,子类继承了父类的属性和方法,并且可以扩展或重写父类的功能。这是面向对象编程中最基本的关系,用于构建类的层次结构。

组合关系:这也是关联关系的一种特例,表示一个类包含另一个类的实例,但这种整体和部分是不可分割的。比如汽车和发动机的关系,发动机是汽车的一部分,二者是不可分割的关系。在代码中通常表现为一个类中包含另一个类的实例,并且不允许外部对这些实例进行独立管理。

2. Java进阶

jar包:JAR(Java Archive)是Java平台标准的一种压缩文件格式,它可以用来打包Java类文件、相关资源文件以及元数据信息。JAR文件通常用于在Java应用程序之间共享和传播代码和资源。您可以将 JAR 包理解为资源包。它包含了 Java 类文件、相关资源文件以及元数据信息,这些文件和信息被打包成一个单独的归档文件。就像您提到的资源包一样,JAR 包也可以用于存储和传输应用程序所需的各种资源和文件。因此,您可以将 JAR 包视为一种用于管理和分发 Java 应用程序和相关资源的包装格式。通常情况下,JAR 包是由 Java 工程生产出来的。在 Java 开发过程中,当您编写了 Java 类文件、相关资源文件以及可能的元数据信息后,可以使用 Java 开发工具(如 Maven、Gradle 或者 Ant 等)将这些文件打包成一个 JAR 文件。这个 JAR 文件包含了您的 Java 应用程序或库的所有组件,可以被轻松地部署和分发。在构建过程中,开发工具会将您的源代码编译成 Java 字节码,并将编译后的类文件以及其他资源文件打包成 JAR 归档文件。这个 JAR 文件可以包含项目中的所有类文件、资源文件、配置文件等内容,使得您的应用程序或库能够以一种整体的方式被使用和传播。
总的来说,JAR 包是 Java 工程生产出的一种打包格式,用于打包和分发 Java 应用程序和库。

tomcat:web服务器软件
笔记
Tomcat服务器下载、安装、配置环境变量教程

第二阶段:Java虚拟机(预计1-2周)

第三阶段:数据库与缓存(预计1-2个月)

1. MySQL
2. Redis

第四阶段:工具

1.Maven

(1)文件架构
功能1:依赖管理通过GAVP坐标实现
在这里插入图片描述
(2)在pom中添加完mvn网站 < dependency >后出现错误
1.18.24版本不兼容

在这里插入图片描述

说明引入的依赖dapendence版本不兼容
修改版本号再试试就可以了
在这里插入图片描述
(3)maven是靠插件plugin
在这里插入图片描述

2.Git

两种方法:1使用idea中的git。2使用git中的MING窗口
Git是一个分布式版本控制系统,它广泛用于软件开发中进行版本控制和协作。以下是Git的一些关键概念和用法:

  1. 版本控制:
    Git可以跟踪文件的变化,记录每次修改的内容,从而实现版本控制。这使得开发团队可以轻松地查看和管理项目的历史版本。
  2. 分布式:
    Git是一种分布式版本控制系统,每个开发者都可以在本地拥有完整的版本库,包括完整的项目历史记录。这使得开发者可以在没有网络连接的情况下工作,并且可以更快速地进行操作。
  3. 仓库(Repository):
    Git仓库是存储项目文件和历史记录的地方。它包含项目的所有文件以及与项目相关的版本信息。
  4. 提交(Commit):
    提交是指将文件的变化保存到Git仓库中的操作。每次提交都会创建一个快照,并记录提交者、提交时间等信息。
  5. 分支(Branch):
    分支是指项目的一个独立线条,它可以包含不同的提交历史。通过创建分支,开发者可以在不影响主线开发的情况下进行新功能的开发或问题修复。
  6. 合并(Merge):
    合并是指将一个分支的修改合并到另一个分支的操作。这使得不同分支上的代码可以合并到一起,确保项目的整体一致性。
  7. 拉取(Pull)和推送(Push):
    拉取是指从远程仓库获取最新的更改,而推送是指将本地的更改上传到远程仓库。这使得团队成员可以协作开发,并及时共享自己的工作成果。
    Git是现代软件开发中不可或缺的工具之一,它提供了强大的版本控制和协作功能,使得团队能够更加高效地进行开发和管理项目。

1:用git上传带密码key的项目到github的公共仓库会被拒绝,除非把仓库改为私有

2:如何回滚

第五阶段:Spring框架系列(预计2个月)

-1:设计思路

Spring用到的设计模式主要是工厂模式,加反射实现的,将程序的耦合度降低
工厂模式(Factory Pattern)详细解释
工厂模式是一种常用的设计模式,属于创建型模式。它提供了一种创建对象的方式,使得客户端代码从直接创建对象解耦,例如依赖注入或工厂模式,将对象的创建和管理责任从客户端代码中分离出来。这样做的好处是降低了客户端代码与具体对象的耦合度增强了系统的灵活性和可维护性。工厂模式主要用于封装和管理创建对象的逻辑,当创建逻辑比较复杂或者当需要根据不同条件创建不同的实例时,使用工厂模式尤其合适。

核心组件
简单工厂(Simple Factory):不是一个真正的设计模式,而是一种编程习惯。它有一个工厂类,可以根据参数的不同返回不同类的实例。
工厂方法(Factory Method):定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
抽象工厂(Abstract Factory):提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
示例:电脑制造
假设我们正在编写一个电脑组装店的软件,需要根据客户需求生产不同类型的电脑(如笔记本、台式机、游戏机等)。我们可以使用工厂模式来处理这种情况。

工厂方法模式的实现
首先,定义一个Computer接口和几个实现这个接口的具体类,表示不同类型的电脑:

public interface Computer {
    void assemble();
}

public class Desktop implements Computer {
    public void assemble() {
        System.out.println("Assembling a desktop computer.");
    }
}

public class Laptop implements Computer {
    public void assemble() {
        System.out.println("Assembling a laptop computer.");
    }
}

public class GamingComputer implements Computer {
    public void assemble() {
        System.out.println("Assembling a gaming computer.");
    }
}

接下来,定义一个工厂接口和实现这个接口的具体工厂类:

public interface ComputerFactory {
    Computer createComputer();
}

public class DesktopFactory implements ComputerFactory {
    public Computer createComputer() {
        return new Desktop();
    }
}

public class LaptopFactory implements ComputerFactory {
    public Computer createComputer() {
        return new Laptop();
    }
}

public class GamingComputerFactory implements ComputerFactory {
    public Computer createComputer() {
        return new GamingComputer();
    }
}

使用工厂模式
客户端代码现在可以使用工厂来获取需要的电脑类型,而不需要直接实例化电脑对象:

public class ComputerStore {
    public static void main(String[] args) {
        ComputerFactory factory = new LaptopFactory();
        Computer myComputer = factory.createComputer();
        myComputer.assemble();
    }
}

结果和优势
通过使用工厂模式,我们的代码变得更加灵活和可维护。如果需要添加新的电脑类型,我们只需要添加一个新的具体电脑类和对应的工厂类,而不需要修改现有的客户端代码。这样不仅使得系统易于扩展,而且还可以降低修改现有代码带来的风险。

工厂模式是处理对象创建逻辑的理想选择,尤其是当对象的创建过程复杂或者需要根据不同的条件产生不同的对象时。通过这种方式,我们可以将对象的创建和使用分离,提高系统的整体稳定性和可复用性。

工厂模式与依赖注入的区别详细解释
工厂模式和依赖注入都是在软件开发中用于管理对象创建的技术,但它们的用途和实现方式有所不同。理解这两者之间的区别有助于开发者选择适合特定场景的最佳实践。

工厂模式(Factory Pattern)
工厂模式是一种创建型设计模式,它提供了一种创建对象的机制,使得接口的实现不依赖于客户端代码。在工厂模式中,客户端不直接创建对象,而是通过调用一个工厂类的方法来获取新的对象实例。工厂方法可能会根据传入的参数决定返回哪种类型的对象。

核心目的:封装对象的创建细节,使得代码可以通用化,增加程序的灵活性和扩展性。

依赖注入(Dependency Injection)
依赖注入是一种编程技术,用于实现控制反转(IoC),将对象的创建和绑定的责任从使用对象的类转移给外部实体(通常是框架或容器)。依赖注入允许类的依赖关系在运行时动态地注入到类中,而不是由类自己控制。

核心目的:提高代码的模块化和测试性,通过外部系统自动地将依赖关系注入到组件中,从而降低组件之间的耦合。

示例解释
假设有一个应用程序需要根据不同的国家环境来创建不同的日期格式器。

工厂模式实现

public interface DateFormatter {
    String format(Date date);
}

public class USDateFormatter implements DateFormatter {
    public String format(Date date) {
        // 实现美国日期格式
        return new SimpleDateFormat("MM-dd-yyyy").format(date);
    }
}

public class EUDateFormatter implements DateFormatter {
    public String format(Date date) {
        // 实现欧洲日期格式
        return new SimpleDateFormat("dd-MM-yyyy").format(date);
    }
}

public class DateFormatterFactory {
    public static DateFormatter getDateFormatter(String region) {
        if ("US".equals(region)) {
            return new USDateFormatter();
        } else if ("EU".equals(region)) {
            return new EUDateFormatter();
        } else {
            return null;
        }
    }
}

在这个例子中,DateFormatterFactory是一个简单的工厂,负责根据地区创建相应的日期格式器。

依赖注入实现
依赖注入通常由框架如Spring来管理:

@Component
public class Application {
    private final DateFormatter dateFormatter;

    @Autowired
    public Application(DateFormatter dateFormatter) {
        this.dateFormatter = dateFormatter;
    }

    public void run() {
        System.out.println(dateFormatter.format(new Date()));
    }
}

@Configuration
public class AppConfig {
    @Bean
    public DateFormatter dateFormatter() {
        // 根据配置或环境自动选择实现
        return new USDateFormatter();
    }
}

在这个例子中,Application类不需要知道DateFormatter的具体实现。它通过构造函数注入(由Spring框架管理)获得所需的依赖。配置类AppConfig负责声明要注入的具体实现类型。

结果和优势
工厂模式:使得对象的创建与使用分离,增加了代码的可管理性和扩展性。客户端需要知道何时调用工厂类来获取对象。
依赖注入:进一步降低了代码之间的耦合,增加了代码的可测试性和灵活性。客户端不需要知道如何和何时获取依赖,这由外部容器自动管理。
选择工厂模式或依赖注入取决于应用程序的

0两核心 IOC和AOP

AOP(面向切面编程)代理设计模式详细解释:
AOP 中的代理设计模式是实现切面(Aspect)功能的关键之一。代理模式允许在目标对象执行前或执行后插入额外的逻辑,从而实现横切关注点的功能。在 AOP 中,代理模式通常与动态代理结合使用,以在运行时创建代理对象,并在需要时将切面织入到目标对象的方法调用中。

代理设计模式的主要角色包括:

目标对象(Target):目标对象是实际执行业务逻辑的对象,它通常是开发人员直接编写的类。

代理对象(Proxy):代理对象包装了目标对象,并在其方法执行前后插入额外的逻辑。代理对象通常实现与目标对象相同的接口或继承相同的父类,以便能够替代目标对象。

在 AOP 中,代理对象可以是静态代理或动态代理:

静态代理:在编译时就已经确定代理对象和目标对象的关系。静态代理需要为每个目标对象编写一个对应的代理类,这种方式比较简单,但是当目标对象变化时,代理类也需要相应地修改。

动态代理:在运行时创建代理对象,并动态地将切面织入到目标对象的方法调用中。Java 中的动态代理通常使用 Java 反射机制来实现。动态代理不需要为每个目标对象编写一个对应的代理类,因此更加灵活,能够适应不同的目标对象。

在动态代理中,常见的代理技术包括 JDK 动态代理和 CGLIB 动态代理:

JDK 动态代理:基于接口的代理,要求目标对象实现一个或多个接口。JDK 动态代理通过 java.lang.reflect.Proxy 类来创建代理对象。

CGLIB 动态代理:基于子类的代理,可以代理没有实现接口的类。CGLIB 动态代理通过创建目标对象的子类来实现代理。

无论是静态代理还是动态代理,代理对象都负责将切面织入到目标对象的方法调用中,从而实现横切关注点的功能。这种代理设计模式在 AOP 中起到了关键作用,使得开发人员可以将关注点集中在切面中,提高了代码的模块化性和可维护性。
面向切面编程(Aspect-Oriented Programming,AOP)是一种编程范式,它允许开发者将横切关注点(cross-cutting concerns)从业务逻辑中分离出来,从而提高代码的模块化。横切关注点指的是那些影响多个类或模块的问题,如日志记录、事务管理、安全性和错误处理等。

AOP通过定义切面(aspect)、连接点(join point)、通知(advice)、切点(pointcut)和引入(introduction)这些核心概念来实现其功能。

切面(Aspect):一个模块化的关注点实现,通常包括交叉多个对象的行为。
连接点(Join point):程序执行过程中的某个特定位置,如方法调用或异常的处理。
通知(Advice):在特定的连接点上执行的动作。通知类型包括:前置通知(Before)、后置通知(After)、环绕通知(Around)、抛出通知(After throwing)和返回通知(After returning)。
切点(Pointcut):匹配连接点的表达式,用于确定在哪些连接点应用通知。
引入(Introduction):添加方法或字段到被通知的类。
示例:日志记录
假设在一个企业应用中,我们需要对所有服务层的方法调用进行日志记录。使用AOP可以非常方便地实现这一需求,而不需要修改实际的业务逻辑代码。

配置AOP切面
使用Spring框架的AOP支持,我们可以创建一个日志记录切面,如下所示:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {
    @Before("execution(* com.example.service.*.*(..))")
    public void logBeforeServiceMethods() {
        System.out.println("Method called: [Service Layer]");
    }
}

在这个示例中,LoggingAspect类定义了一个切面,其中包含一个前置通知。@Before注解表明该通知会在目标方法执行之前执行,execution(* com.example.service..(…))是一个切点表达式,它匹配com.example.service包下所有类的所有方法。

代码示例
假设我们有一个服务类,用于管理用户信息:

package com.example.service;

public class UserService {
    public void addUser(String username) {
        // 添加用户逻辑
    }

    public void deleteUser(String username) {
        // 删除用户逻辑
    }
}

通过上述设置的切面,每次调用addUser或deleteUser方法时,都会先执行logBeforeServiceMethods方法中的日志记录逻辑。

结论
AOP为处理跨多个点的功能提供了一个非常有力的机制,使得代码更加干净、组织性更强。开发者可以集中精力于业务逻辑本身,而将日志记录、事务处理等非业务功能委托给切面来处理。这不仅减少了代码冗余,还增强了程序的可维护性和可扩展性。

前置通知(Before Advice)详细解释
前置通知是面向切面编程(AOP)中的一种通知类型,它允许在目标方法执行之前插入额外的行为。前置通知是用于执行诸如安全检查、日志记录、初始化资源等操作,它是在切点匹配的方法实际执行之前被调用。

核心功能和作用
验证和授权:确保执行操作的用户具有适当的权限。
日志记录:在方法执行前记录重要信息,帮助追踪和诊断。
参数校验:检查传入参数的有效性。
示例:用户验证和日志记录
考虑一个场景,我们需要在执行任何用户操作之前验证用户的身份,并记录这一行为。使用Spring AOP可以非常方便地实现这一需求。

配置前置通知切面
首先,我们创建一个切面用于用户验证和日志记录:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class SecurityAspect {
    
    @Before("execution(* com.example.service.UserService.*(..))")
    public void checkUserAuthentication() {
        // 这里实现身份验证逻辑
        System.out.println("Checking user credentials");
        
        // 这里实现日志记录
        System.out.println("Logging the access before method execution");
    }
}

在这个例子中,SecurityAspect类定义了一个切面,并包含一个前置通知。该通知在com.example.service.UserService中定义的任何方法执行之前运行。

业务逻辑类
假设我们有一个UserService类,管理用户相关操作:

package com.example.service;

public class UserService {
    public void addUser(String username) {
        // 添加用户逻辑
    }

    public void updateUser(String username) {
        // 更新用户逻辑
    }
}

结果和优势
通过上述切面的设置,每次调用UserService中的addUser或updateUser方法之前,checkUserAuthentication中定义的前置通知将先被执行。这样做的优点包括:

集中控制:安全性和日志记录逻辑集中于一个地方,便于管理和修改。
代码清洁和维护性:业务逻辑类更加干净,专注于业务实现,通知负责非业务相关的操作。
灵活性:通过改变切点表达式,可以轻松地更改需要执行前置通知的方法。
前置通知为开发者提供了一种强大的工具,以增强方法的功能性,而无需修改方法本身的代码。这种方法提高了代码的可维护性和可扩展性,是AOP编程中非常重要的一部分。

1注解

@Component代表使用使用bean?
是的,@Component 注解通常用于标记一个类为 Spring 容器管理的组件,也就是说,被 @Component 注解标记的类会被 Spring 自动扫描并且注册为 Spring 容器中的一个 Bean。在 Spring 应用程序中,Bean 是 Spring IoC 容器中管理的对象,可以通过依赖注入的方式在应用程序中被其他组件引用和使用。

除了 @Component 注解之外,Spring 还提供了一系列衍生注解,如 @Controller、@Service、@Repository 等,它们都是 @Component 的特化形式,用于表示特定类型的组件,便于在应用程序中更好地区分不同类型的组件。

例如,@Controller 用于标记一个类为 Spring MVC 控制器,@Service 用于标记一个类为业务逻辑组件,@Repository 用于标记一个类为数据访问组件(通常是用于访问数据库)。这些注解在功能上与 @Component 是等价的,只是用于语义上的区分,让代码更加清晰易读。

2发展历程

J2EE->spring ->springboot 一步步简化

框架历程

单一应用架构
在单一应用架构中,所有功能都被整合到一个应用程序中。这种架构适用于网站流量较小时,因为它能够降低部署节点和成本。在这种情况下,关键是简化增删改查工作量,其中数据访问框架(ORM)起着重要作用。

举例说明:
想象一个小咖啡馆,它只有一个大厅,里面包含了所有的服务,比如点餐、制作咖啡、结账等。在客流量较小的情况下,这种简单而紧凑的结构能够满足需求,减少了维护成本和人力投入。

垂直应用架构
随着访问量的增长,单一应用的性能可能会受到限制。为了提高效率,可以将应用拆分成几个互不相干的子应用。在这种情况下,关键是加速前端页面的开发,这就需要使用 Web 框架(MVC)来实现。

举例说明:
想象一个大型商场,最初只有一个大门和一个前台。随着客流量的增加,为了提高效率,商场决定增加更多的入口、更多的服务台,并且分配给不同的部门。这样一来,前台可以更快地处理客户需求,不同的部门也可以更好地专注于各自的工作。

分布式服务架构
随着应用数量的增加,应用之间的交互也变得更加复杂。为了应对这种情况,可以将核心业务抽取出来,作为独立的服务。在这种情况下,关键是提高业务复用性和整合性,这就需要使用分布式服务框架(RPC)。

举例说明:
想象一个大型电商平台,最初所有的功能都包含在一个单一的应用中,比如商品管理、订单管理、用户管理等。随着业务的发展,为了应对不断增长的用户量和订单量,电商平台将核心业务(比如订单管理)独立出来,作为一个独立的服务。这样一来,不仅可以更好地管理和维护核心业务,还能够更快速地响应市场需求。

流动计算架构
随着服务数量的增加,容量评估和资源利用率管理变得更加重要。在这种情况下,需要增加一个调度中心来实时管理集群容量,提高集群利用率。这就需要使用资源调度和治理中心(SOA)。

举例说明:
想象一个庞大的工厂,里面有许多不同的机器和设备,每个机器都需要不同的资源和能量。为了提高工厂的效率,工厂管理者决定引入一个智能的调度中心。这个调度中心可以根据不同的工作负载和需求,实时分配资源,确保每台机器都能够得到充分利用,同时避免资源的浪费。

从面向过程简化为面向对象,再从面向对象简化为控制反转:
IoC(Inversion of Control:控制反转) 是一种设计思想,而不是一个具体的技术实现。IoC 的思想就是将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理。不过, IoC 并非 Spring 特有,在其他语言中也有应用。为什么叫控制反转?控制:指的是对象创建(实例化、管理)的权力反转:控制权交给外部环境(Spring 框架、IoC 容器)
在这里插入图片描述

spring:
尚硅谷Spring零基础入门到进阶,一套搞定spring6全套视频教程

笔记

3快速学习计划

学习 Spring 框架是一个循序渐进的过程,以下是一个适合一天学习 Spring 的路线安排:

早上:

理解 Spring 框架的基本概念:

了解什么是 Spring 框架,以及它的主要特性和优势。
熟悉 Spring 框架的核心模块,比如 IoC(控制反转)和 AOP(面向切面编程)等。
学习 Spring IoC 容器:

理解 IoC 的概念和原理。
学习如何配置 Spring IoC 容器,包括 XML 配置和注解配置。
实践创建和管理 Spring Bean。
中午:

掌握 Spring 的依赖注入(DI):

理解依赖注入的作用和原理。
学习不同类型的依赖注入方式,包括构造函数注入、Setter 方法注入和字段注入。
实践在 Spring 中进行依赖注入。
了解 Spring AOP(面向切面编程):

了解 AOP 的概念和使用场景。
学习如何使用 Spring AOP 实现横切关注点的处理。
实践编写和配置 AOP 切面。
下午:

学习 Spring MVC:

理解 MVC 架构模式和 Spring MVC 的工作原理。
学习如何配置和使用 Spring MVC,包括控制器、视图解析器、处理器映射等。
实践编写简单的 Spring MVC 应用程序。
深入学习 Spring 数据访问:

学习如何使用 Spring 对各种数据访问技术进行集成,比如 JDBC、Hibernate、MyBatis 等。
实践使用 Spring 进行数据库操作和事务管理。
傍晚:

了解其他 Spring 模块:

学习 Spring Security 来保护应用程序的安全性。
了解 Spring Boot 简化 Spring 应用程序的开发和部署。
了解 Spring Cloud 构建分布式系统和微服务架构。
综合练习和总结:

综合之前学习的知识,完成一些综合练习项目。
总结学习收获,查漏补缺,加深对 Spring 框架的理解。
这只是一个基础的学习路线安排,你可以根据自己的兴趣和实际情况进行调整和扩展。记得在学习过程中不断实践和动手操作,才能更好地掌握 Spring 框架的知识。

Spring Framework 是一个非常广泛和流行的 Java 应用程序开发框架,它提供了一个全面的编程和配置模型。Spring Framework 本身提供了核心功能,如依赖注入、事务管理和模块化服务。基于这个核心框架,开发了许多其他的 Spring 项目,用于支持现代企业应用程序的各种需求。

Spring Framework
Spring Framework 是其他所有 Spring 项目的基础,它提供了基本的编程和配置模型。核心特征包括:
IoC 容器:控制反转容器用于依赖注入。
事件处理:应用程序可以使用标准的观察者模式进行事件发布和响应。
资源管理:提供从多种源(如本地文件系统、Java classpath等)访问资源的抽象。
数据访问:通过JDBC和ORM框架整合提供了一致的数据访问技术。

Spring MVC
Spring MVC 是基于 Spring Framework 的 web 框架,用于构建灵活和可测试的 web 应用。使用 Spring MVC,开发者可以通过控制器类来处理请求,并返回响应。
模型视图控制器:MVC 模式允许分离应用的输入逻辑、业务逻辑和 UI 逻辑。
强大的配置:支持 REST APIs 的构建、数据绑定、类型转换等。

Spring Boot
Spring Boot 是为了简化 Spring 应用的初始搭建及开发过程。它使用了“约定优于配置”的原则,帮助开发者快速启动和运行新项目。
自动配置:自动配置 Spring 和第三方库几乎不需要任何配置。
独立运行:可以创建独立的 Spring 应用程序,可直接运行或作为 jar 包部署。

Spring Cloud
Spring Cloud 为开发者提供了在分布式系统(如配置管理、服务发现、断路器)中常见模式的工具。
分布式配置管理:集中管理所有环境的配置。
服务发现:自动处理服务间的网络通信。

Spring Data
Spring Data 简化了基于 Spring 框架的数据访问技术,支持 NoSQL 和关系数据库的数据访问和管理。
数据仓库抽象:提供统一的数据访问模式减少重复代码。
查询派生机制:允许从方法名自动生成查询。

Spring Security
Spring Security 是一个强大的身份验证和访问控制框架,非常适合为企业应用提供安全性。
全面的安全性:支持身份验证、授权、防止 CSRF 等。
自定义扩展:可通过扩展点自定义安全行为。

结论
Spring Framework 及其相关项目提供了一整套解决方案,帮助开发者在构建现代化的、高性能的、易于测试的 Java 应用程序时,可以更加高效、有组织地工作。这些项目之间的协作性和模块化使得 Spring 不仅仅是一个框架,而是一个完整的企业级应用开发生态系统。

4细节

1.实例化与初始化
在Java编程中,实例化和初始化是创建和设置对象的两个基本步骤。理解这两个概念对于掌握Java对象的生命周期至关重要。

实例化(Instantiation)
实例化是通过使用new关键字创建类的一个新对象的过程。这个过程涉及到为对象分配内存。实例化仅仅是创建了一个类的空间实体,并没有给对象的属性赋予任何具体的值。

MyClass obj = new MyClass();

这里,MyClass是一个类,obj是基于MyClass类创建的对象。使用new关键字,JVM(Java虚拟机)在内存中为MyClass类型的对象分配空间。

初始化(Initialization)
初始化是在实例化后立即发生的过程,其目的是为新创建的对象的成员变量设置初始值。通常,这是通过构造方法(constructor)来完成的。构造方法与类同名,并且在创建对象时自动调用,用于初始化对象的状态。

public class MyClass {
    int number;
    String name;

    // 构造方法
    public MyClass() {
        number = 10; // 初始值
        name = "Hello"; // 初始值
    }
}

在这个例子中,当new MyClass()被调用时,不仅MyClass对象被实例化,而且其构造方法也被调用,将number初始化为10,将name初始化为"Hello"。

实例化与初始化的关系
实例化是创建对象的物理过程(内存分配),而初始化是设置对象的初始逻辑状态(赋值过程)。
实例化后立即进行初始化,确保对象在使用前已被正确设置。
特殊情况:初始化块
Java还支持使用初始化块(instance initializers),这是在任何构造方法运行之前运行的代码块。

示例代码
java
public class MyClass {
int number;
String name;

// 初始化块
{
    number = 30;
    name = "World";
}

// 构造方法
public MyClass() {
    number = 10; // 这将覆盖初始化块中的值
    name = "Hello"; // 这将覆盖初始化块中的值
}

}
在这个例子中,虽然初始化块设置了number和name的值,但构造方法中的赋值将覆盖这些值。无论采用哪种方式,初始化块和构造方法共同确保了对象在使用前已经初始化。

结论
实例化和初始化是创建和准备Java对象的两个密切相关的步骤。通过new关键字进行实例化,通过构造方法或初始化块进行初始化,确保了Java对象在使用前具有合适的初始状态。理解这两个步骤对于有效地使用Java和理解其对象生命周期至关重要。

2用idea创建spring initializr时jdk版本是21而java版本是17
在这里插入图片描述
在使用 IntelliJ IDEA 创建 Spring Initializr 项目时,可能会出现 JDK 版本和 Java 版本不同的情况。这通常是因为 JDK 版本指的是 IntelliJ IDEA 本身使用的 Java 开发工具包版本,而 Java 版本指的是新创建的项目将要使用的 Java 编译版本。

让我们详细解释一下:

JDK 版本:

JDK 版本是指 IntelliJ IDEA 使用的 Java 开发工具包版本。在创建项目时,IDEA 需要知道在后台执行代码的 Java 开发环境的版本。
当你在创建项目时选择 JDK 版本,你实际上是告诉 IntelliJ IDEA 使用哪个版本的 Java 开发工具包来编译和运行你的代码。这通常不会影响你的项目的 Java 编译版本。
Java 版本:

Java 版本是指你的项目将要使用的 Java 编译版本。这决定了你的项目可以使用的 Java 语言的功能和语法。
当你选择项目的 Java 版本时,你决定了在编译和运行你的项目时所使用的 Java 语言版本。这会影响你能否使用该版本中引入的新特性以及项目的兼容性。
在创建 Spring Initializr 项目时,通常会选择与你的项目要求和你打算使用的 Java 版本兼容的 JDK 版本。例如,如果你计划使用 Java 17 版本的语言特性,则可能需要选择 IntelliJ IDEA 配置的 JDK 版本为 JDK 17 或更高版本,以确保你可以使用最新的语言功能。

总的来说,在创建 Spring Initializr 项目时,JDK 版本和 Java 版本不同通常是合理的,因为它们分别指示了 IntelliJ IDEA 使用的开发环境和项目将要使用的编译版本。
Java 编译版本指的是在编写 Java 代码后,通过编译器将其转换为 Java 字节码的版本。这个版本决定了你的代码能否在特定版本的 Java 虚拟机(JVM)上运行。

以下是关于 Java 编译版本的详细说明:

语言特性支持:

每个 Java 编译版本都会引入新的语言特性和改进。这些特性可以包括新的语法、标准库的改进、性能优化等。因此,选择合适的编译版本可以让你使用最新的语言特性和优化,提高代码的可读性、性能和安全性。
兼容性:

Java 编译版本也决定了你的代码在不同的 Java 运行时环境(JRE)或 Java 虚拟机(JVM)上的兼容性。如果你使用了某个编译版本引入的特性,而该特性在目标环境中不受支持,那么你的代码可能无法在该环境中运行,或者会出现异常。
更新周期:

Java 的编译版本通常会随着 Java 平台的版本发布而更新。例如,Java 8 引入了诸如 lambda 表达式和 Stream API 等新特性,而 Java 9、Java 10、Java 11 等版本都陆续引入了更多的改进和新特性。
Oracle 和其他 Java 平台提供商通常会发布 JDK 版本,其中包含了特定的编译器版本。因此,你可以根据需要选择相应的 JDK 版本来使用特定的 Java 编译版本。
指定编译版本:

你可以使用 Java 编译器的 -source 和 -target 选项来指定编译版本。-source 选项用于指定你的代码应该符合的语言版本,而 -target 选项用于指定生成的字节码应该兼容的 Java 运行时环境的版本。
例如,如果你使用 Java 17 编写代码,并且想要将其编译为与 Java 8 兼容的字节码,你可以使用以下命令:
javac -source 17 -target 8 MyClass.java
总的来说,Java 编译版本决定了你的代码的语言特性支持和兼容性,选择合适的编译版本可以确保你的代码在不同的 Java 运行时环境中正确运行,并且可以利用最新的语言特性和优化。

2
IDEA创建一个springboot项目教程(过程中各种报错解决)
idea创建springboot项目连不上国外的网站https://start.spring.io/或者过慢,如果maven配置好了还报错,那就换一个国内的阿里的网站,也可以进行初始化,但是可以选择的版本没有官网多,但是快,基本满足需要。网址为:http://start.aliyun.com 就点击那个初始化网站叛变的小设置按钮,使用这个网址

3
初始化项目的时候,使用的URL是阿里云版的。官网的是采用继承的parent标签。阿里云是直接通过引用依赖,所以看不到parent标签。

1. Spring Core
2. Spring MVC

当我们谈论 Spring 框架时,通常会涉及到 Spring MVC 和 Spring Boot。让我们用一种形象生动的方式来解释它们之间的区别和联系。

想象一家新开的餐厅,它的菜单上有各种各样的菜品。现在,我们将这家餐厅比作是 Spring 框架,菜品就是 Spring 框架中的不同模块和功能。

Spring MVC:餐厅的主厨和服务员

Spring MVC 就像是餐厅的主厨和服务员,负责接待客人、处理订单、准备食物等。它是 Spring 框架中的一个模块,专门用于构建 Web 应用程序。Spring MVC 提供了一种基于 MVC(Model-View-Controller)模式的方式来开发 Web 应用,通过 DispatcherServlet、Controller、ViewResolver 等组件来处理用户请求并返回响应。它可以处理请求映射、数据绑定、视图解析等 Web 开发相关的任务。
Spring Boot:快捷的外卖服务

Spring Boot 就像是餐厅的外卖服务,它提供了一种快速、简便的方式来启动和部署 Spring 应用程序,就像是通过外卖服务可以快速地将食物送到客人家里一样。Spring Boot 极大地简化了 Spring 应用程序的开发和部署过程,通过自动配置、约定大于配置等特性,让开发者可以快速搭建起一个生产就绪的应用程序,而不需要过多的配置。
联系与区别:餐厅的运作

Spring MVC 和 Spring Boot 并不是相互排斥的,而是可以配合使用的。就像是餐厅的主厨和外卖服务可以一起协作,提供不同的服务。
Spring MVC 是 Spring 框架的一部分,专门用于构建 Web 应用程序,而 Spring Boot 则是一个独立的项目,旨在简化 Spring 应用程序的开发和部署。Spring Boot 可以集成 Spring MVC,并提供一些额外的功能,比如自动配置、内嵌服务器等。
使用 Spring Boot 可以快速搭建一个基于 Spring MVC 的 Web 应用程序,并且可以通过自动配置和约定大于配置的方式来减少配置量,提高开发效率。
总之,Spring MVC 和 Spring Boot 都是 Spring 框架中的组件,各自担任着不同的角色,但可以协同工作,为开发者提供更便捷的开发体验和更高效的应用部署方式。

3. Spring Boot
1约定大于配置

springboot里把service注入controller,把dao注入service
在Spring Boot中,通常使用依赖注入(Dependency Injection)来管理应用程序的各个组件,例如将Service注入Controller、将DAO(Data Access Object)注入Service等。这种依赖注入的方式使得组件之间的关系更加松散,提高了代码的灵活性和可维护性。

下面我会详细解释并通过一个示例来说明在Spring Boot中如何将Service注入Controller,以及将DAO注入Service:

将Service注入Controller:
在Spring Boot中,Controller负责接收HTTP请求并处理它们,而Service通常包含业务逻辑。要将Service注入Controller,我们首先需要在Service类上使用@Service注解,以便Spring Boot能够识别它作为一个服务组件。然后在Controller中使用@Autowired注解将Service注入Controller。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class MyController {

    private final MyService myService;

    @Autowired
    public MyController(MyService myService) {
        this.myService = myService;
    }

    @GetMapping("/hello")
    public String sayHello() {
        return myService.getMessage();
    }
}

import org.springframework.stereotype.Service;

@Service
public class MyService {

    public String getMessage() {
        return "Hello from Service!";
    }
}

在这个示例中,MyService类被标记为@Service,表示它是一个服务组件。在MyController中,我们使用@Autowired将MyService注入到Controller中,这样就可以在Controller中调用Service的方法。

将DAO注入Service:
DAO是用于访问数据库的组件,在Spring Boot中,通常使用@Repository注解标记DAO类。要将DAO注入到Service中,我们可以使用@Autowired注解。

示例代码如下:

java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class MyService {

    private final MyDAO myDAO;

    @Autowired
    public MyService(MyDAO myDAO) {
        this.myDAO = myDAO;
    }

    public String fetchData() {
        return myDAO.getData();
    }
}
import org.springframework.stereotype.Repository;

@Repository
public class MyDAO {

    public String getData() {
        // 在这里执行数据库操作,返回数据
        return "Data from database";
    }
}

在这个示例中,MyDAO类被标记为@Repository,表示它是一个数据访问组件。在MyService中,我们使用@Autowired将MyDAO注入到Service中,这样就可以在Service中调用DAO的方法来访问数据库。

通过依赖注入,我们可以轻松地管理Spring Boot应用程序中的各个组件,并且使它们之间的关系更加清晰和可维护。

2springboot详细运行过程

狂神说
狂神说笔记更全

面试官问你你可以这样说,springboot是通过main方法下的SpringApplication.run方法启动的,启动的时候他会调用refshContext方法,先刷新容器,然后根据解析注解或者解析配置文件的形式注册bean,而它是通过启动类的SpringBootApplication注解进行开始解析的,他会根据EnableAutoConfiguration开启自动化配置,里面有个核心方法ImportSelect选择性的导入,根据loadFanctoryNames根据classpash路径以MATA-INF/spring.factorces下面以什么什么EnableAutoConfiguration开头的key去加载里面所有对应的自动化配置,他并不是把这一百二十多个自动化配置全部导入,在他每个自动化配置里面都有条件判断注解,先判断是否引入相互的jar包,再判断容器是否有bean再进行注入到bean容器
在这里插入图片描述
在这里插入图片描述

3配置用yaml(严格要求空格)很流行

近年来,YAML因其简单性、可读性以及在各种应用中的灵活性而持续流行,被广泛用于配置文件和软件程序之间的数据交换。YAML在软件行业和开源社区中的使用已经稳定增长了十年以上。它能够轻松整合到不同的编程环境中,并且其用户友好的语法是其广泛使用的关键因素。YAML常用于需要数据对人类和机器都易于理解的场景,使其成为配置、文档编制和DevOps流程设置的理想选择。
yaml需要配合注解@ConFigurationProperties,可以批量
在这里插入图片描述

在这里插入图片描述

springboot在resources中只需要application.yml或者application.properties
在这里插入图片描述

4JSR 303 数据校验详解

JSR 303 是 Java 的一个标准规范,用于在 Java 应用程序中提供声明式的数据验证机制。该规范定义了一组内置的注解和API,允许开发者通过简单的注解直接在 JavaBean 的属性上声明验证规则,使得数据验证逻辑更简洁、更易于管理。

JSR 303 核心注解
下面是一些常用的 JSR 303 注解及其作用:

@NotNull:确保字段不为空。
@Size(min=, max=):验证字段(字符串、集合、数组)长度是否在给定的范围之内。
@Min(value):验证字段的值是否大于或等于指定的最小值。
@Max(value):验证字段的值是否小于或等于指定的最大值。
@Pattern(regexp):验证字符串字段是否符合正则表达式定义的格式。
示例:使用 JSR 303 进行数据校验
假设我们有一个用户注册的场景,需要验证用户输入的数据。以下是一个简单的 User 类,应用了 JSR 303 注解来确保数据满足业务要求:

import javax.validation.constraints.*;

public class User {
    @NotNull(message = "用户名不能为空")
    private String username;

    @NotNull(message = "密码不能为空")
    @Size(min = 6, max = 15, message = "密码长度必须在6到15字符之间")
    private String password;

    @Min(value = 18, message = "必须年满18岁")
    @Max(value = 100, message = "年龄不能超过100岁")
    private int age;

    @Email(message = "邮箱格式不正确")
    private String email;

    // 构造函数、getter 和 setter 省略
}

使用场景
在一个典型的 Spring Boot 应用中,你可以在控制器层使用 @Valid 注解来自动应用这些验证规则,如下:

import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;

@RestController
public class UserController {

    @PostMapping("/register")
    public String registerUser(@RequestBody @Valid User user) {
        // 如果 User 对象的字段不符合注解定义的规则,将抛出异常
        return "注册成功";
    }
}

在上述例子中,当一个 POST 请求到达 /register 路由时,Spring MVC 会自动校验传入的 User 对象。如果数据验证失败,它会返回一个错误响应,通常包含具体的错误信息,告诉用户哪些字段没有通过验证。

结论
JSR 303 提供的声明式验证机制,极大简化了 Java 应用程序中的数据校验工作。通过在模型层直接使用注解定义规则,开发者可以轻松地确保数据的完整性和正确性,同时使代码更加整洁和易于维护。这种方法在处理表单数据和用户输入验证时特别有用,有效防止无效或恶意的数据输入。
在这里插入图片描述

5 区别:@Controller 与 @RestController

在 Spring 框架中,@Controller 和 @RestController 注解用于定义Web层的类,但它们在用途和行为上有明显的区别。

@Controller
用途:@Controller 通常用于定义传统的 Spring MVC 应用程序中的控制器,主要用于页面导航。
视图解析:返回值通常是一个指向视图(如 JSP 页面)的字符串,由视图解析器解析,用于生成HTML内容。
数据返回:如果需要返回数据而非视图,需要结合 @ResponseBody 注解使用,这样返回的数据(如 JSON 或 XML)会直接写入 HTTP 响应体中。
@RestController
用途:@RestController 是在 Spring 4.0 中引入的,专为构建RESTful Web服务设计。它是 @Controller 和 @ResponseBody 注解的组合。
数据返回:类中的所有方法默认通过 @ResponseBody 注解处理,意味着方法的返回值直接作为HTTP响应体返回,通常是JSON或XML格式。
简化开发:这种注解方式简化了控制器的实现,不需要在每个方法上重复 @ResponseBody 注解,使得代码更简洁,专注于服务的数据处理。
示例
下面的示例展示了如何使用这两个注解:

// 使用@Controller
@Controller
public class WebController {

    @RequestMapping("/home")
    public String home() {
        return "home";  // 返回视图名
    }

    @RequestMapping("/data")
    @ResponseBody
    public Map<String, String> data() {
        return Collections.singletonMap("key", "value");  // 返回数据
    }
}

// 使用@RestController
@RestController
public class ApiController {

    @RequestMapping("/info")
    public Map<String, String> info() {
        return Collections.singletonMap("key", "value");  // 直接返回数据
    }
}

在 WebController 中,home 方法返回一个视图名称,由 Spring MVC 通过配置的视图解析器处理。而 data 方法则需要 @ResponseBody 注解来直接返回数据。

在 ApiController 中,由于使用了 @RestController,所有方法默认都会将返回值用作HTTP响应体,适用于构建返回JSON或XML的RESTful接口。

结论
选择 @Controller 或 @RestController 主要取决于你的应用场景。如果你在开发传统的Web应用,涉及到页面渲染,使用 @Controller 较为合适。如果是构建API或服务,主要返回数据,使用 @RestController 更为便捷。

6 idea查看注解源码

ctrl+alt+b
双击shift
ctrl+F是字段搜素

4. Spring进阶(可暂时不学)

第五阶段:消息队列(预计1-2周)

异步消息:
异步消息是一种在系统中传递和处理信息的方式,其中发送者和接收者之间的通信是非阻塞的,发送者不需要等待接收者的响应即可继续执行其他任务。这种方式的优点在于可以提高系统的吞吐量和性能,并且使系统更具弹性,因为发送者和接收者可以以自己的速度工作。

举个生动的例子,假设有一个在线电商平台,用户下单后需要发送一封确认邮件给用户。在同步处理的情况下,系统可能会等待邮件服务器发送邮件并收到响应,然后才会继续执行其他任务,这可能会导致用户在下单时出现延迟。而使用异步消息,则可以将发送邮件的任务放入消息队列中,然后立即返回用户一个下单成功的响应,而不用等待邮件发送完成。

具体来说,在这个例子中,系统的架构可能如下:

用户下单后,订单服务将订单信息发送到一个名为"订单队列"的消息队列中。

订单服务收到订单后,不需要等待邮件发送完成,而是立即返回给用户一个下单成功的响应。

同时,有一个邮件服务监听"订单队列",一旦有新的订单信息被放入队列,就会立即收到通知。

邮件服务收到通知后,从队列中获取订单信息,并根据订单信息发送确认邮件给用户。

这样,订单服务和邮件服务之间的通信就是异步的,订单服务可以立即返回响应给用户,而邮件服务则可以在后台处理发送邮件的任务,而不会影响用户体验。

在这个例子中,消息队列起到了缓冲的作用,使得系统的各个组件可以独立工作,提高了系统的并发处理能力和性能。

1. RabbitMQ

提示:这里可以添加技术名词解释

例如:

  • Bert
  • GPT 初代
  • GPT-2
  • GPT-3
  • ChatGPT

第六阶段:如何做一个网站

在这里插入图片描述

例如:

  • API
  • 支持模型类型

小结

提示:这里可以添加总结

例如:

提供先进的推理,复杂的指令,更多的创造力。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值