【Spring Framework】IoC容器、依赖注入 + 基于XML && 基于注解 && 基于Java Config配置IoC容器 + Spring与JUnit4整合

概念

  • IoC,Inversion of Control,控制反转:将对象的控制权交由第三方统一管理
  • DI,Dependency Injection:依赖注入,使用反射技术,是一种IoC的实现
  • Spring IoC容器:用于统一创建与管理对象依赖
  • XML管理对象(bean):applicationContext.xml

Spring框架使用流程-基于XML配置IoC容器

1. 导入spring坐标

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.3.18</version>
    </dependency>

2. 创建spring配置文件applicationContext.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

</beans>

3. 实例化对象

  • XML管理Bean
  • Bean id与name都是设置对象在IoC容器中的唯一标识,两者在同一个配置文件中不允许重复出现,在不同的配置文件中可以重复出现,新对象覆盖旧对象。【推荐使用bean id标识对象】,在没有设置bean id和name时,使用类全称作为bean标识。

基于构造方法创建对象

    <!--使用constructor-arg子标签,通过带参构造方法创建对象,类中必须包含该构造方法-->
    <bean id="softApple" class="com.EveX.spring.ioc.entity.Apple">
        <constructor-arg name="title" value="金帅"></constructor-arg>
        <constructor-arg name="color" value="黄色"></constructor-arg>
        <constructor-arg name="origin" value="中国"></constructor-arg>
    </bean>

基于静态工厂创建对象(少用,了解)

    <!--通过静态工厂创建对象-->
    <bean id = "sweetApple" class="com.EveX.spring.ioc.factory.AppleFactory" factory-method="creatSweetApple"></bean>

package com.EveX.spring.ioc.factory;

import com.EveX.spring.ioc.entity.Apple;

public class AppleFactory {
    public static Apple creatSweetApple() {
        Apple sweetApple = new Apple();
        sweetApple.setTitle("红富士");
        sweetApple.setColor("红色");
        sweetApple.setOrigin("欧洲");
        return sweetApple;
    }
}

基于工厂实例化创建对象(少用,了解)

IoC容器对工厂类进行实例化并调用对应的实例方法创建对象

    <!--通过工厂实例化创建对象-->
    <bean id = "factoryInstance" class="com.EveX.spring.ioc.factory.AppleFactoryInstance"></bean>
    <bean id = "sweetApple" factory-bean="factoryInstance" factory-method="creatSweetApple"></bean>

package com.EveX.spring.ioc.factory;

import com.EveX.spring.ioc.entity.Apple;

public class AppleFactoryInstance {
    public Apple creatSweetApple() {
        Apple sweetApple = new Apple();
        sweetApple.setTitle("红富士");
        sweetApple.setColor("绿色");
        sweetApple.setOrigin("欧洲");
        return sweetApple;
    }
}

4. 启动IoC容器

初始化IoC容器并根据XML配置文件实例化对象

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");

    }

路径表达式


其中,类的根路径是:

5. 从IoC容器中获取Bean

Apple sweetApple = context.getBean("sweetApple", Apple.class);

6. 依赖注入

利用setter实现对象依赖注入

利用setter实现静态数值注入

  • 使用property子标签,利用setter实现对象依赖注入
  • 类中需要实现属性的get和set方法,IoC容器自动利用反射机制,运行时调用setXXX()方法为属性赋值
    <bean id="sweetApple" class="com.EveX.spring.ioc.entity.Apple">
        <property name="title" value="红富士"></property>
        <property name="color" value="红色"></property>
        <property name="origin" value="欧洲"></property>
    </bean>

利用setter实现对象注入

  • 使用ref子标签注入依赖对象
    <bean id = "lily" class="com.EveX.spring.ioc.entity.Child">
        <property name="name" value="莉莉"></property>
        <property name="apple" ref="sweetApple"></property>
    </bean>

利用构造方法实现对象注入

    <bean id="andy" class="com.EveX.spring.ioc.entity.Child">
        <constructor-arg name="name" value="安迪"></constructor-arg>
        <constructor-arg name="apple" ref="softApple"></constructor-arg>
    </bean>

