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方法可能会被多次调用, 就有被修改的风险。你能改别人也能改,代码就会很乱。
相关推荐
柒七爱吃麻辣烫9 分钟前
访问Maven私服的教程
java·maven
二进制独立开发19 分钟前
[Trae 04.22+]适用于JAVA Spring开发的智能体提示词
spring·trae
Tang102433 分钟前
Glide 4.x 版本的图片加载流程
java
振宇i35 分钟前
Java 富文本转word
java·word·富文本·docx4j
李菠菜35 分钟前
Java对象映射利器MapStruct应用详解与实战指南
java
神仙别闹38 分钟前
基于Java+MySQL 实现(Web)日程管理系统
java·前端·mysql
黯_森39 分钟前
Java异常机制
java·后端
A阳俊yi1 小时前
Spring Boot日志配置
java·spring boot·后端
苹果酱05671 小时前
2020-06-23 暑期学习日更计划(机器学习入门之路(资源汇总)+概率论)
java·vue.js·spring boot·mysql·课程设计
echo1754251 小时前
Apipost免费版、企业版和私有化部署详解
java