了解Spring

news2024/12/23 18:04:24

目录

什么是Spring?

DI

Spring 存与取

spring 的存操作

spring的取操作

更快速的进行 Spring  存 与 读

三大注入方式

@Autowired

set 注入

构造方法注入

Spring 容器中有多个相同的类时

Bean 作用域

设置作用域

Spring 执行流程

 Bean 生命周期


什么是Spring?

Spring : 它是一个开源框架 , 是包含了众多工具方法的 IoC 容器 , (说的就是对象的创建和销毁的权利都交给了 Spring 来管理了,它本身又具备了存储对象和获取对象的能力,通俗点来讲Spring就是容器, 帮我们管理对象的生命周期) 。

Spring 的核心功能就是 :如何将对象存入到 Spring 中,再从 Spring 中获取对象的过程。

IoC :(Inversion of Control) 控制反转 ,它是一种思想。

从文字上去了解肯定有点难懂,让我们拨开层层迷雾,一一道来。

先来解释一下什么是 控制反转  ,举个栗子 : 

 

设计这么一个关系链,最开始的思想:汽车调用车身,车身调用底盘,底盘调用轮胎,需要的参数都通过构造方法去传递。

代码如下 : 

// 汽车
public class Car {
    Framework framework = new Framework(12);
    public void init() {
        framework.init();
    }
}
// 车身
public class Framework {
    private Bottom bottom;
    public Framework(int size) {
        bottom = new Bottom(size);
    }
    public void init() {
        bottom.init();
    }
}
// 底盘
public class Bottom {
    // 大小
    private Tire tire;
    public Bottom(int size) {
        tire = new Tire(size);
    }
    public void init() {
        tire.init();
    }
}
// 轮胎
public class Tire {
    // 大小
    private int size;
    public Tire(int size) {
        this.size = size;
    }
    public void init() {
        System.out.println("轮胎大小:" + size);
    }
}

这种思想弊病在于:假设轮胎这一层需要加一个参数,这时底盘调用轮胎就得变,因为参数都是由汽车这个类传进来,因此车身调用底盘的参数就要变,汽车调用车身的参数也要变,牵一发而动全身

 

将思想再改变一下,我们将需要的参数进行封装,每次传递的时候,传递一个对象,这么即使需要修改参数,直接修改对象就好了。

代码如下 :

// 测试类
public class Main {
    public static void main(String[] args) {
        Tire tire = new Tire(12);
        Bottom bottom = new Bottom(tire);
        Framework framework = new Framework(bottom);
        Car car = new Car(framework);
        car.init();
    }
}
// 汽车
public class Car {
    private Framework framework;
    public Car(Framework framework) {
        this.framework = framework;
    }
    public void init() {
        framework.init();
    }
}
// 车身
public class Framework {
    private Bottom bottom;
    public Framework(Bottom bottom) {
        this.bottom = bottom;
    }
    public void init() {
        bottom.init();
    }
}
// 底盘
public class Bottom {
    // 大小
    private Tire tire;
    public Bottom(Tire tire) {
        this.tire = tire;
    }
    public void init() {
        tire.init();
    }
}
// 轮胎
public class Tire {
    // 大小
    private int size;
    public Tire(int size) {
        this.size = size;
    }
    public void init() {
        System.out.println("轮胎大小:" + size);
    }
}

这时我们的创建类的顺序就变成了 : Tire -> Bottom -> Framework -> Car.

最开始的创建类的顺序 : Car -> Framework -> Bottom -> Tire

第一次实现 是将 Car 创建 Framework , Framework 创建了 Bottom,依次往下,这样做,都是由上级对象创建并控制下级对象,而第二次实现则是将下级对象注入到当前对象中,此时下级对象的生命周期不在当前对象中,因此下级对象的控制权就不再由上级对象控制,这样即使下级类发生变化,当前类都是不受影响的。这就是IoC思想 , 这就是控制反转. 

对比上面两种思想,IoC 更为灵活,所有对象的生命创建和销毁的权利都交给了Main,Spring扮演的就是Main的角色。

 

DI

DI :(Dependency Injection)“ 依赖注入 ”。

DI :在程序运行期间,动态的将某个对象引入到当前类的机制。实现了对象之间的解耦。

DI 与 IoC 的关系 :

IoC 它就是一种思想,而 DI 就是实现了IoC这种思想的技术。

就像是 乐观锁 是一种思想,而 CAS 就是一种具体实现的技术。

Spring 存与取

创建一个 maven 项目 , 引入Spring的依赖 .这样得到一个Spring的项目.

spring 的存操作