注入集合对象

注入List(默认ArrayList)


注入Set(默认LinkedHashSet-数据有序)


注入Map(默认LinkedHashMap-数据有序)


注入 Properties

使用键值对(key-value pairs)的形式来存储数据,但要求key和value都是字符串类型

获取容器内对象

  • 使用getBeanDefinitionNames方法获取所有的bean id,然后通过bean id获取每一个bean对象
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
            System.out.println(context.getBean(beanDefinitionName));
        }

bean scope属性

<bean id="..." class="..." scope="prototype">
  • bean scope属性用于决定对象何时被创建与其作用范围
  • bean scope会影响容器中对象的数量
  • 默认情况下,bean会在IoC容器创建后自动实例化,且全局唯一


  • singleton:在IoC容器中,singleton是单例多线程执行,存在线程安全问题
  • prototype:多实例,占用更多资源,不存在线程安全问题

bean生命周期


其中,init-method和destroy-method都是bean的一个子字段,保证其对应的方法名和类的方法相对应即可,在生命周期中会进行执行

Spring框架使用流程-基于注解配置IoC容器

四种组件类型注解


  • 组件类型注解默认bean id为首字母小写的类名
  • 对于不好分类的类,则使用Component注解

初始化IoC容器

  • 在IoC容器初始化时,自动扫描四种组件类型注解并完成实例化

XML配置开启组件扫描

  • 比XML配置IoC容器多一行xmlns:context="http://www.springframework.org/schema/context"
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.EveX">
</beans>

两类自动装配注解


  • 如果装配注解放在set方法上,则自动按类型/名称对set方法参数进行注入
  • 如果放在属性上,IoC容器会自动通过反射技术将属性private修饰符自动改为public,直接进行赋值,赋值完成后再改为pribate,不会执行set方法。
  • 不建议使用按类型注入,如果给一个接口按类型装配,那么其所有实现类都是同类型bean,注入过程会出现问题

@Resource

  1. 设置了name属性,则直接按照name在IoC容器中将bean注入
  2. 未设置name属性
    (1)首先以属性名作为bean name在IoC容器中匹配bean,如果匹配到了则注入
    (2)如果未匹配,则按照类型进行匹配(同@Autowired),如果有冲突,加@Primary注解解决
  • 建议:设置name属性 || 保证属性名与bean name一致

元数据注解


通知IoC容器初始化时加载属性文件

<context:property-placeholder location="classpath:config.properties"></context:property-placeholder>

@Value

  1. 新增配置文件
    config.properties

  2. 添加@Value注解

Spring框架使用流程-基于Java Config配置IoC容器

  • 使用独立的Java类管理对象与依赖

Java Config核心注解


Java Config对象实例化

  1. 增加配置类Config.java
    (1)添加@Configuration注解,表示当前类是一个配置类,用于替代applicationContext.xml配置文件
    (2)添加@Bean注解,Java Config利用方法创建对象,将方法返回的对象放入容器,bean id=方法名
@Configuration
public class Config {
    @Bean
    public Apple sweetApple() {
        return new Apple();
    }
}

  1. 程序入口
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);

Java Config 对象依赖注入

将依赖的对象作为参数传入方法中,对象名作为bean id在容器中存在则直接匹配,如果不存在则进行类型匹配

@Configuration
public class Config {
    @Bean
    public Apple sweetApple() {
        return new Apple();
    }

    @Bean
    public Child lily(Apple sweetApple) {
        Child child = new Child();
        child.setApple(sweetApple);
        return child;
    }
}

Spring与JUnit4整合

  1. 添加spring-test(确保和spring-context版本一致)和junit的依赖
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>5.3.18</version>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
  1. 在测试类上添加@RunWith和@ContextConfiguration注解,将Junit4的执行权交由Spring Test,在测试用例执行前自动初始化IoC容器

  2. 在测试类中加入需要测试的属性

  3. 写测试方法

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class SpringTest {
    @Resource
    private Child andy;

    @Test
    public void testAndy() {
        andy.eat();
    }
}
posted @ 2024-02-28 11:21  沙汀鱼  阅读(10)  评论(0编辑  收藏  举报