title: 【学习之路】SpringIoC学习
draft: true
tags:


什么是IoC

控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。

SpringIoC HelloWord

  1. 导包
    spring-beans-4.3.21.RELEASE
    spring-context-4.3.21.RELEASE
    spring-core-4.3.21.RELEASE
    spring-expression-4.3.21.RELEASE

Spring依赖commons-logging也需要导入
创建一个person类

  1. public class Person {
  2. private String lastName;
  3. private Integer age;
  4. private String sex;
  5. @Override
  6. public String toString() {
  7. return "Person{" +
  8. "lastName='" + lastName + '\'' +
  9. ", age=" + age +
  10. ", sex='" + sex + '\'' +
  11. '}';
  12. }
  13. public String getLastName() {
  14. return lastName;
  15. }
  16. public void setLastName(String lastName) {
  17. this.lastName = lastName;
  18. }
  19. public Integer getAge() {
  20. return age;
  21. }
  22. public void setAge(Integer age) {
  23. this.age = age;
  24. }
  25. public String getSex() {
  26. return sex;
  27. }
  28. public void setSex(String sex) {
  29. this.sex = sex;
  30. }
  31. }

配置spring的xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <!-- 使用bean标签注册一个组件(对象,类) id为对象的唯一标识 -->
  6. <bean id="person" class="com.zixuan.my_spring.Person">
  7. <!-- property中注入属性 -->
  8. <property name="lastName" value="张三"></property>
  9. <property name="age" value="18"></property>
  10. <property name="sex" value="男"></property>
  11. </bean>
  12. </beans>
  1. public class IocTest {
  2. @Test
  3. public void test01(){
  4. // 读取xml文件注入到ioc容器中
  5. ApplicationContext ioc = new ClassPathXmlApplicationContext("conf/ioc.xml");
  6. // 用唯一id获取bean对象
  7. Person person = (Person) ioc.getBean("person");
  8. System.out.println(person);
  9. }
  10. }

SpringIoC - 图1

在这个测试中我们并没有new Person也创建了Person实列

IoC注入细节


查看IoC容器注入对象时间

在person类中定义空参构造方法

  1. public Persion(){
  2. System.out.println("Person创建");
  3. }

注释掉测试方法中的

  1. Person person = (Person) ioc.getBean("person");
  2. System.out.println(person);

再次运行测试方法

SpringIoC - 图2

这次运行后发现,容器中对象的创建在容器创建完成的时候就创建好了

如果当前bean对象的值不是单列那么只有在调用getBean()方法的时候才会创建对象

获取两次bean对象判断对象地址值

SpringIoC - 图3

SpringIoC - 图4

返回true得知同一个组件在IoC容器中是单实列的

修改容器中是否为单列模式

  1. <!--
  2. <bean> 标签中scope属性中的值
  3. prototype:多实例的
  4. 1. 容器启动默认不会去创建多实例bean
  5. 2. 在调用getBean()的时候才会创建bean
  6. 3. 每次获取都会创建一个新的实列
  7. singleton:单实例的 默认
  8. 1. 在容器启动完成之前就已经创建好对象,保存在容器中了。
  9. 2. 在任何获取都是之前创建好的哪个对象
  10. -->
  11. <bean class="com.zixuan.spring.bean.Person" id="person" scope="prototype"></bean>

容器中没有组件

SpringIoC - 图5

容器中没有组件会抛出异常

javaBean属性注入方式

  1. 属性注入方式是通过get set方法进行注入
  2. JavaBean属性名是通过get set方法决定的

使用FactoryBean注入

FactoryBean是Spring规定的一个接口

只要是这个接口的实现类Spring都认为是一个工厂

实现FactoryBean之后IoC容器启动的时候不会创建实列,只有在调用getBean()方法的时候才会创建

  1. public class MyFactoryBeanImpl implements FactoryBean<Book> {
  2. /**
  3. * 工厂方法
  4. * @return 返回创建的对象
  5. * @throws Exception
  6. */
  7. @Override
  8. public Book getObject() throws Exception {
  9. System.out.println("MyFactoryBean 创建对象");
  10. Book book = new Book();
  11. book.setBookName("1123");
  12. book.setPrice(123.1);
  13. return book;
  14. }
  15. /**
  16. * 返回创建的对象类型
  17. * Spring会自动调用这个方法来确认创建的对象时什么类型
  18. */
  19. @Override
  20. public Class<?> getObjectType() {
  21. return Book.class;
  22. }
  23. /**
  24. * 是否是单列
  25. * @return true是单列,false不是单列
  26. */
  27. @Override
  28. public boolean isSingleton() {
  29. return true;
  30. }
  31. }
  1. <bean class="com.zixuan.spring.MyFactoryBeanImpl"
  2. id="myFactoryBeanImpl"></bean>

使用注解添加到IoC容器

通过给bean添加注解,可以快速将bean加入到IoC容器中
某个类上添加上类和一个注解都能快速的将这个组件加入到IoC容器中
Spring有四个注解
@Controller:推荐给控制器加这个组件
@Service:推荐给业务逻辑层添加这个注解
@Repository:推荐dao层添加这个注解
@Component:给不属于MVC添加这个注解

注解可以随便加:Spring底层不会去验证添加的注解是否是当前层,
只是为了更好的可读性推荐使用这种添加注解的方式

使用注解将快速的加入到ioc容器中需要以下几步

  1. 给要添加的组件上标注四个注解中的任何一个

  2. 告诉Spring,自动扫描了加了注解的组件:依赖context空间

  3. 需要导入aop包,支持注解模式

  1. @Controller
  2. public class MySpringController {}

导入context命名空间

  1. xmlns:context="http://www.springframework.org/schema/context"

开启包扫描

  1. <context:component-scan base-package="com.zixuan.spring"></context:component-scan>

使用@Autowirde实现自动装配

DI依赖注入@Autowired
该注解会自动装配对象,不需要手动的去new
想使用该对象必须要将该类加入到IoC容器中,否则会找不到该对象

  1. @Controller
  2. public class MySpringController {
  3. /**
  4. * DI依赖注入@Autowired
  5. * 该注解会自动装配对象,不需要手动的去new
  6. * 想使用该对象必须要将该类加入到IoC容器中,否则会找不到该对象
  7. */
  8. @Autowired
  9. private MySpringService mySpringService;
  10. public void test(){
  11. mySpringService.test();
  12. }
  13. }

Autowirder装配机制

MySpringController bean = ioc.getBean(MySpringController.class);
先按照类型去容器中找到对应的组件

  • 找到一个:找到就赋值

  • 没找到:抛异常

  • 找到多个

    • 按照变量名作为id继续装配

      • 匹配上就装配
      • 没有匹配上就报错
        原因,因为是使用变量名作为id去装配的
  • 使用@Qualifier指定一个新的id

    • 找到装配
    • 找不到报错
  • 如果将@Autowired写在方法上

    • 那么这个方法也会在bean创建的时候复制
    • 这个方法的每一个参数都会自动注入值

Autowirder属性

  1. boolean required() default true;

默认值为true,当前组件如果在IoC容器找不到就会报错,修改为false找不到组件那么就不会报异常