Spring原理-IOC和AOP

概述

在此记录spring的学习内容。spring官网:https://spring.io/
在这里插入图片描述

概念故事

从前,在Java的大森林中,有一片神奇的土地,名叫"Spring"。这片土地上生长着各种美丽而强大的植物,它们分别象征着Spring框架中的各种功能和特性。

在这片土地上,有一位智慧而善良的园丁,名叫"Rod Johnson"。Rod是这片土地上的守护者,他有着非凡的见识和智慧。他注意到这片土地原本虽然生机盎然,但由于管理混乱、依赖杂乱等问题而日渐失去活力。于是,他开始策划着一场变革之旅。

Rod明白,为了让这片土地重焕生机,他需要一种全新的方式来管理这里那些繁杂的植物。于是,他提出了"控制反转"的理念,使得每一株植物可以有自己的生长空间,而不再依赖于别的植物。

随后,他又强调"依赖注入"这一概念,让每株植物可以从土地中获取所需的养分,而不用亲自去寻找。这样设计使得这些植物的生长变得更为高效。

Rod还发明了一种神奇的"面向切面编程"技术,一种能够让植物们自由组合、互相辅助的方式,令整片土地都焕发出一种特殊的生机。

渐渐地,这片土地上充满了生机与活力。每一株植物都在互相配合下茁壮成长,形成了一片绚丽而蓬勃的景象。园丁Rod Johnson因其智慧和勇气,被人们誉为这片土地上的英雄。

从那以后,人们便将这片土地上的新秩序称为"Spring",这个充满魔力的名字也因此广为传颂。而这位园丁Rod Johnson,则被尊称为Spring框架的缔造者和守护者。

就这样,Spring框架成为了Java世界中最重要的框架之一,为开发者们带来了许多便利,也为Java企业级应用开发带来了一场新的春天。

原文链接:https://blog.csdn.net/qq_55482652/article/details/137440957

控制反转IOC

控制反转

控制反转(Inversion of Control,IoC)是一种思想,是Spring框架的核心概念之一,它的主要作用是通过将对象的创建和依赖关系的管理交给Spring容器来实现更松耦合的设计,而不是由程序员显式地进行操作。
一句话理解IOC、IOC容器、依赖注入:IOC是一种思想。通过IOC容器管理对象。编码时,通过依赖注入的方式从IOC容器中获取依赖的对象。
IOC容器->创建对象
DI->给对象的属性赋值

对比-传统开发

传统的开发模式中,应用程序本身负责创建和管理对象,并且通过直接调用其他对象的方法来完成业务逻辑。这种方式下,各个对象之间紧耦合,修改其中一个对象的实现会影响到其他所有相关的组件,导致代码的可维护性、可扩展性和可重用性都很差。

public class ServiceA {private ServiceB serviceB = new ServiceB();
}

这种方式中,ServiceA直接依赖于ServiceB的具体实现。

对比-控制反转IOC

Spring采用控制反转的方式解决了这个问题。它将对象的创建和管理职责从应用程序代码转移到了IOC容器。这样,对象不再自行创建依赖对象,而是从IOC容器中获取。在IoC容器中,对象的创建、依赖注入和生命周期的管理都由容器自动完成,使得组件之间的关系变得非常简单和清晰。具体来说,控制反转有两种主要方式:

  • 依赖注入(Dependency Injection, DI):通过构造器、setter方法或者字段注入的方式,将依赖对象注入到需要的对象中。
  • 依赖查找(Dependency Lookup):对象在运行时从容器中主动获取它所需要的依赖对象。

通过控制反转,Spring可以轻松实现面向对象设计中的依赖注入,即将对象所需的依赖关系从对象内部转移到外部(有点类似组合),从而消除了对象之间的硬编码关系,提高了代码的复用性和灵活性。同时,使得项目的结构更加清晰,易于维护。

对比总结

在传统的开发模式中,我们的程序主要由业务逻辑和控制逻辑组成。而在这种模式中,构建应用程序的过程通常是这样的:当需要一个对象时,我们会直接使用 new 运算符等方式来手动创建这个对象,并将其注入到其他对象中使用。这种过程中,创建和维护对象的职责完全由程序员负责。