第一步 , 创建一个Bean对象 . (Bean对象就是java代码中的类)

public class T {
    public String First() {
        return "First";
    }
}

第二步 ,  将 Bean 对象存储到 Spring 当中.

 其中 , 第一小步, 在resources 目录下创建一个spring的配置文件.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:content="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!--    <content:component-scan base-package="com.demo"></content:component-scan>-->

</beans>

将Bean对象放在这个配置文件中 , 这样在Spring在启动项目时 , 这些Bean对象会被初始化出来.

第二小步 , 将 Bean 对象配置到 Spring 配置文件中 .

spring的取操作

取操作 : 首先得到 Spring (上下文) 对象 , 然后从Spring中取出对象 .

public class Main {
    public static void main(String[] args) {
        // 1. 先得到 Spring (上下文) 对象
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        // 2. 从 Spring 中取出 Bean对象
        T t = (T)context.getBean("first"); // 根据 id 来得到 Bean 对象,如果参数为null那么就会强转错误
        // T t = context.getBean(T.class); // 根据 Bean对象的类型来获取 Bean对象 , 但如果Spring中存在相同的对象时,这时使用类型来获取Bean方式就会报错.
        // T t = context.getBean("first",T.class) 根据 id 和 Bean 类型获取 Bean 对象
    }
}

 

 除了ApplicationContext 可以获得Spring对象之外 , BeanFactoy 也可以获取 Spring 对象。

 BeanFactory context = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));

关于 ApplicationContextBeanFactory区别

相同点 : 都是可以得到 Spring 上下文对象。都是来自 Spring 的顶级接口。

不同点 : 在继承关系和功能上 : ApplicationContext  属于 BeanFactory 的子类。BeanFactory 只有最基础的访问 Bean 的能力,而 Application 除了拥有 父类 BeanFactory 功能外,还包含了更多的功能,例如:国际化支持、资源访问、时间传播 等等

                从性能上来看 : ApplicationContext 加载方式是将 Bean 对象一次性加载,所以在后面访问 Bean 对象时会比 BeanFactory 快,(牺牲了空间换取了时间)。BeanFactory 需要某个Bean对象 时,才去加载Bean 对象,所在它在执行 Bean 获取时,速度会比较慢。

更快速的进行 Spring  存

最开始的存就是往 xml 的配置文件中放 Bean对象,但如果后期的项目足够大,对象越来越多,那么这个放操作就会很繁琐并且难以维护。因此使用注解可以更快速的进行存与取。

要做的工作首先,配置要扫描的路径,(也就是那些包下的类需要被加载到 Spring 中),效率会更高。

 重点注意:如果想要加载的对象不在扫描路径下,那么就不能被加载到Spring的IoC容器中

将对象存储到 Spring 中,有两种注解类型可以实现:

1 .  首先是类注解 : @Controller 、@Service 、@Repository 、@Component 、@Configuration

五大类注解 :在项目中扮演的角色是不一样的。

@Controller (控制器): 归属于业务逻辑层,用来控制用户的行为,它主要是用来检查用户参数的有效性。

@Service (服务) :  归属于服务层,调用持久层的类实现相应的功能。(它不会直接和数据库直接交互,像是控制中心一样的存在)

@Repository (仓库) :归属于持久层,是直接和数据库进行交互的。

@Configuration (配置) : 归属与配置层,是用来配置当前项目的一些信息。

@Component (组件) : 归属于公共工具类 , 提供公共方法。

对于上述的5大注解 ,举个栗子:登录博客,这时要输入账号和密码,回车键一摁,前端将请求发给后端,后端拿到信息就会先核实一下登录信息是否正确 这个操作就是 控制器来管理的,而如果你想要发布一个博客,Controller就会调用服务层,服务层会根据请求会涉及到那些功能去进行调用持久层,持久层就会去调用数据库中的表。

@Controller // 注解
public class UController {
    public String inp() {
        return "采用注解方式来注入";
    }
}
public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        UController uController = context.getBean("UController",UController.class);
        System.out.println(uController.inp());
    }

 获取Bean对象 :

如果使用最开始的获取Bean对象的方式,默认情况下 id 就是将类名首字母小写。

特殊情况下:如果类名的首字母和第二个字母都是大写的情况下此时 id 就是原类名。

可以看Spring中的源码

2 .  采用方法注解 : @Bean

@Bean 注解,如果没有给@bean设置name属性的话,默认情况下 获取对象的 id 就是方法名,并且如果设置了name属性之后,那么就不能再使用 方法名来获取对象了。

注意:在采用方法注解时,是将方法返回的对象放入到 Spring 当中。

           使用@Bean注解时,要配合5大类注解来使用。否则会是无效注解。

