实验一 -配置和获取

1.实验目标和思路

由Spring的IOC容器创建类的对象

img006.c8bae859.png

2、创建Maven Module

  1. <dependencies>
  2. <!-- 基于Maven依赖传递性,导入spring-context依赖即可导入当前所需所有jar -->
  3. <dependency>
  4. <groupId>org.springframework</groupId>
  5. <artifactId>spring-context</artifactId>
  6. <version>5.3.1</version>
  7. </dependency>
  8. <!-- junit测试 -->
  9. <dependency>
  10. <groupId>junit</groupId>
  11. <artifactId>junit</artifactId>
  12. <version>4.12</version>
  13. <scope>test</scope>
  14. </dependency>
  15. </dependencies>

基于XML管理bean(上) - 图3

3、创建组件类

  1. package com.atguigu.ioc.component;
  2. public class HappyComponent {
  3. public void doWork() {
  4. System.out.println("component do work ...");
  5. }
  6. }

4、创建 Spring 配置文件

fc6ff35a-7717-41e7-9a80-4b37076e95fd.png
download.png

5、配置组件

  1. <!-- 实验一 [重要]创建bean -->
  2. <bean id="happyComponent" class="com.atguigu.ioc.component.HappyComponent"/>
  • bean标签:通过配置bean标签告诉IOC容器需要创建对象的组件是什么
  • id属性:bean的唯一标识
  • class属性:组件类的全类名

    6、创建测试类

    ```java public class IOCTest {

    // 创建 IOC 容器对象,为便于其他实验方法使用声明为成员变量 private ApplicationContext iocContainer = new ClassPathXmlApplicationContext(“applicationContext.xml”);

    @Test public void testExperiment01() {

      // 从 IOC 容器对象中获取bean,也就是组件对象
      HappyComponent happyComponent = (HappyComponent) iocContainer.getBean("happyComponent");
    
      happyComponent.doWork();
    

    }

}

<a name="roaHn"></a>
## 7.无参构造器
**Spring底层默认通过反射调用组件类的无参构造器来创建对象。如果没有会抛出以下异常**
> org.springframework.beans.factory.BeanCreationException**: Error creating bean with name **'happyComponent1' defined in class path resource [applicationContext.xml]: Instantiation of bean failed; 
> nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.atguigu.ioc.component.HappyComponent]: No default constructor found; 
> nested exception is java.lang.NoSuchMethodException: com.atguigu.ioc.component.HappyComponent.<init>()
> 


<a name="p8gf2"></a>
# 实验二 -根据类类型获取bean

<a name="DHpte"></a>
## 1、方式一:根据id获取
由于 id 属性指定了 bean 的唯一标识,所以根据 bean 标签的 id 属性可以精确获取到一个组件对象。上个实验中我们使用的就是这种方式。
<a name="VVgjy"></a>
## 2、方式二:根据类型获取
<a name="gI8bZ"></a>
### ①指定类型的 bean 唯一
```java
@Test
public void testExperiment02() {

    HappyComponent component = iocContainer.getBean(HappyComponent.class);

    component.doWork();

}

②指定类型的 bean 不唯一

相同类型的 bean 在IOC容器中一共配置了两个:

<!-- 实验一 [重要]创建bean -->
<bean id="happyComponent" class="com.atguigu.ioc.component.HappyComponent"/>

<!-- 实验二 [重要]获取bean -->
<bean id="happyComponent2" class="com.atguigu.ioc.component.HappyComponent"/>

根据类型获取时会抛出异常:

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type ‘com.atguigu.ioc.component.HappyComponent’ available: expected single matching bean but found 2: happyComponent,happyComponent2

③思考

如果组件类实现了接口,根据接口类型可以获取 bean 吗?

可以,前提是bean唯一

如果一个接口有多个实现类,这些实现类都配置了 bean,根据接口类型可以获取 bean 吗?

不行,因为bean不唯一

④结论

根据类型来获取bean时,在满足bean唯一性的前提下,其实只是看:『对象 instanceof 指定的类型』的返回结果,只要返回的是true就可以认定为和类型匹配,能够获取到。

实验三 [重要]给bean的属性赋值:setter注入

1、给组件类添加一个属性

public class HappyComponent {

    private String componentName;

    public String getComponentName() {
        return componentName;
    }

    public void setComponentName(String componentName) {
        this.componentName = componentName;
    }

    public void doWork() {
        System.out.println("component do work ...");
    }

}

2、在配置时给属性指定值

通过property标签配置的属性值会通过setXxx()方法注入,大家可以通过debug方式验证一下

