Spring4-2 Bean配置

  配置形式:基于XML文件的形式、基于注解的形式;
  配置方式:通过全类名(反射)、工厂方法(静态工厂方法或实例工厂方法)或FactoryBean的方式进行配置。


1. IoC容器

  在Spring IoC容器读取Bean配置来创建Bean实例前,必须对其进行实例化;只有在IoC容器实例化后,可以从中获取Bean实例并使用。
  Spring提供了BeanFactory和ApplicationContext两种类型的IOC容器实现;其中, BeanFactory接口是IoC容器的基本实现,面向Spring框架本身;而ApplicationContext是BeanFactory的子接口,提供了更多的高级特性,面向Spring框架的开发者,故常使用ApplicationContext来代表IoC容器。
  Spring的IoC容器使用示例如下:

/**
 * 基于Spring框架实现
 * ApplicationContext接口代表IoC容器:在初始化上下文时即实例化所有单例的Bean
 *   -- ClassPathXmlApplicationContext:实现类,其从类路径下加载配置文件;
 *   -- FileSystemXmlApplicationContext:实现类,其从文件系统中加载配置文件;
 *   -- ConfigurableApplicationContext:子接口,增加refresh()和close()方法,使ApplicationContext具有启动、刷新和关闭上下文的能力。
 */
// 1. 创建Spring的IoC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("helloBean.xml");

// 2. 从IoC容器中获取Bean:getBean(String idStr)方法
HelloWorld helloWorld = (HelloWorld) ctx.getBean("qiaobc");

2. 依赖注入的方式

  Spring支持属性注入、构造器注入和工厂方法注入(不推荐)共三种依赖注入的方式。

  2.1 属性注入

<!--
    配置bean
    id:唯一标识容器中的bean;可指定多个名字,中间用逗号隔开;
    class:bean的全类名,采用反射的方式在IoC容器中创建Bean,即要求Bean必须有无参的构造器;
 -->
<bean id="qiaobc" class="com.qiaobc.spring.beans.HelloWorld">
    <!-- 属性注入:通过setter方法注入Bean的属性值或依赖的对象 -->
    <property name="name" value="Android"></property>
</bean>

  2.2 构造器注入

<!-- 通过构造方法来配置Bean的属性:可以指定参数的位置和类型,以区分重载的构造器 -->
<!-- 1). 按索引匹配入参:可用index实现位置区分 -->
<bean id="car" class="com.qiaobc.spring.beans.Car">
    <!-- public Car(String brand, String corp, double price){} -->
    <constructor-arg value="BMW"></constructor-arg>
    <constructor-arg value="WuHan"></constructor-arg>
    <constructor-arg value="600000"></constructor-arg>
</bean>

<!-- 2). 按类型匹配入参 -->
<bean id="car2" class="com.qiaobc.spring.beans.Car">
    <!-- public Car(String brand, String corp, int maxSpeed){} -->
    <constructor-arg value="BMW2" type="java.lang.String"></constructor-arg>
    <constructor-arg type="java.lang.String">
        <!-- 字面值(可以用字符串表示的值)可以通过value属性或value子元素进行注入 -->
        <!-- 若字面值包含特殊字符,可以使用 <![CDATA[]]>把字面值包裹起来 -->
        <value><![CDATA[>WuHan]]></value>
    </constructor-arg>
    <constructor-arg value="240.00" type="int"></constructor-arg>
</bean>

3. 详解属性注入

3.1 引用其他的Bean

  组成应用程序的Bean经常需要相互协作以完成应用程序的功能,在Bean配置文件中通过<ref>元素或ref 属性指定对Bean的引用即可实现互相访问。
  
bean配置文件核心代码如下所示:

<!-- 引用其他的bean -->
<bean id="person" class="com.qiaobc.spring.beans.Person">
    <property name="name" value="qiaobc"></property>
    <property name="age" value="23"></property>
    <!-- 可以使用property的ref属性建立bean之间的引用关系 -->
    <property name="car" ref="car2"></property>
    <!-- 为级联属性赋值:属性需要先初始化后才可以为级联属性赋值,与Struts不同 -->
    <property name="car.maxSpeed" value="250"></property>
</bean>
3.2 内部Bean

bean配置文件核心代码如下所示:

