Spring -- DI

一、什么是DI

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

二、注入的三种方式

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

2.1 属性注入 @Autowired

使用方法

  1. @Autowired 作用:告诉Spring我们需要这个对象,去loC容器里拿
  2. @Autowired 注入原则
    • 在注入时,是根据类型去注入的
    • 如果一个类型存在多个对象时,优先名称匹配,如果名称都匹配不上,就会报错。
@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
@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
@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
@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
@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是可以省略的
@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方法注入

@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方法可能会被多次调用, 就有被修改的风险。你能改别人也能改,代码就会很乱。
  • 20
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值