Spring -- DI

文章目录

一、什么是DI

  1. 概念:DI(依赖注入)就是当我们把依赖对象取出来(创建好后),赋值给该对象的属性
  2. DI的其他翻译:属性装配、依赖装配

二、注入的三种方式

注入只是去拿,但是有没有,是要依靠【Spring实现的loC的方式】

2.1 属性注入 @Autowired

使用方法

  1. @Autowired 作用:告诉Spring我们需要这个对象,去loC容器里拿
  2. @Autowired 注入原则
    • 在注入时,是根据类型去注入的
    • 如果一个类型存在多个对象时,优先名称匹配,如果名称都匹配不上,就会报错。
java 复制代码
@Controller
public class TestController {
    @Autowired
    private UserService userService;
    public void doController(){
        userService.doService();
        System.out.println("这是Controoler注解");
    }
}

@Service
public class UserService {
    public void doService(){
        System.out.println("这是Service注解");
    }
}
  1. 关于报错:因为@Autowired不是官方推荐写法,所以IDEA可能会报错。但即便如此,由于操作简单,使用量依旧很高
  2. 使用Debug查看当前变量的值:Debug状态下,选中某个变量,选择"Evaluate Expression......"可以进行数值模拟

@Autowired存在的问题以及解决方法

因为构造方法注入和Setter注入都是依据@Autowired实现的,所以它们也存在下面的问题

  1. 有多个类型时要根据名称去拿,有报错的风险
  2. 没有办法去注入一个由final修饰的属性:因为final是不可变的,要求是在定义期间或初始化期间给其赋值
  3. 使用量太高了,可能会滥用
  4. 违反了软件设计的单一原则

@Autowired问题的解决方法

【1】方法介绍:

  1. 让属性名和你需要的对象名称一致:这样@Autowired就可以根据名称匹配

  2. 如果不想保持一致:使用@Primary、@Qualifier

    • @Primary:标识默认的对象
    • @Qualifier:指定要使用的Bean名称
      • 既然@Autowired没办法加上属性名,我们就用其他的注解来给其加上属性名
    • @Resource:通过描述bean的信息,去指定要用哪个
  3. 重命名Bean:

  4. @Autowird VS @Resource

    • 提供者不同:ctrl或选中注解就可以出现该注解的相关信息,点击小圆球可以定位包。rt是jdk的包。
      • @Autowired 是Spring框架提供的注解,而@Resource是JDK提供的注解
    • 注入方式:
      • @Autowired 默认是按照类型注入,如果同一个类型存在多个,再按照名称匹配,如果名称匹配不上,就会报错
      • @Resource 支持更多的参数设置,例如 name 设置,可以根据名称获取 Bean

【2】方法的具体使用:

  1. 使用@Primary:
java 复制代码
@Configuration
public class BeanConfig {
    @Bean
    public UserInfo userInfoZ(){
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("zhangsan");
        userInfo.setPassword("123456");
        return userInfo;
    }

    @Primary
    @Bean
    public UserInfo userInfoL(){
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("lisi");
        userInfo.setPassword("123456");
        return userInfo;
    }

}

@Controller
public class TestController {
    @Autowired
    private UserInfo userInfo;

    public void doController(){
        System.out.println(userInfo); //lisi
    }
}
  1. 使用@Qualifier:
java 复制代码
@Configuration
public class BeanConfig {
    @Bean
    public UserInfo userInfoZ(){
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("zhangsan");
        userInfo.setPassword("123456");
        return userInfo;
    }

    @Bean
    public UserInfo userInfoL(){
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("lisi");
        userInfo.setPassword("123456");
        return userInfo;
    }

}

@Controller
public class TestController {
	@Qualifier("userInfoZ")
    @Autowired
    private UserInfo userInfo;

    public void doController(){
        System.out.println(userInfo); //zhangsan
    }
}
  1. 使用@Resource:
java 复制代码
@Configuration
public class BeanConfig {
    @Bean
    public UserInfo userInfoZ(){
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("zhangsan");
        userInfo.setPassword("123456");
        return userInfo;
    }
    @Bean
    public UserInfo userInfoW(String nameW){
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername(nameW);
        userInfo.setPassword("123456");
        return userInfo;
    }

    @Bean
    public String nameW(){
        return "wangwu";
    }

}

@Controller
public class TestController {
    @Resource(name = "userInfoW")
    @Autowired
    private UserInfo userInfo;
    
    public void doController(){
        System.out.println(userInfo);  //wangwu
    }
}
  1. 重命名Bean:
java 复制代码
@Configuration
public class BeanConfig {
    @Bean("u1")
    public UserInfo userInfoZ(){
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("zhangsan");
        userInfo.setPassword("123456");
        return userInfo;
    }