<!-- 内部bean:只能在内部使用,而不能被外部引用 -->
<bean id="person1" class="com.qiaobc.spring.beans.Person">
    <property name="name" value="qiaobc"></property>
    <property name="age" value="23"></property>
    <property name="car">
        <bean class="com.qiaobc.spring.beans.Car">
            <constructor-arg value="BMW"></constructor-arg>
            <!-- 配置null值: <null/> -->
            <constructor-arg><null/></constructor-arg>
            <constructor-arg value="260" type="int"></constructor-arg>
        </bean>
    </property>
</bean>
3.3 集合属性

bean配置文件核心代码如下所示:

<!-- 1). 配置List属性:Person类中声明private List<Car> cars; -->
<bean id="person2" class="com.qiaobc.spring.beans.collections.Person">
    <property name="name" value="qiaobei"></property>
    <property name="age" value="23"></property>
    <property name="cars">
        <!-- 使用list节点为List类型的属性赋值 -->
        <list>
            <ref bean="car" />
            <ref bean="car2" />
            <ref bean="car3" />
        </list>
    </property>
</bean>

<!-- 2). 配置Set属性需要使用set节点类配置,而数组元素仍采用list节点来配置 -->

<!-- 3). 配置Map属性:Person类中声明private Map<String, Car> carsMap; -->
<bean id="person3" class="com.qiaobc.spring.beans.collections.Person">
    <property name="name" value="chenchen"></property>
    <property name="age" value="23"></property>
    <property name="carsMap">
        <!-- 使用Map节点和entry子节点为Map类型的属性赋值 -->
        <map>
            <entry key="AA" value-ref="car"></entry>
            <entry key="BB" value-ref="car2"></entry>
            <entry key="CC" value-ref="car3"></entry>
        </map>
    </property>
</bean>

<!-- 4). 配置Properties属性:Person类中声明private Properties properties; -->
<bean id="person4" class="com.qiaobc.spring.beans.collections.Person">
    <property name="properties">
        <!-- 使用props和prop节点为Properties属性赋值 -->
        <props>
            <prop key="name">root</prop>
            <prop key="password">1234</prop>
        </props>
    </property>
</bean>

<!-- 5). 使用util schema里集合标签定义独立的集合Bean,以供其他Bean引用 -->
<util:map id="carsMap">
    <entry key="AAA" value-ref="car"></entry>
    <entry key="BBB" value-ref="car2"></entry>
    <entry key="CCC" value-ref="car3"></entry>
</util:map>

<!-- 6). 简化配置:使用p命名空间为bean的属性赋值,需要先导入p命名空间 -->
<bean id="person5" class="com.qiaobc.spring.beans.collections.Person"
    p:name="chengege" p:age="25" p:carsMap-ref="carsMap"></bean>

4. 自动装配

这里写图片描述

bean配置文件核心代码如下所示:

<bean id="address" class="com.qiaobc.spring.beans.autowire.Address"
    p:city="Wuhan" p:street="Luoshi"></bean>

<bean id="car" class="com.qiaobc.spring.beans.autowire.Car"
    p:brand="BMW" p:price="600000"></bean>

<!-- 手动装配 -->
<bean id="person" class="com.qiaobc.spring.beans.autowire.Person"
    p:name="qiaobc" p:address-ref="address" p:car-ref="car"></bean>

<!-- 
    自动装配:使用autowire属性指定自动装配的方式
    byName 根据当前bean的属性名称和目标bean的名称进行自动装配;需要精确匹配
    byType 根据当前bean的属性类型和目标bean的类型进行自动装配;若IoC容器中有多个相同类型的bean则抛出异常
 -->
<bean id="person2" class="com.qiaobc.spring.beans.autowire.Person"
    p:name="qiaobc" autowire="byType"></bean>

5. bean之间的关系

这里写图片描述

bean配置文件核心代码如下所示:

<!-- 抽象bean:其abstract属性为true,抽象bean不能被IoC容器实例化 -->
<!-- 若某个bean的class属性未指定,则其必须是抽象bean -->
<bean id="address1" p:city="Wuhan" p:street="Luoshi" abstract="true"></bean>

<!-- bean之间的继承关系:使用bean的parent来实现 -->
<bean id="address2" class="com.qiaobc.spring.beans.autowire.Address"
    parent="address1" p:street="Wuluo"></bean>

<bean id="car" class="com.qiaobc.spring.beans.autowire.Car"
    p:brand="bmw" p:price="600000"></bean>

<!-- bean之间的依赖关系:要求在配置Person时,必须有一个关联的Car,即依赖于Car -->
<bean id="person" class="com.qiaobc.spring.beans.autowire.Person"
    p:name="qiaobei" p:address-ref="address2" depends-on="car"></bean>