而在IOC容器的设计思想下,控制权被完全反转了。即对象的创建和维护都交由外部容器管理,而程序员只需关注于定义依赖关系以及编写具体的业务逻辑(程序员只要确定需要什么依赖,并且关注业务逻辑即可,不用关心依赖对象的创建和维护)。实现这种控制反转的核心技术就是依赖注入、依赖查找。在Spring框架中,DI 通常通过三种方式进行:构造函数注入、 Setter 方法注入和字段注入。

总的来说,控制反转的目的是减少程序员对对象的手动创建和维护工作,实现代码重用、灵活性和可维护性。同时,依赖注入也使得程序的结构更加清晰,易于扩展和测试。因此,IOC容器和依赖注入已经成为了现代编程语言和框架中不可或缺的一部分。

IOC容器

IOC控制反转是一种思想,而在Spring框架中,负责创建、管理和注入依赖对象的容器就叫IOC容器(也可以叫做Bean容器)。

具体来说,当使用IOC容器时,我们将需要依赖的对象交给容器管理,而不是自行手动创建和维护这些对象。IOC容器会自动扫描项目中所有Bean定义,根据配置文件或者注解等方式实例化Bean对象,并将其注册到容器中。当我们需要使用某个依赖项时,只需要从容器中获取即可,而无需关心对象如何创建和维护。这种方式下,我们只需要关注业务逻辑的实现,从而使代码更加简洁、灵活和易于维护。

Spring框架中常用的IOC容器有两种:BeanFactory 和ApplicationContext。其中,BeanFactory 是Spring框架最基本的IOC容器,提供了最基本的IOC能力。ApplicationContext 是在BeanFactory 的基础上进行了扩展,提供了更多的特性和功能,例如国际化支持、AOP、事件机制等,因此是Spring框架中常用的IOC容器。

问题:IOC容器是如何管理依赖对象的?

依赖注入

依赖注入(Dependency Injection,DI)是一种应用程序设计模式,它将类之间的依赖关系从代码内部提取出来,转而通过外部容器进行管理。通过使用依赖注入,对象不再创建和维护它所依赖的其他对象,而是由 IOC 容器负责创建这些对象,并将其注入到需要使用它们的地方。依赖注入的核心思想是松耦合(loose coupling),也就是减少模块之间的依赖关系,使得系统更加灵活、易于扩展和维护。同时,依赖注入也有助于提高代码的可测试性,因为我们可以使用模拟对象来替代真实的依赖对象进行单元测试。
(说人话就是,依赖注入是给对象的属性赋值,也是从IOC容器中找东西)

实现依赖注入DI有3种方法:

  1. 构造器注入
  2. Setter方法注入
  3. 字段注入

构造器注入

构造器注入是通过构造函数将依赖注入到目标对象中的。这种方式确保了依赖对象在目标对象创建时即被提供,适用于强制性依赖。
示例:

@Component
public class ServiceA {private final ServiceB serviceB;@Autowiredpublic ServiceA(ServiceB serviceB) {this.serviceB = serviceB;}
}

优点:
确保依赖关系在对象创建时即被注入,不会出现未初始化的问题。
对于必须的依赖来说,构造器注入更加明确和安全。

缺点:
当依赖项较多时,构造函数的参数列表会变得很长,不太优雅。

Setter方法注入

Setter注入是通过setter方法将依赖注入到目标对象中的。适用于可选的依赖,或在对象创建之后进行依赖注入。
示例:

@Component
public class ServiceA {private ServiceB serviceB;@Autowiredpublic void setServiceB(ServiceB serviceB) {this.serviceB = serviceB;}
}

优点:
灵活性高,可以在对象创建之后再进行依赖注入。
适用于可选依赖和配置复杂对象。

缺点:
可能导致对象处于不完全初始化状态,增加了调试和维护的复杂性。

字段注入

字段注入是通过直接在字段上使用注解将依赖注入到目标对象中的。这种方式简单直观,但不推荐使用,因为违反了依赖倒置原则。

示例:

@Component
public class ServiceA {@Autowiredprivate ServiceB serviceB;
}

优点:
实现简单,代码简洁。

缺点:
使单元测试变得困难,因为依赖关系在对象创建之后无法更改。
违反了依赖倒置原则(Dependence Inversion Principle),使得类的设计不够优雅。

依赖注入方式总结

