第2节 Spring IOC 容器对 Bean 的管理

194 阅读3分钟

一、Spring IOC 容器

  IOC(Inversion of Control) ,即控制反转。通常情况下我创建一个对象都是在程序中通过 new 关键字来完成的。在使用 Spring 框架后,对象的创建由 IOC 容器来完成。

二、Spring IOC 容器对 Bean 的管理

IOC 容器对 Bean 的管理主要体现在两个方面

  1. 创建对象
  2. 注入属性

IOC 容器对 Bean 的管理方式

IOC 容器对 Bean 的管理手段主要是:依赖注入,实现依赖注入的方式有如下形式:

1. 基于 xml 文件的方式

(1) xml 方式创建对象
该种方式在创建对象时,默认也是执行 User 类的无参构造方法来完成对象的创建。

public class User implements Serializable {
    private String username;
    
    public User() {
    }
}
<bean id="user" class="com.sff.demo.bean.User"></bean>

(2) xml方式注入属性

  • set方法注入属性
public class Student implements Serializable {
    private String name;

    public void setName(String name) {
        this.name = name;
    }
}
<bean id="student" class="com.sff.demo.bean.Student">
    <!-- 
        name:类里面的属性名称
        value:向属性中注入的值
    -->
    <property name="name" value="Kate"></property>
</bean>
  • 有参数构造器注入属性
public class Order implements Serializable  {
    private String orderNo;
    private String address;

    public Order(String orderNo, String address) {
        this.orderNo = orderNo;
        this.address = address;
    }
}
<bean id="order" class="com.sff.demo.bean.Order">
    <constructor-arg name="orderNo" value="JD009876"/>
    <constructor-arg name="address" value="beijing"/>
</bean>

set方法有参构造器 是属性注入的常用方式,利用这两种方式可以完成一些特殊属性的注入。

  • 特殊字符和NULL值注入
public class Company implements Serializable {
    private String id;
    private String name;

    public void setId(String id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }
}
<bean id="company" class="com.sff.demo.bean.Company">
    <!-- 给属性注入 null 值 -->
    <property name="id"> <null/> </property>
   
   <!-- 给属性注入特殊符号,比如注入:<航空科技有限公司>
         1.使用 <![CDATA[]]> 2.使用转义符: &lt; &gt; -->
    <property name="name">
        <value> <![CDATA[<航空科技有限公司>]]>   </value>
    </property>
</bean>
  • 外部Bean对象的注入
public class Bus implements Serializable {
    private String busNo;
    private Company company;

    public void setBusNo(String busNo) {
        this.busNo = busNo;
    }

    public void setCompany(Company company) {
        this.company = company;
    }
}
<bean name="busCompany" class="com.sff.demo.bean.Company">
    <property name="name" value="北京公交公司"/>
</bean>
<bean name="bus" class="com.sff.demo.bean.Bus">
    <property name="company" ref="busCompany"/>
    <property name="busNo" value="空56路"/>
</bean>
  • 数组、集合属性注入 主要是通过 <array> 、<list>、<set> 和 <map> 标签来完成
@Getter
@Setter
public class Collection implements Serializable {
    private String[] arrays;
    private List<String> lists;
    private Set<String> sets;
    private Map<String, String> maps;
}
<bean id="collection" class="com.sff.demo.bean.Collection">
    <!--数组属性注入-->
    <property name="arrays">
        <array>
            <value>aaa</value>
            <value>bbb</value>
        </array>
    </property>

    <!--list集合属性注入-->
    <property name="lists">
        <list>
            <value>大哥</value>
            <value>二哥</value>
        </list>
    </property>

    <!--set集合属性注入-->
    <property name="sets">
        <set>
            <value>15号线</value>
            <value>5号线</value>
        </set>
    </property>

    <!--map集合注入-->
    <property name="maps">
        <map>
            <entry key="name" value="大飞"/>
            <entry key="age" value="18"/>
        </map>
    </property>
</bean>

集合元素的注入除了使用 <array> 、<list>、<set> 和 <map> 标签,还可以使用 <utils:list/>、<utils:set/>、<utils:map/> 标签,使用该标签时要引入对应的命名空间

xmlns:utils="http://www.springframework.org/schema/util"
  • 工厂方式注入 工厂方式注入属性时,我们可以利用工厂方法注入,也可以利用 Spring 的 FactoryBean ,它 Spring 提供的一个工厂类接口,通过实现该接口可以定制一些 Bean 实例化时的特殊逻辑。

定义一个Bean对象:

@Getter
@Setter
public class Car implements Serializable {
   private String carName;
}

FactoryBean 方式:

public class CarBeanFactory implements FactoryBean<Car> {
   @Override
   public Car getObject() throws Exception {
      Car car = new Car();
      car.setCarName("奔驰");
      return car;
   }

   @Override
   public Class<?> getObjectType() {
      return Car.class;
   }
}
<bean name="car" class="com.sff.demo.bean.CarBeanFactory"></bean>

工厂方法方式:

// 简单工厂
public class CarFactory {

   public Car getCar() {
      Car car = new Car();
      car.setCarName("宝马");
      return car;
   }
}
<!--工厂方法注入-->
<bean id="carFactory" class="com.sff.demo.bean.CarFactory"/>
<bean id="bwmCar" factory-bean="carFactory" factory-method="getCar"/>
  • xml 中引入外部属性文件来实现 Bean 属性注入
<context:property-placeholder location="classpath:jdbc.propertiest">
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
      <property name="username" value="${prop.username}"/>
      <property name="password" value="${prop.password}"/>
</bean>

2.  基于注解的方式

基于注解的方式来管理 Bean 时,不管使用那种注解,首先要扫描到该注解所在的类的包路径,这里要使用到 <context:component-scan> 标签

<!-- 如果扫描多个包,多个包使用逗号隔开 -->
<context:component-scan base-package="com.sff.demo.ano"></context:component-scan>
<context:component-scan base-package="com.sff.demo.ano" use-default-filters="false">
   <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

表示只扫描 com.sff.demo.ano 包下带有 @Controller 注解的类。

<context:component-scan base-package="com.sff.demo.ano" use-default-filters="false">
   <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/>
</context:component-scan>

表示只要 com.sff.demo.ano 包下带有 @Component 注解的类都不会被扫描到。

  • IOC 注解
@Component
@Controller
@Service
@Repository
  • 依赖注入注解
@Autowired
@Resource
@Qualifier
@Value

@Autowired 注解:
默认按类型装配(byType),如果想实现按名称装配(byName),需要结合 @Qualifiler 注解使用(@Qualifiler根据属性名称进行注入),该注解是Spring自带的注解。(@Qualifier 注解还可以给方法参数注入)

@Resource注解:
默认按名称装配(byName),可以通过 @Resource 的 name 属性指定名称,如果没有指定name属性,则按照字段的名称查找,找不到与字段名称匹配的bean时才会按照类型(byType)进行装配。但是如果name属性一旦指定,就只能安装name属性值装配。@Resource 主键属于 J2EE JSR250 规范中的注解,不是 Spring 自带的注解哦。

@Value注解:
该注解只针对普通数据类型(比如:String、Integer 等)注入,而@Autowired @Resource @Qualifier 只针实体 Bean 对象注入。