4.Spring IoC&DI

2024-04-18 1436阅读

文章目录

  • 1.Ioc - 控制反转(解耦)
    • 1.1传统开发
    • 1.2批量生产车轮(修改代码) - 传统方式,繁琐
    • 1.3解耦
      • 1.3.1使用Ioc方法后
      • 1.3.2添加变量颜色 只需要修改Tire即可
      • 1.4Bean的存储
        • 1.4.1@Controller(控制器存储)
        • 1.4.2@Service(服务存储)
          • 1.4.2.1根据context来获取bean
          • 1.4.2.2根据名称来获取bean
          • 1.4.2.3根据名称和类型获取bean
          • 1.4.2.4特殊情况-类名前两位都大写,bean的名称为类名
          • 1.4.3@Repository (仓库存储)
          • 1.4.4@Component (组件存储)
          • 1.4.5@Configuration (配置存储)
          • 1.4.6为什么要这么多类注解? - 五大注解
          • 1.4.7@Controller和其他注解的区别
          • 1.4.8@Bean 使用
            • 1.4.8.1@Bean正常使用举例
            • 1.4.8.2测试@Bean传递参数是如何选择的
            • 1.4.9启动类位置关系影响
            • 1.5 Bean命名
            • 1.6@Bean取
            • 2.DI - 依赖注入
              • 2.1属性注入
                • 2.1.1属性注入流程
                • 2.1.2属性注入问题
                • 2.2构造方法注入
                  • 2.2.1只存在一个构造函数时
                  • 2.2.2存在多个构造函数时
                  • 2.3Setter方法注入
                  • 2.4三种注入优缺点分析
                  • 2.5@Autowired存在问题
                    • 2.5.1.属性名和你需要使用的对象名保持一致
                    • 2.5.2.使用@Primary注解标识默认的对象
                    • 2.5.3.使用@Qualifier
                    • 2.5.4 使用 @Resource 注解
                    • 2.6常见面试题 - @Autowird 与 @Resouce的区别
                    • 3.Ioc、DI、AOP的关系
                      • 2.6常见面试题 - @Autowird 与 @Resouce的区别
                      • 3.Ioc、DI、AOP的关系

                        大家好,我是晓星航。今天为大家带来的是 Ioc和DI 相关的讲解!😀

                        1.Ioc - 控制反转(解耦)

                        1.1传统开发

                        软件设计原则:高内聚,低耦合。

                        高内聚:一个模块内部的关系

                        低耦合:各个模块之间的关系

                        我们的实现思路是这样的:

                        先设计轮子(Tire),然后根据轮子的大小设计底盘(Bottom),接着根据底盘设计车身(Framework),最后根据车身设计好整个汽车(Car)。这里就出现了一个"依赖"关系: 汽车依赖车身,车身依赖底盘,底盘依赖轮子.

                        4.Spring IoC&DI

                        最终程序的实现代码如下:

                        Main.java

                        package com.example.demo.ioc;
                        /**
                         * Created with IntelliJ IDEA
                         * Description
                         * User: 晓星航
                         * Date: 2024 -03 -15
                         * Time: 20:16
                         */
                        public class Main {
                            public static void main(String[] args) {
                                Car car = new Car(17);
                                car.run();
                                Car car2 = new Car(19);
                                car2.run();
                            }
                        }
                        

                        Car.java

                        package com.example.demo.ioc;
                        /**
                         * Created with IntelliJ IDEA
                         * Description
                         * User: 晓星航
                         * Date: 2024 -03 -15
                         * Time: 20:16
                         */
                        public class Car {
                            private Framework framework;
                            public Car(int size) {
                                framework = new Framework(size);
                                System.out.println("car init...");
                            }
                            public void run() {
                                System.out.println("car run");
                            }
                        }
                        

                        FrameWork.java

                        package com.example.demo.ioc;
                        /**
                         * Created with IntelliJ IDEA
                         * Description
                         * User: 晓星航
                         * Date: 2024 -03 -15
                         * Time: 20:17
                         */
                        public class Framework {
                            private  Bottom bottom;
                            public Framework(int size) {
                                bottom = new Bottom(size);
                                System.out.println("framework init...");
                            }
                        }
                        

                        Bottom.java

                        package com.example.demo.ioc;
                        /**
                         * Created with IntelliJ IDEA
                         * Description
                         * User: 晓星航
                         * Date: 2024 -03 -15
                         * Time: 20:19
                         */
                        public class Bottom {
                            private Tire tire;
                            public Bottom(int size) {
                                tire = new Tire(size);
                                System.out.println("bottom init...");
                            }
                        }
                        

                        Tire.java

                        package com.example.demo.ioc;
                        /**
                         * Created with IntelliJ IDEA
                         * Description
                         * User: 晓星航
                         * Date: 2024 -03 -15
                         * Time: 20:20
                         */
                        public class Tire {
                            private int size;
                            public Tire(int size) {
                                this.size =size;
                                System.out.println("tire init...size" + size);
                            }
                        }
                        

                        输出结果:

                        4.Spring IoC&DI

                        1.2批量生产车轮(修改代码) - 传统方式,繁琐

                        我们为了批量化生产各种型号的车轮胎,继而修改了Tire类中的size变量为默认值,传参到Tire中,这就导致了Bottom的关联问题。

                        4.Spring IoC&DI

                        在将参数int size传到Bottom中之后,Tire不报错了,但是Bottom又出现了关联问题

                        4.Spring IoC&DI

                        在将参数int size传到Framework中之后,Bottom不报错了,但是Framework又出现了关联问题

                        在将参数int size传到Car中之后,Framework不报错了,此时Car中可以正常批量化生产各种型号的车轮的车了

                        使用@Component和@Autowired来简化代码

                        4.Spring IoC&DI

                        @Component: 标注Spring管理的Bean,使用@Component注解在一个类上,表示将此类标记为Spring容器中的一个Bean

                        @Autowired: 是一个注释,它可以对类成员变量、方法及构造函数进行标注,让 spring 完成 bean 自动装配的工作

                        4.Spring IoC&DI

                        我们之前都用@Controller管理,为什么现在用@Component

                        4.Spring IoC&DI

                        因为@Controller就是用@Component来实现的。

                        1.3解耦

                        1.3.1使用Ioc方法后

                        4.Spring IoC&DI

                        传统方法耦合性高,我们为了提高代码编写效率就引入了Ioc可以将代码进行解耦操作,提高代码编写的效率

                        1.2中我们只为了更改轮胎的尺寸,但是我们改了轮胎Tire之后,导致我们还要修改底盘Bottom,车身Framework,以及汽车Car,那么有没有什么方法可以只修改轮胎Tire一个代码呢?

                        传统方法:

                        4.Spring IoC&DI

                        使用了Ioc之后的方法:

                        4.Spring IoC&DI

                        通过上述两个图的对比,我们可以明显发现使用完Ioc之后,无论我们在车上加任意种新的元素,我们代码都不会产生关联报错。

                        使用Ioc的车代码:

                        Car.java:

                        4.Spring IoC&DI

                        Framwork.java:

                        4.Spring IoC&DI

                        Bottom.java:

                        4.Spring IoC&DI

                        Tire.java:

                        4.Spring IoC&DI

                        Main.java:

                        4.Spring IoC&DI

                        运行结果

                        4.Spring IoC&DI

                        1.3.2添加变量颜色 只需要修改Tire即可

                        1. 在Tire中增加color变量
                        4.Spring IoC&DI
                        1. 在传参时多传一个颜色参数即可
                        4.Spring IoC&DI

                        运行结果:

                        4.Spring IoC&DI

                        4.Spring IoC&DI

                        1.4Bean的存储

                        共有两种注解类型可以实现:

                        1.注解: @Controller、 @Service、 @Repository、 @Component、 @Configuration

                        2.方法注解: @Bean.

                        1.4.1@Controller(控制器存储)

                        启动类和我们的容器类一定要同级或者启动类高于其他类,这样启动类中的bean才能拿到其他类中的值

                        4.Spring IoC&DI

                        启动类:

                        4.Spring IoC&DI

                        spring上下文

                        4.Spring IoC&DI

                        使用getBean获取spring容器中的对象

                        4.Spring IoC&DI

                        可以看到,此时我们使用bean来获取spring容器中的值已经成功!

                        4.Spring IoC&DI

                        如果删除@Controller注解,就会报如下错误

                        4.Spring IoC&DI

                        1.4.2@Service(服务存储)

                        1.4.2.1根据context来获取bean

                        再写一个userService类,我们还是在启动类中使用bean来获取spring容器中的类中的元素

                        4.Spring IoC&DI

                        输出结果:

                        4.Spring IoC&DI

                        注:启动类在文件夹中的存放位置一定要等于或高于其他类的位置,不然启动类的作用会失效。

                        4.Spring IoC&DI

                        1.4.2.2根据名称来获取bean

                        4.Spring IoC&DI

                        4.Spring IoC&DI

                        4.Spring IoC&DI
                        1.4.2.3根据名称和类型获取bean

                        4.Spring IoC&DI

                        4.Spring IoC&DI

                        4.Spring IoC&DI
                        1.4.2.4特殊情况-类名前两位都大写,bean的名称为类名

                        4.Spring IoC&DI

                        4.Spring IoC&DI

                        1.4.3@Repository (仓库存储)

                        代码:

                        4.Spring IoC&DI

                        4.Spring IoC&DI

                        运行结果图:

                        4.Spring IoC&DI

                        1.4.4@Component (组件存储)

                        代码:

                        4.Spring IoC&DI

                        4.Spring IoC&DI

                        运行结果:

                        4.Spring IoC&DI

                        1.4.5@Configuration (配置存储)

                        代码:

                        4.Spring IoC&DI

                        4.Spring IoC&DI

                        运行结果:

                        4.Spring IoC&DI

                        1.4.6为什么要这么多类注解? - 五大注解

                        • @Controller: 控制层,接收请求,对请求进行处理,并进行响应
                        • @Servie: 业务逻辑层,处理具体的业务逻辑
                        • @Repository: 数据访问层,也称为持久层。负责数据访问操作
                        • @Configuration: 配置层,处理项目中的一些配置信息

                          4.Spring IoC&DI

                          程序的应用分层,调用流程如下:

                          4.Spring IoC&DI4.Spring IoC&DI

                          4.Spring IoC&DI

                          1.4.7@Controller和其他注解的区别

                          使用@Controller

                          4.Spring IoC&DI

                          4.Spring IoC&DI

                          可正常访问

                          使用@Service

                          4.Spring IoC&DI

                          4.Spring IoC&DI

                          不能正常返回

                          证明@Controller可以作为程序的入口实现,而其他注解不行

                          1.4.8@Bean 使用

                          1.4.8.1@Bean正常使用举例

                          4.Spring IoC&DI

                          4.Spring IoC&DI

                          UserInfo.java:

                          4.Spring IoC&DI

                          BeanConfig.java:

                          4.Spring IoC&DI

                          启动类代码:

                          4.Spring IoC&DI

                          此时代码没有正常运行,产生报错信息

                          4.Spring IoC&DI

                          修改代码,将根据context获取bean变为根据名称来获取bean

                          4.Spring IoC&DI

                          此时程序正常输出结果:

                          4.Spring IoC&DI

                          总结:

                          4.Spring IoC&DI

                          可以使用 名称获取bean 或者 根据名称和类型来获取bean 这两种方式都可以成功获取到bean。

                          1.4.8.2测试@Bean传递参数是如何选择的

                          当name和name2都存在时,Bean会取走对应的name值 zhangsan。(与name和name2先后顺序无关)

                          4.Spring IoC&DI

                          当name被注释掉,只剩name2存在时,Bean会取走的name2值 wangwu。(bean会只能取走相关的值,而不会不取值,除非没有相关定义的name)

                          4.Spring IoC&DI

                          4.Spring IoC&DI

                          结论:如果需要的Bean的类型,对应的对象只有一个时,就直接赋值,如果有多个时,通过名称去匹配

                          1.4.9启动类位置关系影响

                          SpringBoot 特点;约定大于配置

                          其中之一体现: 就是扫描路径

                          默认扫描路径是: 启动类所在的目录及其子孙目录

                          4.Spring IoC&DI

                          1.5 Bean命名

                          4.Spring IoC&DI

                          如何修改BeanName

                          五大注解

                          4.Spring IoC&DI4.Spring IoC&DI4.Spring IoC&DI

                          1.6@Bean取

                          1.属性注入 @AutoWired

                          2.构造方法注入

                          如果只有一个构造方法, @AutoWired可以省略

                          如果有多个构造方法,必须使用@Qualifier指定(参考2.5.3)一个对象,或使用@Primary注解标识默认的对象(参考2.5.2)

                          3.Setter方法注入

                          @Autowired出现的问题 - 参考2.5

                          2.DI - 依赖注入

                          4.Spring IoC&DI

                          2.1属性注入

                          2.1.1属性注入流程

                          代码:

                          4.Spring IoC&DI

                          4.Spring IoC&DI

                          运行结果图:

                          4.Spring IoC&DI

                          4.Spring IoC&DI

                          2.1.2属性注入问题

                          启动类:

                          4.Spring IoC&DI

                          UserController.java:

                          4.Spring IoC&DI

                          BeanConfig.java:

                          4.Spring IoC&DI

                          运行结果

                          4.Spring IoC&DI

                          当我们使用类UserInfo属性来定义一个新的值时,程序没有发生报错,一切成功运行

                          我们修改一下代码,将userInfo改为user,再次运行

                          4.Spring IoC&DI

                          我们可以看到报错了,报错信息为我们命名为user后,idea找到了一个userInfo和一个userInfo2,此时idea不知道应该使用哪一个导致报错

                          4.Spring IoC&DI

                          如果只有一个对象,属性注入以类型进行匹配,与注入的属性名称无关

                          但是如果一个类型存在多个对象时,优先名称匹配,如果名称

                          都匹配不上,那就报错~

                          4.Spring IoC&DI

                          2.2构造方法注入

                          2.2.1只存在一个构造函数时

                          代码:

                          4.Spring IoC&DI

                          4.Spring IoC&DI

                          运行结果图:

                          4.Spring IoC&DI

                          2.2.2存在多个构造函数时

                          我们增加一个值后,相应的增加了构造函数:

                          4.Spring IoC&DI

                          此时我们运行报了空指针异常。

                          4.Spring IoC&DI

                          通过分析上述代码得知,我们idea默认调用了第一个无参的构造函数,导致us空指针异常

                          我们将无参的构造函数注解掉,再次运行

                          4.Spring IoC&DI

                          报错信息大致为,无参构造函数注解掉后,idea不知道该使用哪个构造函数,导致找不到构造函数,从而报错

                          4.Spring IoC&DI

                          再次修改代码,加上@Autowired,表示我们给idea指定了要用哪个构造函数,再次运行:

                          4.Spring IoC&DI

                          此时可以发现,我们程序运行又回归正常了

                          4.Spring IoC&DI

                          总结:如果存在多个构造函数时,需要加上@AutoWired注明使用哪个构造函数。

                          如果只有一个构造函数时,@AutoWired可以省略掉

                          4.Spring IoC&DI

                          2.3Setter方法注入

                          当我们直接使用构造函数里面的Setter方法自动生成,此时我们的UserService有没有注入进来呢?

                          4.Spring IoC&DI

                          我们运行一下,发现报错了

                          4.Spring IoC&DI

                          报错信息为us空指针异常

                          我们修改一下代码,在Setter方法上面加上@Autowired

                          4.Spring IoC&DI

                          再次运行,可以看到我们的元素再次注入成功!

                          4.Spring IoC&DI

                          从上代码结果可以看出我们在使用Setter方法注入时,也需要在Setter方法上加上 @Autowired 才能运行成功

                          2.4三种注入优缺点分析

                          • 属性注入

                            • 优点:简洁,使用方便。
                            • 缺点:
                              • 只能用于 IoC 容器,如果是非 oC 容器不可用,并且只有在使用的时候才会出现 NPE(空指针异常)
                              • 不能注入一个Final修饰的属性
                              • 构造函数注入(Spring 4.X推荐)

                                • 优点:
                                  • 可以注入final修饰的属性
                                  • 注入的对象不会被修改
                                  • 依赖对象在使用前一定会被完全初始化,因为依赖是在类的构造方法中执行的,而构造方法是在类加载阶段就会执行的方法
                                  • 通用性好,构造方法是JDK支持的,所以更换任何框架,他都是适用的
                                  • 缺点:注入多个对象时,代码会比较繁琐
                                  • Setter注入(Spring 3.X推荐)

                                    • 优点:方便在类实例之后,重新对该对象进行配置或者注入
                                    • 缺点:
                                      • 不能注入一个Final修饰的属性
                                      • 注入对象可能会被改变,因为setter方法可能会被多次调用,就有被修改的风险

                                        2.5@Autowired存在问题

                                        当程序中同一个类型有多个对象是,使用@Autowired会报错(一些情况下)

                                        2.5.1.属性名和你需要使用的对象名保持一致

                                        4.Spring IoC&DI4.Spring IoC&DI4.Spring IoC&DI

                                        可以看到只要名称保持一致,idea就可以正常找到对应的属性名,从而打印出正确的结果。

                                        2.5.2.使用@Primary注解标识默认的对象

                                        4.Spring IoC&DI

                                        2.5.3.使用@Qualifier

                                        4.Spring IoC&DI4.Spring IoC&DI

                                        idea运行结果:

                                        4.Spring IoC&DI

                                        可以看到在加上 @Qualifier("userInfo2") 指定属性名后,idea在运行时就能按照加的属性名指定使用,而不会导致idea不知道使用useInfo还是userInfo2。

                                        2.5.4 使用 @Resource 注解

                                        4.Spring IoC&DI4.Spring IoC&DI4.Spring IoC&DI

                                        可以看到在我们加上了 @Resource 并 @Resource(name = "userInfo2") 指定属性名为 userInfo2 后,我们idea也可以正常打印出结果

                                        2.6常见面试题 - @Autowird 与 @Resouce的区别

                                        • @Autowired 是spring框架提供的注解,而@Resource是JDK提供的注解
                                        • **@Autowired 默认是按照类型注入,而@Resource是按照名称注入.**相比于 @Autowired 来说,@Resource 支持更多的参数设置,例如 name 设置,根据名称获取 Bean。

                                          4.Spring IoC&DI

                                          一个类型存在多个对象:

                                          4.Spring IoC&DI

                                          按照名称来匹配:

                                          4.Spring IoC&DI

                                          3.Ioc、DI、AOP的关系

                                          di依赖注入 AOP面向切片 IOC控制反转

                                          spring是一个轻量级控制反转Ioc和面向切片Aop的容器

                                          控制反转IOC是一种设计思想,DI依赖注入是实现IOC的一种方法

                                          性名为 userInfo2 后,我们idea也可以正常打印出结果

                                          2.6常见面试题 - @Autowird 与 @Resouce的区别

                                          • @Autowired 是spring框架提供的注解,而@Resource是JDK提供的注解
                                          • **@Autowired 默认是按照类型注入,而@Resource是按照名称注入.**相比于 @Autowired 来说,@Resource 支持更多的参数设置,例如 name 设置,根据名称获取 Bean。

                                            [外链图片转存中…(img-M4s0g0ws-1712818818828)]

                                            一个类型存在多个对象:

                                            4.Spring IoC&DI

                                            按照名称来匹配:

                                            4.Spring IoC&DI

                                            3.Ioc、DI、AOP的关系

                                            di依赖注入 AOP面向切片 IOC控制反转

                                            spring是一个轻量级控制反转Ioc和面向切片Aop的容器

                                            控制反转IOC是一种设计思想,DI依赖注入是实现IOC的一种方法

                                            感谢各位读者的阅读,本文章有任何错误都可以在评论区发表你们的意见,我会对文章进行改正的。如果本文章对你有帮助请动一动你们敏捷的小手点一点赞,你的每一次鼓励都是作者创作的动力哦!😘

VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]