选择依赖注入方式的考虑

  • 构造器注入适用于强制性依赖,确保对象在创建时即被完全初始化。
  • Setter注入适用于可选依赖和需要在对象创建之后进行配置的情况。
  • 字段注入由于违反设计原则,通常不推荐使用,除非是在非常简单的场景中。

总结来说,选择合适的依赖注入方式应根据具体的需求和设计原则来决定。构造器注入和Setter注入是更推荐的方式,而字段注入应尽量避免。

代码比较:

假设我们有一个名为UserService的类,它需要依赖于UserDao类来进行数据存储。那么在传统的编程方式中,我们可能会这样写代码:

public class UserService {private UserDao userDao;public UserService() {this.userDao = new UserDao();}public void addUser(User user) {// 进行业务逻辑处理userDao.save(user);}// 其他方法省略...
}

在上述代码中,我们通过创建UserDao对象来满足UserService对依赖的需求。然而,这种方式会导致UserService和UserDao紧密耦合在一起,不利于代码的维护和扩展,并且使得UserService难以进行单元测试。

而如果使用依赖注入的话,我们可以将UserDao对象的创建和管理交给外部容器(如Spring容器)来完成,从而解耦和UserService与UserDao之间的关系,代码如下所示:

public class UserService {private UserDao userDao;public UserService(UserDao userDao) {this.userDao = userDao;}public void addUser(User user) {// 进行业务逻辑处理userDao.save(user);}// 其他方法省略...
}

在上述代码中,我们通过构造函数注入的方式将UserDao对象注入到了UserService类中,而UserDao对象则是由外部容器负责创建和管理的。这样一来,UserService与UserDao之间的耦合就被消除了,同时也提高了代码的可测试性和可维护性。

总的来说,依赖注入能够大大简化代码的编写和维护工作,使代码更加灵活、易于扩展和测试。

那这个UserDao是什么时候注入到UserService类中的呢?

UserDao对象是在创建UserService实例时通过依赖注入的方式注入到UserService类中的。具体来说,在使用Spring框架时,可以通过在配置文件中配置UserDao的实现类和UserService的构造函数参数来实现自动注入;或者使用@Autowired注解标记UserService类中的UserDao字段,让Spring容器自动完成注入。这样一来,当需要使用UserService对象时,Spring容器会自动创建一个UserDao对象并将其注入到UserService对象中。这样就实现了UserServiceUserDao之间的解耦合。

那这个创建的UserDao是单例吗?

在Spring容器中,默认情况下,所有的Bean都是单例的。也就是说,当使用依赖注入的方式创建UserDao对象时,默认情况下会创建一个单例对象,并且在整个应用程序的生命周期内都可以使用这个对象。如果需要创建多个实例,则需要在配置文件中进行相应的设置。可以使用@Scope注解来指定Bean的作用域,常见的作用域有单例(Singleton)、原型(Prototype)、请求(Request)、会话(Session)等。例如,可以使用@Scope("prototype")注解来将UserDao配置为原型作用域,这样每次从Spring容器中获取UserDao对象时,都会创建一个新的实例。

默认情况下会创建一个单例对象,并且在整个应用程序的生命周期内都可以使用这个对象。如果容器中已经创建了UserDao对象,则后续获取UserDao对象时不会再次创建新的对象,而是直接返回之前已经创建好的对象。

需要注意的是,在某些情况下,例如多线程环境下,使用单例模式可能会存在线程安全问题,此时建议将Bean的作用域配置为原型,这样可以每次都创建一个新的对象实例来避免线程安全问题。

IOC实现原理

spring提供两种方式创建Bean,一种是xml,一种是注解。

基于XML的原理

读取解析xml配置文件->反射实例化对象->存储在Map集合中

1 读xml

读取配置文件(spring.xml)->xml解析->获取bean的id和类的全路径名

<?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"><bean id="empDao" class="com.zou.learnspring.dao.impl.EmpDaoImpl2"/></beans>

补充
bean标签的属性: 点击跳转

2 实例化对象

通过反射实例化对象->全路径名获取字节码对象->通过字节码实例化->放到容器中(当作一个Map集合)
Class clazz = Class.forName(“com.zou.learnspring.dao.impl.EmpDaoImpl2”)
Object obj = clazz.newInstance();
map.put(“empDao”, obj);

3 getBean获取对象

工厂模式返回Bean对象
BeanFactory接口定义的getBean方法,该方法底层就是map.get(“name”);

接口的继承ApplicationContext -> … -> BeanFactory
ApplicationContext的实现类:ClassPathXmlApplicationContext。其中间也是间接实现了ApplicationContext接口。
在idea中,在ApplicationContext接口中,通过Ctrl+H可以查看接口的实现类
在这里插入图片描述

面向切面编程

作用:事务控制、日志记录、性能检测、权限控制

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

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

相关文章

1.1 寻找灵感:怎样像艺术家一样去看待这个世界

“你是从哪里获取到这些创作灵感的&#xff1f;” 当每一个艺术家被问到这个问题时&#xff0c;只有诚实的艺术家会回答&#xff1a; “这是我偷窃的” 怎样像艺术家一样去看待这个世界呢&#xff1f; 你首先需要弄明白什么是值得你偷窃的&#xff0c;然后你才能继续接下来…

如何在一台电脑上安装多个版本的JDK并且切换使用?

如何在一台电脑上安装多个版本的JDK并且切换使用&#xff1f; 文章目录 如何在一台电脑上安装多个版本的JDK并且切换使用&#xff1f;1.目录管理2.下载JDK3.配置环境变量4. 验证 1.目录管理 我们需要首先对不同版本的JDK进行版本管理&#xff0c;如下所示&#xff0c;我在C盘路…

# linux 系统下 切换 root 用户时出现 authentication failure 的解决办法

linux 系统下 切换 root 用户时出现 authentication failure 的解决办法 1、问题分析&#xff1a; 切换 root 用户时出现 authentication failure&#xff0c;意思即 “身份验证失败”&#xff0c;这是由于新安装的系统&#xff0c;可能没有给 root 用户设置密码。 2、解决方…

算法(二)二分查找

文章目录 二分查找简介实现方式循环方式递归方式 经典例子 二分查找简介 二分查找&#xff08;binary search&#xff09;算法&#xff0c;也叫折半算法。二分查找是针对有序的数据集合的查找办法&#xff0c;如果是无序的数据结合就使用遍历。二分查找之所以快速&#xff0c;…

OWASP top10--SQL注入(四、sqlmap安装及使用)

目录 sqlmap工具安装&#xff1a; 工具说明&#xff1a; 主要功能特性包括&#xff1a; 基本使用示例&#xff1a; 先下载python2.7.9版本 sqlmap运行 sqlmap工具使用 -u -r –-levelLEVEL扫描深度级别 --riskRISK 执行测试的风险 -threads 线程数 -batch-smart智能…

鸿蒙开发加强2

快速创建一个符合长度的数组 空数组 Array.from({length: 200}) // 200的长度的空数组 场景&#xff1a;只确定长度&#xff0c;不确定内容的情况 State 状态装饰器 》增强功能 数据变化了 可以引起页面的重新渲染 没有State修饰的变量&#xff0c;不会引起UI的刷新渲染 加…

fintuning chatglm3

chatglm3介绍 ChatGLM3-6B 是 ChatGLM 系列最新一代的开源模型&#xff0c;在保留了前两代模型对话流畅、部署门槛低等众多优秀特性的基础上&#xff0c;ChatGLM3-6B 引入了如下特性&#xff1a; 更强大的基础模型&#xff1a; ChatGLM3-6B 的基础模型 ChatGLM3-6B-Base 采用…

ic基础|时钟篇06:crg到底是什么?一文带你了解crg中的时钟系统!

大家好&#xff0c;我是数字小熊饼干&#xff0c;一个练习时长两年半的ic打工人。我在两年前通过自学跨行社招加入了IC行业。现在我打算将这两年的工作经验和当初面试时最常问的一些问题进行总结&#xff0c;并通过汇总成文章的形式进行输出&#xff0c;相信无论你是在职的还是…

基于Swing和socket实现双向通讯案例

server代码&#xff1a; import javax.swing.*; import java.awt.*; import java.io.*; import java.net.ServerSocket; import java.net.Socket;public class Server extends JFrame {private JTextArea messageArea;private JTextField textField;private PrintWriter write…

像艺术家一样工作:前言

名人名言 “艺术是盗窃” —— 巴勃罗毕加索 “不成熟的诗人模仿&#xff0c;成熟的诗人偷窃&#xff1b;对于偷窃得到的艺术&#xff0c;坏的诗人丑化它&#xff0c;好的诗人加入自己的理解&#xff0c;使它变得更好&#xff0c;至少会让它有点不同。最优秀的诗人&#xff0…

After Effects 2022(AE2022)支持win版和mac版下载

​After Effects 2022 是由Adobe公司推出的一款专业视频后期制作软件&#xff0c;它主要用于视频合成、视频特效制作、视频剪辑、动画制作等领域。After Effects 2022 内置了丰富的特效和过渡效果&#xff0c;用户可以通过它进行高级的视频合成和动画制作。 该软件具有直观的用…

一文搞懂分布式事务Seta-AT模式实现原理

分布式事务概念 分布式事务&#xff08;Distributed Transaction&#xff09; 是指在分布式系统中&#xff0c;涉及多个数据库、服务、消息队列等资源&#xff0c;并且需要保证这些资源上的操作要么全部成功提交&#xff0c;要么全部失败回滚的一种机制。在分布式系统中&#…

IO流---字节流.Java

一&#xff0c;概述 IO流是存储和读取数据的解决方案。 I&#xff1a;input O:output流&#xff1a;像水流一样传输数据 因为IO流与File是息息相关的&#xff0c;所以在学习IO流之前&#xff0c;简单回顾一下File&#xff1a;&#x1f604;&#x1f60a;&#…

python对文本操作,生成可执行文件

.exe文件主要包含pingmianF.py文件和read_inp_auto.py文件 实现效果 代码 read_inp_auto.py #-*- coding: utf-8 -*- import re import sys import os import os.path import time import pingmianF from pingmianF import vector import numpy as np from tkinter import me…

GDPU JavaWeb EL与JSTL

标签化&#xff0c;可以简化百分号的繁忙。 标签库配置 先下载好jstl标签库&#xff0c;然后放到lib。接着&#xff0c;要让编译器识别到&#xff0c;因此要在模块配置依赖&#xff0c;这里导jar包都得注意一下模块依赖。 也可以在libraries项目库设置。 EL与JSTL查询图书 在…

2024华为OD机试真题-攀登者1-C++(C卷D卷)

题目描述 攀登者喜欢寻找各种地图,并且尝试攀登到最高的山峰。 地图表示为一维数组,数组的索引代表水平位置,数组的元素代表相对海拔高度。 其中数组元素0代表地面。 例如: [0,1,2,4,3,1,0,0,1,2,3,1,2,1,0],代表如下图所示的地图, 地图中有两个山脉位置分别为1,2,3,4,5 …

设计模式(十)结构型模式---享元模式

文章目录 享元模式简介结构UML图具体实现UML图代码实现 享元模式简介 享元模式&#xff08;fly weight pattern&#xff09;主要是通过共享对象来减少系统中对象的数量&#xff0c;其本质就是缓存共享对象&#xff0c;降低内存消耗。享元模式将需要重复使用的对象分为两个状态…

大学生Python自救课程总结

因为一些事情的缘故&#xff0c;我已经几乎没有更新很久了&#xff0c;然后现在快到期末了&#xff0c;不知道各位学习python的同志们慌不慌【坏笑】。 本学期&#xff0c;我只是简单的讲了讲python的基础用法。当然&#xff0c;可能有些地方总结的并不全面&#xff0c;很多知…

MyBatis中的接口代理机制及其使用

1. MyBatis中的接口代理机制及其使用 文章目录 1. MyBatis中的接口代理机制及其使用2. 实操2.1 准备工作2.2 insert 增加操作2.3 delete 删除操作2.4 update 修改操作2.5 select 查询一条记录操作2.6 select 查询多条记录操作 3. 总结&#xff1a;4. 最后&#xff1a; MyBatis …

HackTheBox-Machines--Nineveh

Nineveh测试过程 1 信息收集 NMAP 端口扫描 80 端口 80端口是服务器的默认页面&#xff0c;无可利用功能点&#xff0c;源代码没有可利用的敏感信息 目录扫描 1.http://10.129.25.123/department 访问/department目录跳转到登录页面&#xff0c;尝试暴力破解&#xff0c;获取…