<bean id="happyComponent3" class="com.atguigu.ioc.component.HappyComponent">

    <!-- property标签:通过组件类的setXxx()方法给组件对象设置属性 -->
    <!-- name属性:指定属性名(这个属性名是getXxx()、setXxx()方法定义的,和成员变量无关) -->
    <!-- value属性:指定属性值 -->
    <property name="componentName" value="veryHappy"/>
</bean>

实验四 [重要]给bean的属性赋值:引用外部已声明的bean

1、声明新的组件类

public class HappyMachine {

    private String machineName;

    public String getMachineName() {
        return machineName;
    }

    public void setMachineName(String machineName) {
        this.machineName = machineName;
    }
}

2、原组件引用新组件

image.png

3、配置新组件的 bean

<bean id="happyMachine" class="com.atguigu.ioc.component.HappyMachine">
    <property name="machineName" value="makeHappy"/>
</bean>

4、在原组件的 bean 中引用新组件的 bean

<bean id="happyComponent4" class="com.atguigu.ioc.component.HappyComponent">
    <!-- ref 属性:通过 bean 的 id 引用另一个 bean -->
    <property name="happyMachine" ref="happyMachine"/>
</bean>

基于XML管理bean(上) - 图7

5、易错点

如果错把ref属性写成了value属性,会抛出异常:
Caused by: java.lang.IllegalStateException: Cannot convert value of type ‘java.lang.String’ to required type ‘com.atguigu.ioc.component.HappyMachine’ for property ‘happyMachine’: no matching editors or conversion strategy found
意思是不能把String类型转换成我们要的HappyMachine类型
说明我们使用value属性时,Spring只把这个属性看做一个普通的字符串,不会认为这是一个bean的id,更不会根据它去找到bean来赋值

实验五 [重要]给bean的属性赋值:内部bean

1、重新配置原组件

在bean里面配置的bean就是内部bean,内部bean只能在当前bean内部使用,在其他地方不能使用。

<!-- 实验五 [重要]给bean的属性赋值:内部bean -->
<bean id="happyComponent5" class="com.atguigu.ioc.component.HappyComponent">
    <property name="happyMachine">
        <!-- 在一个 bean 中再声明一个 bean 就是内部 bean -->
        <!-- 内部 bean 可以直接用于给属性赋值,可以省略 id 属性 -->
        <bean class="com.atguigu.ioc.component.HappyMachine">
            <property name="machineName" value="makeHappy"/>
        </bean>
    </property>
</bean>

实验六 [重要]给bean的属性赋值:引入外部属性文件

1、加入依赖

<!-- MySQL驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.3</version>
        </dependency>
        <!-- 数据源 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.31</version>
        </dependency>

2、创建外部属性文件

image.png

jdbc.user=root
jdbc.password=atguigu
jdbc.url=jdbc:mysql://192.168.198.100:3306/mybatis-example
jdbc.driver=com.mysql.jdbc.Driver

3、引入

  <!-- 引入外部属性文件 -->
    <context:property-placeholder location="classpath:jdbc.properties"/>

4、使用

<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="url" value="${jdbc.url}"/>
    <property name="driverClassName" value="${jdbc.driver}"/>
    <property name="username" value="${jdbc.user}"/>
    <property name="password" value="${jdbc.password}"/>
</bean>

注意是driverClassName!!!!!

5、测试

@Test
public void testExperiment06() throws SQLException {
    DataSource dataSource = iocContainer.getBean(DataSource.class);

    Connection connection = dataSource.getConnection();

    System.out.println("connection = " + connection);
}

实验七 给bean的属性赋值:级联属性赋值

1、配置关联对象的 bean

<bean id="happyMachine2" class="com.atguigu.ioc.component.HappyMachine"/>

2、装配关联对象并赋值级联属性

关联对象:happyMachine
级联属性:happyMachine.machineName

<!-- 实验七 给bean的属性赋值:级联属性赋值 -->
<bean id="happyComponent6" class="com.atguigu.ioc.component.HappyComponent">
    <!-- 装配关联对象 -->
    <property name="happyMachine" ref="happyMachine2"/>
    <!-- 对HappyComponent来说,happyMachine的machineName属性就是级联属性 -->
    <property name="happyMachine.machineName" value="cascadeValue"/>
</bean>

实验八 给bean的属性赋值:构造器注入

配置

<!-- 实验八 给bean的属性赋值:构造器注入 -->
<bean id="happyTeam" class="com.atguigu.ioc.component.HappyTeam">
    <constructor-arg value="happyCorps"/>
    <constructor-arg value="10"/>
    <constructor-arg value="1000.55"/>
</bean>