IoC和DI

要使用IoC功能就要导入4个Spring的核心容器的jar包:spring-beans、spring-core、spring-context、spring-expression。反转控制(IoC)是控制创建对象的方法,即以前创建对象的工作由开发人员进行,现在将对象创建和依赖关系反转给了Spring进行完成。Spring会根据配置文件对对象进行创建、依赖管理和属性注入。
简单来说,就是创建对象并赋初值,将对象存入Spring仓库等待调用,这样就不必每次调用都创建对象消耗内存了。

  • 创建对象:如何创建、什么时候创建、创建几个、什么时候销毁——由Spring创建,要创建的对象将它的类名写在配置文件Bean标签中就创建,写几个创建几个。默认在容器初始化时创建,默认创建一个(单例),默认在容器销毁时销毁,以上可以通过Bean的scope属性修改。
  • 依赖管理:依赖就是对象属性也是一个(自定义)对象,两个对象的类是相互依赖的。依赖由ref属性进行连接。
  • 属性注入:就是给属性赋初值。初始化属性可以通过Set方法、构造器和p标签三种方式进行。

    基于配置文件的对象创建

    默认在创建容器时创建对象。容器可以创建一个类型对象,也可以创建多个类型对象,只要id不同即可。

    1. <beans xmlns="http://www.springframework.org/schema/beans"
    2. xmlns:p="http://www.springframework.org/schema/p"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://www.springframework.org/schema/beans
    5. https://www.springframework.org/schema/beans/spring-beans.xsd">
    6. // 最简单的一种创建对象方式
    7. <bean class="com.briup.spring.bean.Student" id="student"></bean>
    8. // 基于工厂的创建对象方式
    9. <bean class="com.briup.spring.bean.StudentFactory" id="stuFact" factory-method="getStudent"></bean>
    10. <bean class="com.briup.spring.bean.StudentFactory" id="fact"></bean> // 静态工厂
    11. <bean id="stuFactInstance" factory-method="getStudent2" factory-bean="fact"></bean> // 实例工厂
    12. // 属性赋值之Set方法
    13. <bean id="h" class="com.briup.spring.bean.Student">
    14. <property name="id" value="11"></property>
    15. <property name="name" value="lisi"></property>
    16. <property name="salary" value="105.6"></property>
    17. <property name="wife" ref="w"></property>
    18. </bean>
    19. <bean id="w" class="com.briup.spring.bean.Student2">
    20. <property name="id" value="11"></property>
    21. <property name="name" value="lisi"></property>
    22. <property name="salary" value="105.6"></property>
    23. </bean>
    24. // 属性赋值之构造器
    25. <bean id="c" class="com.briup.spring.bean.Student">
    26. <constructor-arg name="id" value="11"></constructor-arg>
    27. <constructor-arg name="name" value="lisi"></constructor-arg>
    28. <constructor-arg name="salary" value="105.6"></constructor-arg>
    29. <constructor-arg name="wife" ref="w"></constructor-arg>
    30. </bean>
    31. <bean id="d" class="com.briup.spring.bean.Student2">
    32. <constructor-arg name="id" value="11"></constructor-arg>
    33. <constructor-arg name="name" value="lisi"></constructor-arg>
    34. <constructor-arg name="salary" value="105.6"></constructor-arg>
    35. </bean>
    36. // 属性赋值之p标签,需要引入p命名空间约束
    37. <bean id="hunsband" class="com.briup.ioc.Hunsband" p:id="1" p:name="lisi" p:salary="18.9" p:date-ref="now"></bean>
    38. <bean id="now" class="java.util.Date"></bean>
    39. </beans>
    1. ApplicationContext app = new ClassPathXmlApplicationContext("applictionContext.xml");
    2. Student stu = (Student) app.getBean("student"); // 根据id创建对象,适合多个该类型对象时创建
    3. Student student = app.getBean(Student.class); // 根据类的全类名创建对象,适合单个该类型对象创建

    image.png

  • ApplicationContext实现了BeanFactory的接口,BeanFactory是Spring的顶层接口。

  • BeanFactory在创建容器时不会创建对象,而ApplicationContext在创建容器时会创建对象。

    • ClassPathXmlApplicationContext是根据全类名创建。
    • FileSystemXmlApplicationContext是根据配置文件在磁盘中的绝对路径创建。
    • AnnotationConfigApplicationContext则是根据注解和配置类创建。

      基于注解的对象创建

      半注解

      半注解依旧需要配置文件,但配置文件只是指明加入容器的类的对象,即这些类所在的包名,以及配置依赖关系。
      半注解的配置文件如下:
      1. // 在beans添加一个约束:
      2. xmlns:context="http://www.springframework.org/schema/context"
      3. // 指明要扫描的包,该包和子包下的类会被创建对象放到容器中
      4. <context:component-scan base-package="com.briup.annataion"></context:component-scan>
      使用的注解是下面全注解方式中的Bean(pojo)类注解。

      全注解

      自Spring 5起,可以使用全注解方式。要使用全注解方式,需要导入spring-aop的jar包。将一个类变为配置类代替配置文件即可使用全注解方式,从而不必使用配置文件:
  • 配置类注解@Configuration:指明当前类是配置类;@ComponentScan(package):指明当前包或特定位置下的包及子包下的类是Bean类;@Bean:指明将该方法的返回值放入Spring容器中,能够被其它Bean类所依赖;@PropertySource:加载配置文件,可以使用${key}调用文件的value值;@Import:导入其它配置类。

  • Bean(pojo)类注解@Component@Controller@Service@Repository:功能一样,但语义不同,分别指明该类为Bean、Web、Service、Dao层的对象;@Scope:指定Bean类的生命周期,可以为singleton单例、prototype多例、request、session、golbal session;@Value(value):为属性使用Set方法赋值;@Autowaired:根据属性类型从容器调用合适的对象自动赋值;@Qualifier(value):为Autowaired指明一个id,也可以用在方法的参数上;@Resource(name):按照容器内对象的id注入;@PostConstruct:指定该方法在对象初始化时调用;@PostDestroy:指定该方法在对象销毁时调用。

    生命周期

    容器中对象的生命周期:单例为默认的生命周期,在容器创建时创建(如果是BeanFactory则是在调用时创建),容器销毁时销毁。多例基本一样,但不会调用销毁时要调用的方法(destroy方法)。request、session、golbal session则是将对象存入这些对象中,且与这些对象的生命周期相同,其中golbal session指的是集群中全局session。

    测试

    Spring使用了容器存储对象,但每次测试都需要读取配置文件、创建容器、创建对象;如果测试类的成员变量使用了@Autowaired之类的注解,但此时又没创建容器,就十分麻烦;诸如此类不方便测试的问题接踵而至。故Spring整合了JUnit,能够方便地进行测试。要进行测试,要导入test包和JUnit包。JUnit的版本可以是4,也可以是5,但导入的类不同。
    测试方式:
    JUnit4:在正常配置配置文件或配置类后,在测试类添加注解:@RunWith(SpringJUnit4ClassRunner.class)@RunWith(SpringRunner.class),以及@ContextConfiguration(classes=TestConfig.class)即可,其中location是配置文件路径,classes是配置类全类名数组。
    JUnit5:在正常配置配置文件或配置类后,在测试类添加注解:@ExtendWith(SpringExtension.class)@ContextConfiguration(classes=TestConfig.class);或@SpringJUnitConfig(classes = TestConfig.class)