@Controller
public class UController {
    @Bean
    public UController inp() {
        return new UController();
    }
}
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        UController uController = context.getBean("inp",UController.class);
    }
@Controller
public class UController {
    @Bean(name = {"n1","n2"}) // 设置name属性
    public UController inp() {
        return new UController();
    }
}
public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        UController uController = context.getBean("n1",UController.class);
    }

三大注入方式

@Autowired

接下来 , 我们使用注解的方式来获取对象。

public class User {
    // 使用属性注入的方式获取 Bean对象
    @Autowired
    private UController uController;
}

加上 @Autowired ,Spring就会自动把对象赋值给变量。

@Autowired 

优点 : 实现简单

缺点 :1. 功能性问题 :不能注入不可变(final)对象。(final对象要么直接赋值,要么在构造方法中赋值)

 2 . 通用性问题 : 只适用于 IoC 容器。 

 3 . 设计原则问题 : 更容易违背单一设计原则。(因为属性注入的方式更简便 从而就会导致滥用,所以它更容易违背单一设计原则)。

set 注入

public class User {
    // 2. set 注入
    private UController uController;
    @Autowired
    public void setuController(UController uController) {
        this.uController = uController;
    }
    public void hi() {
        System.out.println("hi");
    }
}

优点 : 更加符合单一设计原则。(相比起属性注入,set 注入更繁琐,因此更加符合单一设计原则)

缺点 : 1. 不能注入不可变对象。

             2. 注入对象可被修改。(set方法是普通 set 方法, 可以被重复调用,在被调用时就存在修改的风险)

构造方法注入

public class User {
    private UController uController;
    @Autowired
    public User(UController uController) {
        this.uController = uController;
    }
}

优点 : 构造方法注入相比与前两种注入方法,它可以注入不可变对象,并且它只会执行一次,也不存在像Setter注入那样,被注入的对象随时被修改的情况。

1 . 可注入不可变对象。

2 . 注入对象不会被修改

3 . 注入对象会被完全初始化

4 . 通用性更好。

附加 :

@Resource VS @Autowried

相同点 : 都是用来实现依赖注入的。

不同点 :1. @ Autowired 来自于 Spring,而 @Resource 来自于 JDK 。

                2. 相比起 @Autowired  ,@Resource 支持更多的参数设置,例如 name 设置,根据名称获取 Bean。

                3. @Autowired 可用与 Setter 注入,构造方法注入和属性注入。而@Resource 只能用于Setter注入和属性注入,不能使用构造方法注入。

Spring 容器中有多个相同的类时

@Component
public class PeopleBeans {
    @Bean
    public Student student1() {
        return new Student();
    }
    @Bean
    public Student student2() {
        return new Student();
    }
}

@Controller
public class PeoController {
    @Resource
    private Student stu;
    public void fun() {
        System.out.println(stu.toString());
    }
}

public class Student {
    private int age = 10;
    public Student() {
        System.out.println("实现了构造方法");
    }
    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                '}';
    }
}

// 测试
public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
    }
}

 报错的原因是因为容器中有两个相同的类 , 程序无法确定将那个依赖注入,因此弹出错误让程序猿处理.

解决方案 : 

如果使用 @Resource : 可采用 name 属性来指定依赖的名称 

@Resource(name = "student1")

如果使用 @Autowried : 可以配合 @Qualifier 来设置依赖的名称

@Autowired
@Qualifier("student1")

Bean 作用域

Bean 作用域 : Bean 在整个 Spring 框架(项目)中的行为模式 . 

六大作用域 :

1 . singleton : 单例作用域 (默认情况下的作用域)

2 . prototype : 原型作用域 (多例作用域)

 以下四种都是在SpringMVC 中存在 :

3 . request : 请求作用域

4 . session : 回话作用域

5 . application : 全局作用域

6 . websocket : HTTP WebSocket 作用域

其中 singleton 是默认选择的作用域 , 它在 IoC容器中只存在一份 , 无论是通过 ApplicationContext 或者 注解的方式获取到的都是同一个对象.

prototype : 每次从IoC容器中取出都会是一个新的对象 .

其中 request : 每次 http 请求会创建新的Bean实例 , 类似于 prototype . 

session : 在一个 http session 中, 定义一个 Bean 实例, 一般用来记录用户的登录信息.

singleton 与 application 的区别

singleton 是 Spring Core 的作用域 , application 是 Spring Web 的作用域.

singleton 作用 IoC 的容器, 而 application 作用于 Servlet 容器 .

设置作用域