    @Bean
    public UserInfo userInfoL(){
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("lisi");
        userInfo.setPassword("123456");
        return userInfo;
    }

}

@Controller
public class TestController {
    @Autowired
    private UserInfo u1;

    public void doController(){
        System.out.println(u1); //zhangsan
    }
}

2.2 构造方法注入

  1. 构造函数的创建问题 :
    • 当我们新增了属性时,可能就要去新加上构造方法,十分繁琐
    • 当我们添加了有参的构造函数,就不会默认生成无参的构造函数了,如果需要用无参的,就需要手动生成
  2. @Autowired 指定用哪个构造函数 :当有多个构造函数且没有指定用哪个时,Spring去初始化就会不知道用哪个,可能会报错
    • 如果有无参构造函数,默认用无参的,此时userService为null
    • 如果没有无参构造函数,我们需要用@Autowired告诉Spring使用哪个构造函数。当然,如果只有一个构造函数时,@Autowired是可以省略的
java 复制代码
@Controller
public class TestController {
    private UserService userService;

    @Autowired
    public TestController(UserService userService) {
        this.userService = userService;
    }

    public TestController() {
    }

    public void doController(){
        userService.doService();
        System.out.println("这是Controoler注解");
    }
}

@Service
public class UserService {
    public void doService(){
        System.out.println("这是Service注解");
    }
}

2.3 setter方法注入

java 复制代码
@Controller
public class TestController {
    private UserService userService;

    @Autowired    //需要加上,不加会报错
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void doController(){
        userService.doService();
        System.out.println("这是Controoler注解");
    }
}

2.4 三种注入方式优缺点分析

  1. 属性注入 :虽然不被官方推荐,但因为简单,程序员推荐使用
    • 优点: 简洁,使用方便
    • 缺点:
      • @Autowired是Spring提供的,只能在Spring这使用
      • 不能注入⼀个Final修饰的属性
  2. 构造函数注⼊(Spring 4.X推荐)
    • 优点:
      • 符合final可以在构造方法中赋值的设定,故而可以注入final修饰的属性
      • 注入的对象不会被修改。因为构造函数是在创建对象的时候执行的,执行完之后除非再创建一个对象,或者使用Setter注入,否则不会轻易被改变。
      • 依赖对象在使用前⼀定会被完全初始化,因为依赖是在类的构造方法中执行的,而构造方法是在类加载阶段就会执行的方法
      • 通用性好, 构造方法是JDK支持的,即使是更换任何框架,他都是适用的
    • 缺点:注入多个对象时, 代码会比较繁琐,还需要用@Autowired指定
  3. Setter注入(Spring 3.X推荐) :事实上,当一个对象需要被修改,我们就没必要交给Spring管理了,直接自己new一个算了
    • 优点:方便在类实例之后, 重新对该对象进行配置或者注入
    • 缺点:
      • 不能注入⼀个Final修饰的属性
      • 注入对象可能会被改变, 因为setter方法可能会被多次调用, 就有被修改的风险。你能改别人也能改,代码就会很乱。
相关推荐
我是人✓7 小时前
Java文件上传三方式对比:从传统到SpringBoot
java·开发语言
欣栀♡7 小时前
JVM 频繁 Full GC 先看日志括号里的 cause,jstat 的 FGC 在 JDK 8 上会骗人
java·jvm
IT研究室8 小时前
最新计算机毕业设计选题推荐-基于spring boot的葡萄酒文化宣传网站-网站-文档指导-Java-springboot
java·spring boot·课程设计
慧都小项8 小时前
MyEclipse 中创建和测试 JAX-RS REST 接口:从项目配置到 REST Explorer
java·restful·myeclipse·jax-rs
Wang's Blog8 小时前
Java 项目实战: 交友项目 - 入门案例:编写 Dubbo 服务提供者
java·dubbo·交友
秋饼8 小时前
Spring AI 2.0 结构化输出企业级实战:从 BeanOutputConverter 源码到生产级解析容错
java·ai·技术分享·后端开发
摇滚侠8 小时前
《计算机是如何工作的:人人都能懂的计算机软硬件工作原理》第 9 章 机器码与汇编语言 阅读笔记 9
java·开发语言·笔记
Cc.Y8 小时前
Java零基础入门:深入Java核心:文件IO与序列化全解
java·开发语言·python
拿本唠嗑AI研究9 小时前
本体工程实战指南:从建模到可维护的完整落地路径
java·人工智能·python·jena·ontology
lambo mercy9 小时前
Day3:结构化输出
java·数据库·oracle