6. bean的作用域

这里写图片描述

bean配置文件核心代码如下所示:

<!-- 
    bean的作用域:使用bean的scope属性来配置bean的作用域,默认值为singleton
    singleton:默认值,IoC容器初始化时即创建bean实例,仅创建一次,即单例的;
    prototype:原型的,IoC容器初始化时不创建bean实例,而在每次请求时均创建新的bean实例返回;
 -->
<bean id="car" class="com.qiaobc.spring.beans.scope.Car" scope="singleton">
    <property name="brand" value="BMW"></property>
    <property name="price" value="600000"></property>
</bean>

7. 使用外部属性文件

这里写图片描述

src/db.properties文件内容如下所示:

user=root
password=root
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql:///hibernate

bean配置文件核心代码如下所示:

<!-- 在属性文件中配置c3p0数据源,推荐使用 -->
    <!-- 在Spring2.5以后使用context:property-placeholder元素导入属性文件,并进行配置即可 -->
    <context:property-placeholder location="classpath:db.properties"/>
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="${user}"></property>
        <property name="password" value="${password}"></property>
        <property name="driverClass" value="${driverClass}"></property>
        <property name="jdbcUrl" value="${jdbcUrl}"></property>
    </bean>

    <!-- 在Bean配置文件中:配置c3p0数据源,不建议如此配置 -->
    <!-- 
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="root"></property>
        <property name="password" value="root"></property>
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql:///hibernate"></property>
    </bean> 
     -->

8. SpEL

这里写图片描述

bean配置文件核心代码如下所示:

<bean id="address" class="com.qiaobc.spring.beans.spel.Address">
    <!-- 使用SpEL为属性赋一个字面值:标准数据类型或字符串 -->
    <property name="city" value="#{'Wuhan'}"></property>
    <property name="street" value="Jiedaokou"></property>
</bean>

<bean id="car" class="com.qiaobc.spring.beans.spel.Car">
    <property name="brand" value="BMW"></property>
    <property name="price" value="500000"></property>
    <!-- 使用SpEL引用类的静态属性 -->
    <property name="tyrePerimeter" value="#{T(java.lang.Math).PI * 80}"></property>
</bean>

<bean id="person" class="com.qiaobc.spring.beans.spel.Person">
    <property name="name" value="qiaobc"></property>
    <!-- 使用SpEL来引用其他bean -->
    <property name="car" value="#{car}"></property>
    <!-- 使用SpEL来引用其他bean的属性 -->
    <property name="city" value="#{address.city}"></property>
    <!-- 在SpEL中使用运算符 -->
    <property name="info" value="#{car.price > 300000 ? '金领' : '白领'}"></property>
</bean>

9. IoC容器中bean的生命周期

这里写图片描述

bean配置文件核心代码如下所示:

<bean id="car" class="com.qiaobc.spring.beans.cycle.Car"
    init-method="init" destroy-method="destory">
    <property name="brind" value="BMW"></property>
</bean>

<!-- 
    需要实现BeanPostProcessor接口,并实现其中的方法:
    postProcessBeforeInitialization(Object bean, String beanName):在init-method之前被调用
    postProcessAfterInitialization(Object bean, String beanName):在init-method之后被调用
 -->
<!-- 配置bean的后置处理器:不需要配置id,IoC容器自动识别是一个BeanPostProcessor -->
<bean class="com.qiaobc.spring.beans.cycle.MyBeanPostProcessor"></bean>

自定义BeanPostProcessor的实现类如下:

package com.qiaobc.spring.beans.cycle;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        if("car".equals(beanName)) {
            System.out.println("postProcessAfterInitialization:" + beanName);
        }
        return bean;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
        System.out.println("postProcessBeforeInitialization:" + beanName);
        return bean;
    }
}

10. 通过工厂方法配置Bean

这里写图片描述

bean配置文件核心代码如下所示:

<!-- 
通过静态工厂方法来配置bean:注意不是配置静态工厂方法实例 
    class属性:指向静态工厂方法所属类的全类型 
    factory-method属性:指向静态工厂方法的名称 
    constructor-arg标签:若静态工厂方法需要传入参数,则使用该元素为其配置参数
 -->
<bean id="car1" class="com.qiaobc.spring.beans.factory.StaticCarFactory"
    factory-method="getCar">
    <constructor-arg value="bmw"></constructor-arg>
</bean>

