当前位置: 首页 > news >正文

ssm框架之spring:浅聊IOC

IOC

前面体验了spring,不过其运用了IOC,至于IOC( Inverse Of Controll—控制反转 )

看一下百度百科解释:

控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。

从这个里面可以看出三个重要的词汇:控制,反转,依赖注入。

  • 控制:既然提到控制,那么就是谁控制谁,也就行前提需要有两个对象,不然哪里来的控制。

    一般创建对象的时候,通过new来创建一个对象。但是现在又有个问题了,IOC既然是控制,那么其如何生成对象呢?既然是解耦减少new来创建对象。前面对于例子初体验的时候,看出控制对象的时候没有通过new来创建对象。

  • 反转: 既然叫做反转,那自然就有转了,不然就没有反转一说了。当然没有正转这个词汇,简单说就是一般用法就是正转。

    比如一个对象控制另一个对象的时候,会在这个类中创建这个被调用的对象。

    class A{}
    class B{public static void main(String[] args) {// 所谓的正转调用 因为需要调用A的方法所以需要创建一个A的对象A a=new A();}
    }
    

    而反转却没有看见通过new来创建对象。详情看初体验的例子

    可以看出没有通过new来创建对象,那么如何创建对象呢?肯定是Spring帮我们创建了对象。其通过配置文件就创建了对象,而这个帮忙创建对象的好人就是被称为IOC容器。而IOC容器帮我们查找以及注入依赖对象,而作为操作者的对象只能被动的接受依赖对象。 所以可以看出不是手动去创建对象,而根据配置文件Spring通过IOC容器进行依赖注入,然后对对象进行创建,销毁。所以是说控制对象生存周期的不再是引用它的对象,而是 Spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被 Spring 控制,所以这叫控制反转。

  • 依赖注入(DI):依赖注入和IOC两者其实可以说IOC是一种编程思维,而依赖注入是具体实现这个编程思维的方式。

    其实最常用的两种注入方法是:set注入,构造注入,当然这个在spring中听过xml或者注解进行体现。

    通过依赖注入机制 只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。

    当然组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中

    当然依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。

其实在Spring中的IOC容器使用了工厂模式,以及反射,如果没有反射也就没有必要进行配置信息。

现在有两个问题了,Spring中是通过那个类进行处理这个配置信息的,毕竟配置信息可以是xml或者注解,而这个类必然要进行判断之后才能处理的。

创建bean容器

Spring的IOC容器就是IOC思想的一种实现,而在IOC容器(IOC容器存放着bean 所以被叫做 Spring bean容器)的创建,需要看一个接口BeanFactory,这个是创建Spring bean容器的根接口,这个不是我说的而是源码:

在这里插入图片描述

但是BeanFactory这个是Spring内部使用的接口,面向Spring本身,不是给开发人员用的。一般使用其子接口ApplicationContext,而这个接口在前面例子中很多体现,现在可以看下其关系:

在这里插入图片描述

常用的ApplicationContext实现类或接口:

类/接口描述
ClassPathXmlApplicationContext通过读取类路径下的XML格式配置文件创建的IOC容器对象
FileSystemXmlApplicationContext通过文件系统路径下XML格式配置文件创建的IOC容器对象
ConfigurableApplicationContextApplicationContext的子接口,包含了一些扩展方法比如close(),refresh等。
AnnotationConfigApplicationContext完全注解的时候,用来加载带有配置注解的类。
WebApplicationContext为web应用准备,是基于web环境开发创建IOC容器对象,并将对象存入ServletContext域中。

得到bean信息

其实这个需要一个接口:BeanDefinition (Definition的英文意思是解释,释义。 不得说母语英语真是友好,看名知其意,还是需要学英语的。)

然后看一下其源码是如果解释的:

在这里插入图片描述

翻译如下:

BeanDefinition 描述了一个实例信息,其拥有的属性只,构造方法中带有的参数以及具体实现去其它更多信息。

当然这个类加载信息,需要通过配置文件或者注解才可以,而这个配置文件或者注解也有一定的标准,不然呈现也不能读取这些配置的信息。具体源码就不再此篇聊了。

还有在spring中也不可能只有一个bean的信息,所以在spring中用一个BeanDefinitionMap进行保存信息。

可以用一个图来看一下这个IOC创建容器的大概过程:

在这里插入图片描述

图中还有缓存这个概念,毕竟生存的bean有的时候会被重复使用,如果调用某个bean的时候先判断是否被保存,如果有就直接调用,如果没有就在返回查看BeanDefinitionMap中需要的bean的配置信息。图中既然写了一级缓存那就是spring有多级缓存了,这个后面有机会再聊吧。

自己写一个依注释实现IOC注入的代码

代码的结构如下:

在这里插入图片描述

代码直接能用,可以复制在自己环境内就可以运行。而且每步带有注解。

  • 首先实现两个接口:Di和Bean

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Bean {}@Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Di {
    //    无法使用Object作为注解参数String value();
    }
  • 自己定义一个容器接口:MyApplicationContext

//创建一个自己Spring容器的接口 这个将BeanFactory和ApplicationContext融为一个方便写不然需要写父接口和子接口
public interface MyApplicationContext {Object getBean(Class clazz);
}
  • 实现容器接口的类:MyAnnotionAoolicationContext

    public class MyAnnotionAoolicationContext implements MyApplicationContext {private static Annotation beanAnnotation;//    用一个map存储bean的信息 模仿 BeanDefinitionMapprivate static Map<Class, Object> MyBeanDefinitionMap = new HashMap<Class, Object>();//     作为一个加载扫描其下包或者类的根目录private static String rootFile;@Overridepublic Object getBean(Class clazz) {return MyBeanDefinitionMap.get(clazz);}//    创建构造方法,加载配置文件或者带有自定义注解的
    //   这个直接使用的是通过注解进行创建容器,不是通过xml配置文件进行配置public MyAnnotionAoolicationContext(String packagename) {try {// 因为传递过来包名路径是. 转换为路径符合String packageFile = packagename.replace(".", File.separator);//        得到绝对路径 因为会部署在不同的电脑上,目的是遍历其下的文件中是否都有注解URL url = Thread.currentThread().getContextClassLoader().getResource(packageFile);String fileString = URLDecoder.decode(url.getFile(), "utf-8");rootFile = fileString.substring(1, fileString.length() - packageFile.length());//            System.out.println(fileString);loadFile(fileString);} catch (Exception e) {System.out.println(e);throw new RuntimeException(e);}loadDi();}//    遍历根路径下的文件中带有注解的文件private static void loadFile(String fileString)   {try {File file = new File(fileString);
    //        首先判断是否是文件夹if (file.isDirectory()) {File[] childFileArr = file.listFiles();//            判断文件夹是否为空,如果为空就直接跳出即可if (childFileArr.length == 0 || childFileArr == null) {return;} else {//                遍历所有的文件判断是文件还是文件夹for (File childFile : childFileArr) {if (childFile.isFile()) {
    //                            System.out.println(childFile);//                         通过路径得到反射所需要的包路径+类名//                         这样得到的文件不是以.java 结束,而是以.classString childFileString = childFile.toString();String forName = childFileString.substring(rootFile.length(), childFileString.length() - ".class".length()).replace("\\",".");Class clazz= Class.forName(forName);//                            自己写的注解一般作用在类上而不是接口上,所以将接口,和注解类排除if(!clazz.isAnnotation() && !clazz.isInterface()){
    //                                判断类上是否有bean注解,如果有就实例化  getAnnotation针对的是类上的注解
    //                                不过一般如果类的实例化上都没有注解,那么方法上带注解实现ioc 也就没有多少意义了Annotation beanAnnotation= clazz.getAnnotation(Bean.class);//                                Class s=Class.forName("com.xzd.myannotion.Bean");
    //                                System.out.println(s.getFields());if(beanAnnotation!=null){
    //                                    为了方便暂时使用空构造方法Object bean= clazz.newInstance();System.out.println(forName);System.out.println(clazz);
    //                                    因为一般针对的是接口,所以保存MyBeanDefinitionMap中如果有接口就以接口作为主键if(clazz.getInterfaces().length>0) {
    //                                    默认使用第一个接口吧MyBeanDefinitionMap.put(clazz.getInterfaces()[0], bean);}else {MyBeanDefinitionMap.put(clazz, bean);}}}} else {loadFile(String.valueOf(childFile));}}}}} catch ( Exception e) {System.out.println(e);throw new RuntimeException(e);}}//     前面的实例对象,还可以为属性进行注入值private void loadDi(){try {//       一般类上带有注解的才会在属性上带有ioc注入,所以就不便利所有的类,直接从MyBeanDefinitionMap获取即可Set<Map.Entry<Class, Object>> set= MyBeanDefinitionMap.entrySet();Iterator<Map.Entry<Class, Object>>  iterator= set.iterator();while(iterator.hasNext()){Map.Entry<Class, Object> entry =iterator.next();Class clazz= entry.getKey();Object bean= entry.getValue();
    //              System.out.println(bean+"111");//            得到属性,从属性判断是否有注入数据Field[] fields=  clazz.getDeclaredFields();System.out.println(fields.length);for(Field field:fields){Annotation annotation= field.getAnnotation(Di.class);if(annotation!=null){Class fieldClass= field.getType();fieldClass.getName();System.out.println(fieldClass.getName()+"111");String fieldName= field.getName();Object value= ((Di) annotation).value();Constructor fieldconstructor=fieldClass.getConstructor(String.class);field.setAccessible(true);field.set(bean, fieldconstructor.newInstance(value));};}}} catch (Exception e) {throw new RuntimeException(e);}}}
  • 为了方便直接在一个bean上进行注解

    @Bean
    public class Student  {@Di("12")Integer age;@Di("王五")String name;@Overridepublic String toString() {return "Student{" +"age=" + age +", name='" + name + '\'' +'}';}
    }
    
  • 测试方便调用:test

    public class testSpring {public static void main(String[] args) {// 直接从目录上开始加载 MyApplicationContext myApplicationContext= new MyAnnotionAoolicationContext("com.xzd");Student student= (Student) myApplicationContext.getBean(Student.class);System.out.println(student);}
    }

在这里插入图片描述

相关文章:

ssm框架之spring:浅聊IOC

IOC 前面体验了spring&#xff0c;不过其运用了IOC&#xff0c;至于IOC( Inverse Of Controll—控制反转 ) 看一下百度百科解释&#xff1a; 控制反转&#xff08;Inversion of Control&#xff0c;缩写为IoC&#xff09;&#xff0c;是面向对象编程中的一种设计原则&#x…...

pytest初识

一、单元测试框架 &#xff08;1&#xff09;什么是单元测试框架&#xff1f; 单元测试是指在软件开发中&#xff0c;针对软件的最小单元&#xff08;函数、方法&#xff09;进行正确性的检查测试 &#xff08;2&#xff09;单元测试框架 java&#xff1a;junit和testng pytho…...

设计模式~责任链模式(Chain of Responsibility)-12

目录 &#xff08;1&#xff09;优点 &#xff08;2&#xff09;缺点 &#xff08;3&#xff09;使用场景 &#xff08;4&#xff09;注意事项&#xff1a; &#xff08;5&#xff09;应用实例&#xff1a; &#xff08;6&#xff09;经典案例 代码 责任链&#xff0c; …...

【ElasticSearch】(一)—— 初识ES

文章目录1. 了解ES1.1 elasticsearch的作用1.2 ELK技术栈1.3 elasticsearch和lucene1.4 为什么不是其他搜索技术&#xff1f;1.5 总结2. 倒排索引2.1 正向索引2.2 倒排索引2.3 正向和倒排3. ES的一些概念3.1 文档和字段3.2 索引和映射3.3 mysql与elasticsearch1. 了解ES Elasti…...

MySQL 事务隔离

MySQL 事务隔离事务隔离实现事务的启动ACID : 原子(Atomicity)、一致(Consistency)、隔离(Isolation)、永久(Durability) 多个事务可能出现问题 : 脏读 (dirty read) , 不可重复读 (non-repeatable read) , 幻读 (phantom read) 事务隔离级别 : 读未提交 (read uncommitted)…...

基础06-JS中for-in和for-of有什么区别

for…in 和 for…of 的区别 题目 for…in 和 for…of 的区别 key 和 value for…in 遍历 key , for…of 遍历 value const arr [10, 20, 30] for (let n of arr) {console.log(n) }const str abc for (let s of str) {console.log(s) }function fn() {for (let argument…...

AI视频智能分析EasyCVR视频融合平台录像计划模块搜索框细节优化

EasyCVR支持海量视频汇聚管理&#xff0c;可提供视频监控直播、云端录像、云存储、录像检索与回看、智能告警、平台级联、智能分析等视频服务。在录像功能上&#xff0c;平台可支持&#xff1a; 根据业务场景自定义录像计划&#xff0c;可支持7*24H不间断录像&#xff0c;支持…...

TCP和UDP对比

TCP和UDP对比 UDP(用户数据报协议) 无连接(指的是逻辑连接关系,不是物理上的连接) 支持单播、多播以及广播,也就是UDP支持一对一、一对多、一对全 面向应用报文的,对应用层交付的报文直接打包 无连接不可靠的传输服务(适用于IP电话、视频会议等实时应用),不使用流量控制和…...

CVS Health 西维斯健康EDI需求

CVS Health西维斯健康在特拉华州成立&#xff0c;通过旗下的 CVS Pharmacy 和 Longs Drugs 零售店以及 CVS.com 电商提供处方药、美容产品、化妆品、电影和照片加工服务、季节性商品、贺卡和方便食品。CVS Health通过使高质量的护理变得更经济、更易获得、更简单、更无缝&#…...

Anaconda配置Python科学计算库SciPy的方法

本文介绍在Anaconda环境中&#xff0c;安装Python语言SciPy模块的方法。 SciPy是基于Python的科学计算库&#xff0c;用于解决科学、工程和技术计算中的各种问题。它建立在NumPy库的基础之上&#xff0c;提供了大量高效、易于使用的功能&#xff0c;包括统计分析、信号处理、优…...

数据库基本功之复杂查询的子查询

子查询返回的值可以被外部查询使用,这样的复合查询等效与执行两个连续的查询. 1. 单行单列子查询 (>,<,,<>,>,<)内部SELECT子句只返回一行结果 2.多行单列子查询 (all, any, in,not in) all (>大于最大的,<小于最小的) SQL> select ename, sal from…...

脑机接口科普0019——大脑的分区及功能

本文禁止转载&#xff01;&#xff01;&#xff01;&#xff01; 在前文脑机接口科普0018——前额叶切除手术_sgmcy的博客-CSDN博客科普中&#xff0c;有个这样的一张图&#xff1a; 这个图呢&#xff0c;把大脑划分为不同的区域&#xff0c;然后不同的区域代表不同的功能。 …...

阿里云服务器使用教程:CentOS 7 安装JDK及Tomcat(以jdk1.8、tomcat9.0.37为例)

目录 1、下载JDK及Tomcat的安装包并上传至服务器 2、安装JDK 3、安装Tomcat 4、Tomcat启动后无法打开Tomcat首页的原因 1、下载JDK及Tomcat的安装包并上传至服务器 &#xff08;1&#xff09;下载JDK1.8版本压缩包 官网&#xff1a;Java Downloads | Oracle &#xff08…...

Ubuntu20.04下安装vm17+win10/11

一、安装vmware17 1、官网下载 vmware官网&#xff1a;https://www.vmware.com/cn/products/workstation-pro/workstation-pro-evaluation.html 2、安装依赖 sudo apt update sudo apt install build-essential linux-headers-generic gcc make3、权限和安装 到下载的目录下…...

Kalman Filter in SLAM (1) ——Data Fusion and Kalman Filter(数据融合和卡尔曼滤波)

文章目录0. 参考资料1. Intro Example 例子引入1.1. 测量硬币直径1.2. 思考2. Data Fusion 数据融合2.1. 数据融合在做什么&#xff1f;2.2. 数据融合的前提——不确定度2.3. 数据融合的结果——统计意义下的最优估计3. State Space Representation 状态空间表达式3.1. 状态方程…...

黑马程序最后

这里写自定义目录标题内建stl常用算法adjacent_findbinary_searchcountcount if常用排序算法常用拷贝和替换replace常用算术生成算法常用集合算法https://gitee.com/jiangjiandong/Cpp-0-1-Resource/blob/master/%E7%AC%AC5%E9%98%B6%E6%AE%B5-C%E6%8F%90%E9%AB%98%E7%BC%96%E7…...

u盘系统文件删除后的五种恢复方法

U盘是我们日常生活中使用较为普遍的移动存储设备&#xff0c;由于其便携性和易用性广受人们的欢迎。然而&#xff0c;在我们使用U盘的过程中&#xff0c;经常会出现误删文件的情况&#xff0c;例如本来要作为启动盘的u盘&#xff0c;误删里面的系统文件怎么办&#xff1f;当U盘…...

【玩转c++】List讲解和模拟底层实现

本期主题&#xff1a;list的讲解和模拟实现博客主页&#xff1a;小峰同学分享小编的在Linux中学习到的知识和遇到的问题小编的能力有限&#xff0c;出现错误希望大家不吝赐1.list的介绍和使用1.1.list的介绍1.list是可以在常数范围内在任意位置进行插入和删除的序列式容器&…...

【Python】特征编码

特征编码1. 独热编码(离散变量编码) sklearn.preprocessing.OneHotEncoder1.1 原理 & 过程1.2 封装函数2. 连续变量分箱(连续变量编码) sklearn.preprocessing.KBinsDiscretizer2.1 原理2.2 等宽分箱 KBinsDiscretizer(strategyuniform)2.3 等频分箱 KBinsDiscretizer(stra…...

前端开发者必备的Nginx知识

nginx在应用程序中的作用 解决跨域请求过滤配置gzip负载均衡静态资源服务器…nginx是一个高性能的HTTP和反向代理服务器&#xff0c;也是一个通用的TCP/UDP代理服务器&#xff0c;最初由俄罗斯人Igor Sysoev编写。 nginx现在几乎是众多大型网站的必用技术&#xff0c;大多数情…...

zh3100组合式选粉机的设计【说明书+27张CAD图纸】

zh3100组合式选粉机作为粉体分级领域的核心设备&#xff0c;其设计融合了流体力学、机械传动与颗粒分离理论&#xff0c;通过优化结构参数与气固两相流场分布&#xff0c;实现高精度、低能耗的粉体分级作业。该设备采用模块化组合设计理念&#xff0c;将选粉室、导流装置、分级…...

**实时内核中的任务调度机制:从理论到C++实现的深度探索**在嵌入式系统和高实时性应用中,**实时内核(Real-

实时内核中的任务调度机制&#xff1a;从理论到C实现的深度探索 在嵌入式系统和高实时性应用中&#xff0c;实时内核&#xff08;Real-Time Kernel&#xff09; 是整个系统稳定运行的核心。它不仅负责资源分配&#xff0c;还承担着任务调度、中断响应、同步机制等关键职责。本文…...

ngx_http_join_exact_locations

1 定义 ngx_http_join_exact_locations 函数 定义在 ./nginx-1.24.0/src/http/ngx_http.cstatic ngx_int_t ngx_http_join_exact_locations(ngx_conf_t *cf, ngx_queue_t *locations) {ngx_queue_t *q, *x;ngx_http_location_queue_t *lq, *lx;q ngx_queue_he…...

如何用Tool-SQL解决Text2SQL中的条件不匹配问题?实战案例分享

实战解析&#xff1a;用Tool-SQL攻克Text2SQL条件不匹配难题 当数据工程师面对"帮我找出上季度华东区销售额超50万但退货率低于5%的客户"这类业务查询时&#xff0c;传统Text2SQL方案常陷入条件错配的泥潭——系统生成的SQL要么遗漏关键约束&#xff0c;要么将"…...

小白友好:InstructPix2Pix极速推理,秒级响应你的修图指令

小白友好&#xff1a;InstructPix2Pix极速推理&#xff0c;秒级响应你的修图指令 你有没有过这样的经历&#xff1f;手机里存着一张照片&#xff0c;风景很美&#xff0c;但天空灰蒙蒙的&#xff1b;或者朋友聚会合影&#xff0c;大家都笑得很开心&#xff0c;就是背景有点乱。…...

布隆过滤器与哈希索引:两级验证模型

在高并发、大数据量的系统中&#xff0c;快速判断一个元素是否“已经存在”是一项基础而关键的能力。无论是防止重复提交、抵御缓存穿透&#xff0c;还是实现分布式去重&#xff0c;都需要一种高效的存在性检查机制。实践中&#xff0c;布隆过滤器&#xff08;Bloom Filter&…...

基于偏振无关的传输相位调控技术,实现可见光超透镜的优化设计

基于传输相位的可见光超透镜 偏振无关搞过光学设计的工程师都知道&#xff0c;传统透镜那个笨重的曲面有多让人头疼。现在有了一种黑科技——可见光波段的超透镜&#xff0c;厚度只有几百纳米&#xff0c;却能实现传统透镜的光学效果。关键是这玩意儿还搞定了偏振相关性这个老大…...

App启动总览

特征 / 步骤 冷启动 (Cold Start) 温启动 (Warm Start) 热启动 (Hot Start) 速度 最慢 🐢 中等 🏃 最快 🚀 进程创建 ✅ 需要 ❌ 跳过 ❌ 跳过 Application.onCreate() ✅ 需要调用 ❌ 跳过 ❌ 跳过 Activity.onCreate() ✅ 需要调用 ✅ 需要调用 ❌ 跳过 Activity.onSta…...

高效构建智能媒体库:MetaTube插件全方位应用指南

高效构建智能媒体库&#xff1a;MetaTube插件全方位应用指南 【免费下载链接】jellyfin-plugin-metatube MetaTube Plugin for Jellyfin/Emby 项目地址: https://gitcode.com/gh_mirrors/je/jellyfin-plugin-metatube MetaTube是一款专为Jellyfin和Emby设计的开源元数据…...

英语节日庆祝口语

一、春节 (Chinese New Year / Spring Festival) 1. 春节祝福 中文英文春节快乐&#xff01;Happy Chinese New Year! / Happy Spring Festival!新年快乐&#xff01;Happy New Year!恭喜发财&#xff01;Wishing you prosperity! / Gong Xi Fa Cai!万事如意&#xff01;May …...