• 【Java EE】依赖注入DI详解


    🌴什么是依赖注入

    依赖注⼊是⼀个过程,是指IoC容器在创建Bean时, 去提供运⾏时所依赖的资源,⽽资源指的就是对象.

    简单来说, 就是把对象取出来放到某个类的属性中

    在⼀些⽂章中, 依赖注⼊也被称之为 “对象注⼊”, “属性装配”, 具体含义需要结合⽂章的上下⽂来理解

    🍀依赖注入的三种方法

    关于依赖注⼊, Spring也给我们提供了三种⽅式:

    1. 属性注⼊(Field Injection)
    2. 构造⽅法注⼊(Constructor Injection)
    3. Setter 注⼊(Setter Injection)

    🌸属性注入(Field Injection)

    属性注⼊是使⽤ @Autowired 实现的。

    比如我们将StudentService类注⼊到StudentController类中.

    StudentService.java代码如下:

    @Service
    public class StudentService {
        public void run() {
            System.out.println("StudentService启动");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    StudentController.java代码如下:

    @RestController
    public class StudentController {
        @Autowired
        private StudentService studentService;
        public void run() {
        	System.out.println("StudentController启动");
            studentService.run();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    获取StudentController中的run方法

    @SpringBootApplication
    public class SpringMvcApplication {
    
        public static void main(String[] args) {
            //获取spring上下文
            ApplicationContext context = SpringApplication.run(SpringMvcApplication.class, args);
            //从spring中获取对象
            StudentController studentController = context.getBean("studentController",StudentController.class);
            //使用spring对象
            studentController.run();
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    🌸构造方法注入

    构造⽅法注⼊是在类的构造⽅法中实现注⼊,如下代码所示:

    @RestController
    public class StudentController {
    
        private StudentService studentService;
    
        public StudentController() {
        }
        
        @Autowired
        public StudentController(StudentService studentService) {
            this.studentService = studentService;
        }
        public void run() {
            System.out.println("StudentController启动");
            studentService.run();
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    注意事项:

    • 如果类只有⼀个构造⽅法,那么@Autowired注解可以省略;如果类中有多个构造⽅法,那么需要添加上@Autowired来明确指定到底使⽤哪个构造⽅法

    🌸Setter注入

    Setter注入和属性的Setter⽅法实现类似,只不过在设置set⽅法的时候需要加上@Autowired注解

    @RestController
    public class StudentController {
    
        private StudentService studentService;
    
        @Autowired
        public void setStudentService(StudentService studentService) {
            this.studentService = studentService;
        }
        public void run() {
            System.out.println("StudentController启动");
            studentService.run();
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    🌸三种注入优缺点分析

    属性注⼊

    • 优点: 简洁,使⽤⽅便;
    • 缺点:
      – 只能⽤于 IoC 容器,如果是⾮ IoC 容器不可⽤,并且只有在使⽤的时候才会出现 NPE(空指
      针异常)
      – 不能注⼊⼀个Final修饰的属性

    构造函数注入

    • 优点:
      – 可以注⼊final修饰的属性
      – 注⼊的对象不会被修改
      – 依赖对象在使⽤前⼀定会被完全初始化,因为依赖是在类的构造⽅法中执⾏的,⽽构造⽅法
      是在类加载阶段就会执⾏的⽅法.
      – 通⽤性好, 构造⽅法是JDK⽀持的, 所以更换任何框架,他都是适⽤的

    • 缺点:
      – 注⼊多个对象时, 代码会⽐较繁琐

    Setter注入

    • 优点: ⽅便在类实例之后, 重新对该对象进⾏配置或者注⼊
    • 缺点:
      – 不能注⼊⼀个Final修饰的属性
      – 注⼊对象可能会被改变, 因为setter⽅法可能会被多次调⽤, 就有被修改的⻛险

    🌳@Autowired存在的问题

    当同⼀类型存在多个bean时,在使⽤@Autowired就会存在问题

    比如我们有以下bean。

    BeanFiguation.java代码如下:

    @Configuration
    public class BeanFiguation {
        @Bean
        public Student student1() {
            Student student = new Student();
            student.setId(11);
            student.setName("山高路远");
            student.setAge(11);
            return student;
        }
        @Bean
        public Student student2() {
            Student student = new Student();
            student.setId(22);
            student.setName("与君共勉");
            student.setAge(22);
            return student;
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    StudentController.java代码如下:

    @RestController
    public class StudentController {
    
        @Autowired
        private Student student;
    
        public void run() {
            System.out.println(student);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    当我们进行启动时:
    在这里插入图片描述
    报错的原因是,⾮唯⼀的 Bean 对象

    🌲解决@Autowired对应多个对象问题

    为了解决上述问题,Spring提供了以下4种解决⽅案:

    • bean对象名称与属性名相匹配
    • @Primary
    • @Qualifier
    • @Resource

    第一种:bean对象名称与属性名相匹配
    在这里插入图片描述
    第二种:使⽤@Primary注解:当存在多个相同类型的Bean注⼊时,加上@Primary注解,来确定默认的实现.

    @Component
    public class BeanConfig {
     @Primary //指定该bean为默认bean的实现
     @Bean("u1")
     public User user1(){
     User user = new User();
     user.setName("zhangsan");
     user.setAge(18);
     return user;
     }
     @Bean
     public User user2() {
     User user = new User();
     user.setName("lisi");
     user.setAge(19);
     return user;
     }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    第三种:使⽤@Qualifier注解:指定当前要注⼊的bean对象。在@Qualifier的value属性中,指定注⼊的bean的名称。

    @Qualifier注解不能单独使⽤,必须配合@Autowired使⽤

    @Controller
    public class UserController {
     @Qualifier("user2") //指定bean名称
     @Autowired
     private User user;
     public void sayHi(){
     System.out.println("hi,UserController...");
     System.out.println(user);
     }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    第四种:使⽤@Resource注解:是按照bean的名称进⾏注⼊。通过name属性指定要注⼊的bean的名称。

    @Controller
    public class UserController {
     @Resource(name = "user2")
     private User user;
     public void sayHi(){
     System.out.println("hi,UserController...");
     System.out.println(user);
     }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    🍃@Autowird与@Resource的区别

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

    ⭕总结

    感谢大家的阅读,希望得到大家的批评指正,和大家一起进步,与君共勉!

  • 相关阅读:
    MySQL 8.0 架构 之 慢查询日志(Slow query log)(2)流程图:查询记录到慢查询日志中的条件
    AntvG6-graph图谱工具
    Go的函数(function)
    园林绿化资质怎么办理,新办园林绿化资质资产要求解读
    python学习笔记(4)—— 模型
    matlab之数组排序的方法和函数
    自动登录远程linux服务器
    JS高级:进程与线程
    asp.net基于net的冰淇淋订单管理系统-计算机毕业设计
    java中几种对象存储(文件存储)中间件的介绍
  • 原文地址:https://blog.csdn.net/m0_65941010/article/details/137975099