使用 @Scope 注解 , 可以修饰类或者方法.

以下两种方式都可以 :  

@Scope("prototype")
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

Spring 执行流程

首先启动Spring项目 , 结合 xml 文件对Bean对象进行初始化 , 根据配置好的目录扫描带有五大注解的类或者带有@Bean注解的方法 , 将这些Bean对象注册到容器中. 最后给带有@Autowried 和 @Resource 注解的变量进行依赖注入 .

 Bean 生命周期

生命周期指的是一个对象从诞生到销毁的整个生命过程 , 我们将这个过程叫做一个对象的生命周期 .

Bean的生命周期主要分为 5 个部分 :

1 . 实例化 Bean (为对象分配内存 , 将字节码转换成内存中的对象 , 实现了从无到有,这是Bean里面什么也没有)

2 . 设置属性 (Bean 注入和装配)

3 . Bean 初始化 (各种通知 , 进行初始化的前置工作,进行初始化工作 [使用注解 @PostConstruct 初始化, 使用 (xml) init - method 初始化],初始化的后置工作)

4 . 使用Bean 

5 . 销毁Bean

End........

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/713709.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【密码学基础】半/全同态加密算法基础学习笔记

文章目录 1 半同态加密Pailliar加法同态加密Paillier加解密过程Paillier的同态性Paillier的安全性 El Gamal乘法同态加密RSA乘法同态加密 2 全同态加密BFV全同态加密BFV的编码方式BFV加解密过程BFV的安全性BFV的同态性自举Bootstrapping 3 同态加密应用场景场景1&#xff1a;安…

【maven】安装、使用和常用命令