<!-- 配置实例工厂方法所属类的实例 -->
<bean id="instanceCarFactory" class="com.qiaobc.spring.beans.factory.InstanceCarFactory"></bean>

<!-- 通过实例工厂方法来配置bean -->
<bean id="car2" factory-bean="instanceCarFactory" factory-method="getCar">
    <constructor-arg value="audi"></constructor-arg>
</bean>

自定义静态工厂StaticCarFactory如下:

package com.qiaobc.spring.beans.factory;

import java.util.HashMap;
import java.util.Map;

/**
 * 静态工厂方法:直接调用某一个类的静态方法就可以返回Bean的实例
 */
public class StaticCarFactory {

    private static Map<String, Car> cars = new HashMap<String, Car>();

    static{
        cars.put("bmw", new Car("bmw", 600000));
        cars.put("audi", new Car("audi", 400000));
    }

    public static Car getCar(String name) {
        return cars.get(name);
    }

}

自定义实例工厂InstanceCarFactory如下:

package com.qiaobc.spring.beans.factory;

import java.util.HashMap;
import java.util.Map;

/**
 * 实例工厂方法:需要先创建工厂本身,再调用工厂的实例方法来返回bean的实例
 */
public class InstanceCarFactory {

    private Map<String, Car> cars = null;

    public InstanceCarFactory() {
        cars = new HashMap<String, Car>();
        cars.put("bmw", new Car("bmw", 600000));
        cars.put("audi", new Car("audi", 400000));
    }

    public Car getCar(String brand) {
        return cars.get(brand);
    }

}

11. 通过FactoryBean配置Bean

这里写图片描述

bean配置文件核心代码如下所示:

<!-- 
    通过FactoryBean来配置Bean的实例
    class属性:指向FactoryBean的全类名;
    property:配置FactoryBean的属性;
    注意:实例返回的实例是FactoryBean的getObject()方法所返回的实例
 -->
<bean id="car" class="com.qiaobc.spring.beans.factoryBean.CarFactoryBean"></bean>

自定义FactoryBean的实现类如下:

package com.qiaobc.spring.beans.factoryBean;

import org.springframework.beans.factory.FactoryBean;

/**
 * 自定义的FactoryBean需要实现FactoryBean接口
 */
public class CarFactoryBean implements FactoryBean<Car> {

    // 返回bean的对象
    @Override
    public Car getObject() throws Exception {
        return new Car("bmw", 600000);
    }

    // 返回bean的类型
    @Override
    public Class<?> getObjectType() {
        return Car.class;
    }

    // 是否为单实例的
    @Override
    public boolean isSingleton() {
        return true;
    }

}

12. 配置形式之基于注解的方式

12.1 基于注解配置Bean

这里写图片描述
  其中,context:include-filter和context:exclude-filter子节点支持多种类型的过滤表达式,如下图所示:
这里写图片描述

12.2 基于注解装配Bean的属性

这里写图片描述

bean配置文件核心代码如下所示:

<!-- 
    指定Spring IoC容器扫描的包 
    resource-pattern属性:指定扫描的资源,如repository/*.java
    context:include-filter子节点:指定包含哪些指定表达式的组件,该子节点需要use-default-filters配合使用
-->
<context:component-scan 
    base-package="com.qiaobc.spring.beans.annotation" use-default-filters="true">

    <!-- context:include-filter子节点:指定包含哪些指定表达式的组件,该子节点需要use-default-filters配合使用 -->
    <!-- 
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
     -->

    <!-- context:exclude-filter子节点:指定排除哪些指定表达式的组件 -->
    <!-- 
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
     -->

    <!-- 
    <context:exclude-filter type="assignable" expression="com.qiaobc.spring.beans.annotation.repository.UserRepository"/>
     -->

    <!-- 
    <context:include-filter type="assignable" expression="com.qiaobc.spring.beans.annotation.repository.UserRepository"/>
     -->

</context:component-scan>
<!-- 可能会抛出java.lang.NoClassDefFoundError: org/springframework/aop/TargetSource异常,加入spring-aop-4.0.0.RELEASE.jar即可 -->

13. 泛型依赖注入

Spring4.x中可以为子类注入子类对应的泛型类型的成员变量的引用,示意图如下:

这里写图片描述


14. 整合多个配置文件

  Spring允许通过import将多个配置文件引入到一个文件中,进行配置文件的集成;在启动Spring容器时,仅需要指定合并好的配置文件即可;其中,import元素的resource属性支持Spring的标准路径资源。
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值