安装 windows 下载Maven二进制文件 前往Apache Maven官方网站 (https://maven.apache.org) &#xff0c;找到最新的稳定版本&#xff0c;然后下载对应的二进制压缩包&#xff08;如apache-maven-3.8.2-bin.zip&#xff09;。解压缩文件 将下载的压缩包解压到你选择的目录&…

QCC51XX---chain修改

QCC51XX---系统学习目录_嵌入式学习_force的博客-CSDN博客 如何去修改音频chain链路,就是那种想多加几条输入源或输出,又或者把当前的输入输出换到别的地方的那种应用。例如一个自带mic的dongle,或者模拟输入的LE dongle。 如果要改某个状态下的音频链路,那就需要先找出默认…

修复常见 Android 问题的 9 款顶级 Android 手机维修软件

许多人发现Android手机或平板电脑上的Android操作系统一开始运行得很好&#xff0c;但随着时间的推移&#xff0c;可能会出现各种Android系统问题。您可能会遇到一些问题&#xff0c;例如系统速度变慢、启动无响应、挂起错误、界面冻结、短信停滞、应用程序崩溃等。那么&#x…

Linux学习之内存查看命令free和top

我用来演示的系统使用CentOS Linux release 7.6.1810 (Core)&#xff0c;内核版本是3.10.0-957.el7.x86_64。 Linux在进程申请内存的时候&#xff0c;一般都是尽可能给进程内存&#xff0c;因为进程在申请内存的时候有损耗。 free free命令可以看以k为单位的内存。 free -…

使用less命令搜索文件中的关键字

目录 介绍常用搜索技巧实例 介绍 less 与 more 类似&#xff0c;less 可以随意浏览文件&#xff0c;支持翻页和搜索&#xff0c;支持向上翻页和向下翻页。 语法 less [参数] 文件 参数说明&#xff1a; -b <缓冲区大小> 设置缓冲区的大小 -e 当文件显示结束后&#xff…

STM32 USART

USART.C 文件中只是针对串口1&#xff0c;使用其他串口需要稍作修改 IC、SPI主要用于一块开发板上两个芯片之间的通信&#xff0c;例如&#xff1a;主控和传感器之间的通信 串口适用于两块开发板之间的通信&#xff0c;或者说开发板和上位机之间的通信&#xff0c;有线通信 以…

MAC OS X 这个“安装 macOS Xxx Xxx”应用程序副本已损坏,不能用来安装 macOS,超级终端修改日期date 已解决

原因&#xff1a;旧版 macOS 证书已经过期 解决方法&#xff1a;断开互联网&#xff0c;修改系统时间 date 102013142018.20 说明&#xff1a;10是月&#xff0c;20是日&#xff0c;13是时&#xff0c;14是分&#xff0c;2018是年&#xff0c;20是秒 输入上面的代码按回车后…

【ARM】-异常与中断

文章目录 中断中断请求、中断源中断服务程序保存现场、恢复现场中断仲裁、中断优先级中断嵌套 异常广义上的异常同步异常异步异常精确异步异常&#xff08;Precise Asynchronous Exception&#xff09;非精确异步异常&#xff08;Imprecise Asynchronous Exception&#xff09;…

发展零碳数据中心,超聚变推动液冷规模商用

算力的发展犹如一体两面。 一方面&#xff0c;在数字经济、产业数字化和数字化转型中&#xff0c;算力发挥着关键的引擎作用&#xff1b;另一方面&#xff0c;持续增长的多元异构算力需求、不断提升的算力密度以及逐渐成体系的算力网络&#xff0c;也带来了不可低估的长期能耗…

Linux基础笔记

已经有很长很长一段时间没有更新帖子了&#xff0c;一眨眼2023 已经过半&#xff0c;这些日子里&#xff0c;有太多太多事情要做了&#xff0c;今年只更新了几篇&#xff0c;这几天刚好有空&#xff0c;浅浅更新一篇叭&#xff01;~~~ 首先&#xff0c;Linux是一种开源的操作系…

测试开发工程必备技能之一:Mock的使用

目录 1. 背景 2. Mock是什么 3. Mock能做什么 4. Mock实现方式 5. Mock市面上常见的解决方案 6. Python下unittest.mock使用 总结&#xff1a; 1. 背景 在实际产品开发过程中&#xff0c;某个服务或前端依赖一个服务接口&#xff0c;该接口可能依赖多个底层服务或模块&…

K8S | 容器和Pod组件

对比软件安装和运行&#xff1b; 一、场景 作为研发人员&#xff0c;通常自己电脑的系统环境都是非常复杂&#xff0c;在个人的习惯上&#xff0c;是按照下图的模块管理电脑的系统环境&#xff1b; 对于「基础设施」、「主机操作系统」、「系统软件」来说&#xff0c;通常只做…

MYSQL根据标签查询数据

场景条件&#xff1a; 1.根据用户id查询到该id绑定的标签&#xff08;可能是多个标签也可能是单个标签&#xff09; 2.根据标签的id查询到绑定标签id的信息表 SELECT labelID FROM LRrelation WHERE relationID 1 SELECT * FROM notification SELECT * FROM notification…

解决GitHub下载速度太慢问题的方法汇总(持续更新,建议收藏)

文章目录 前言一、使用 git clone --depth1 来下载二、修改host文件解决三、谷歌浏览器插件加速四、油猴插件和脚本五、gitclone.com六、Github 加速下载链接七、Github 镜像访问八、使用码云下载参考资料&#xff0c;感谢以下文章 前言 Github上下载仓库或者克隆仓库&#xf…

运输层:TCP流量控制

1.运输层&#xff1a;TCP流量控制 笔记来源&#xff1a; 湖科大教书匠&#xff1a;TCP流量控制 流量控制(flow control)就是让发送方的发送速率不要太快&#xff0c;要让接收方来得及接收。 实现方法&#xff1a;滑动窗口机制 移动发送窗口&#xff0c;因接收窗口大小为300&am…

C++思维,作业7.3

#include <iostream> #include <cstring> using namespace std; int monster_blood10000; //英雄 class Hero { protected:string name;int hp;int attck; public:Hero(){//cout << "Hero的无参构造" << endl;}Hero(string name,int hp,int …

《Pytorch深度学习和图神经网络(卷 1)》学习笔记——第七章

这一章内容有点丰富&#xff0c;多用了一些时间&#xff0c;实例就有四五个。 这章内容是真多啊&#xff01;&#xff08;学完之后又回到开头感叹&#xff09; 大脑分级处理机制&#xff1a; 将图像从基础像素到局部信息再到整体信息 即将图片由低级特征到高级特征进行逐级计…

代码评审的18个军规,收藏好!

前言 大家好&#xff01; 我们开发完需求&#xff0c;提测前&#xff0c;一般都需要代码评审。小伙伴们&#xff0c;你们知道代码评审&#xff0c;一般都有哪些军规嘛&#xff1f;今天田螺哥给你带来代码评审的18个军规。 公众号&#xff1a;捡田螺的小男孩 &#xff08;有田…

多肽试剂:151308-48-4,分子式C117H149N27O28,分子量2381.6,具有一定的稳定性

【产品描述】 多肽试剂&#xff08;CAS&#xff1a;151308-48-4&#xff09;一般多肽可以作为螯合剂进行科研实验&#xff0c;一般多肽试剂与其他肽类物质相同&#xff0c;多肽能完全溶解于水&#xff0c;具有一定的稳定性&#xff0c;酸&#xff0c;热组分不改变&#xff0c;…