Spring学习笔记 | 详解Bean的配置及其细节

IOC和DI概述

IOC其思想是反转资源获取的方向,传统的资源查找方式要求组件向容器发起请求查找资源。作为回应,容器适时的返回资源,而应用了IOC之后,则是容器主动地将资源推送给它所管理的组件,组件所要做的仅是选择一种合适的方式来接受资源,这种行为也被称为查找的被动形式。

DI是IOC的另一种表述方式,即组件以一些预先定义好的方式(例如setter())接受来自容器的资源注入,相对于IOC而言,这种表述更直接。


配置Bean

在ApplicationContext.xml中配置bean

<?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">
    <!-- 配置bean-->
    <bean id="helloWorld" class="com.spring.helloworld.HelloWorld">
        <!-- name为属性名-->
        <property name="name" value="Spring"></property>
    </bean>
</beans>

class:bean的全类名,通过反射的方式在IOC容器中创建bean,所以要求bean中必须有无参数的构造器。
id:标识容器中的bean,id唯一。


Spring容器

在SpringIOC容器读取bean配置创建bean实例之前,必须对它进行实例化,只有在容器实例化后,才可以从IOC容器里获取bean实例并使用。

Spring提供了两种类型的IOC容器实现

  • BeanFactory:IOC容器的基本实现
  • ApplicationContext:提供了更多的高级特性,是BeanFactory的子接口。
    ClassPathXmlApplicationContextApplicationContext的一个实现类,其作用是从类路径下加载配置文件。

BeanFactory是Spring框架的基础实施,面向Spring本身;ApplicationContext面向使用Spring框架的开发者,几乎所有的应用场合都直接使用ApplicationContext而非底层的BeanFactory。但是无论使用何种方式,其配置文件都是相同的。


依赖注入

Spring支持3种依赖注入的方式

  • 属性注入
  • 构造器注入
  • 工厂方法注入(很少使用)

属性注入

属性注入即通过setter()注入Bean的属性值或依赖的对象

属性注入使用<property>元素,使用name属性指定Bean的属性名称,value属性或<value>子节点指定属性值。属性注入是实际应用中最常用的注入方式

<bean id="helloWorld" class="com.spring.helloworld.HelloWorld">
        <!-- name为属性名-->
        <property name="name" value="Spring"></property>
</bean>

构造方法注入

通过构造方法注入Bean的属性值或依赖的对象,它保证了Bean实例在实例化后就可以使用。
构造器注入在<constructor-arg>元素里声明属性,<constructor-arg>中没有name属性

首先要有相应的构造器:

package com.spring.helloworld;

public class Car {
    private String brand;
    private String corp;
    private int price;
    private int maxSpeed;

    public Car(String brand, String corp, int price) {
        this.brand = brand;
        this.corp = corp;
        this.price = price;
    }

    @Override
    public String toString() {
        return "Car{" +
                "brand='" + brand + '\'' +
                ", corp='" + corp + '\'' +
                ", price=" + price +
                ", maxSpeed=" + maxSpeed +
                '}';
    }
}

在ApplicationContext.xml文件中的构造方法注入:

<!-- 通过构造器注入属性值可以指定参数的位置和参数的类型,以区分重载的构造器 -->
    <bean id="car2" class="com.spring.helloworld.Car">
        <constructor-arg value="Audi" type="java.lang.String"></constructor-arg>
        <constructor-arg value="Shanghai" type="java.lang.String"></constructor-arg>
        <constructor-arg value="300000" type="int"></constructor-arg>
    </bean>

Spring属性配置细节

字面值

可用字符串表示的值,可用通过<value>元素标签或value属性进行注入。

基本数据类型及其封装类、String等类型都可以采取字面值注入的方式。若字面值中包含特殊字符,可用使用<![CDATA[]]>把字面值包裹起来。

<bean id="car" class="com.spring.helloworld.Car">
        <constructor-arg value="Audi" type="java.lang.String"></constructor-arg>
        <constructor-arg value="Shanghai" type="java.lang.String"></constructor-arg>
        <constructor-arg value="300000" type="int"></constructor-arg>
    </bean>

引用其它Bean

组成应用程序的Bean经常需要相互协作以完成引用程序的功能,要使Bean能够相互访问,就必须在Bean配置文件中指定对Bean的引用。

在Bean的配置文件中,可以通过<ref>元素或ref属性来为Bean的属性或构造器参数指定对Bean的引用。

也可以在属性或构造器里包含Bean的声明,这样的Bean称为内部Bean

我们先建立一个Person类,如下:

package com.spring.helloworld;

public class Person {
    private String name;
    private int age;
    private Car car;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", car=" + car +
                '}';
    }
}

在ApplicationContxt.xml文件中配置如下:

<bean id="person" class="com.spring.helloworld.Person">
        <property name="name" value="Tom"></property>
        <property name="age" value="24"></property>
        <!-- 使用ref来建立bean之间的引用关系-->
        <property name="car" ref="car2"></property>
    </bean>

测试类:

package com.spring.helloworld;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) { 
        Person person = (Person) context.getBean("person");
        System.out.println(person);
    }
}

内部Bean

当Bean实例仅仅给一个特定的属性使用时,可以将其声明为内部Bean,内部Bean声明直接包含在<property><constructor-arg>元素里,不需要设置任何idname属性。

内部Bean不能使用在任何其他地方。

内部类的一个注入实例:

<bean id="person" class="com.spring.helloworld.Person">
        <property name="name" value="Tom"></property>
        <property name="age" value="24"></property>
        <!-- 内部bean-->
        <property name="car">
            <bean id="car3" class="com.spring.helloworld.Car">
                <!-- 下面是使用构造方法注入,也可以使用属性注入的方式 -->
                <constructor-arg value="Audi" type="java.lang.String"></constructor-arg>
                <constructor-arg value="Shanghai" type="java.lang.String"></constructor-arg>
                <constructor-arg value="300000111" type="int"></constructor-arg>
            </bean>
        </property>
</bean>

注入参数详解:null值和级联属性

可以使用专用的<null/>元素标签为Bean的字符串或其他对象类型的属性注入null值。

和Struts、Hibernate等框架一样,Spring支持级联属性的配置。

<?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">
    <!-- 通过构造器注入属性值可以指定参数的位置和参数的类型,以区分重载的构造器 -->
    <bean id="car2" class="com.spring.helloworld.Car">
        <constructor-arg value="Audi" type="java.lang.String"></constructor-arg>
        <constructor-arg value="Shanghai" type="java.lang.String"></constructor-arg>
        <constructor-arg value="300000" type="int"></constructor-arg>
    </bean>

    <bean id="person" class="com.spring.helloworld.Person">
        <property name="name" value="Tom"></property>
        <property name="age" value="24"></property>
        <!-- 使用ref来建立bean之间的引用关系-->
        <property name="car" ref="car2"></property>
        <!-- 为级联属性赋值. 注意:属性需要先初始化后才可以为级联属性赋值,否则会有异常 -->
        <property name="car.maxSpeed" value="25000"></property>
    </bean>
</beans>

集合属性

在Spring中可以通过一组内置的xml标签(例如:<list>,<set>,<map>)来配置集合属性。

配置java.util.List类型的属性,需要指定<list>标签,在标签里包含一些元素,这些标签可以通过<value>指定简单的常量值,通过<ref>指定对其他Bean的引用,通过<bean>指定内置Bean定义,通过<null/>指定空元素,甚至可以内嵌其他集合。

数组的定义和List一样,都使用<list>
配置java.util.set需要使用<set>标签,定义元素的方法与List一样。

示例:配置一个java.util.List类型的属性。

  • 我们在com.spring.collection包中新建一个Person类:
package com.spring.collection;

import java.util.List;

public class Person {
    private String name;
    private int age;
    private List<Car> car;

    public List < Car > getCar() {
        return car;
    }

    public void setCar(List < Car > car) {
        this.car = car;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }


    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", car=" + car +
                '}';
    }
}
  • 然后在com.spring.collection中新建一个Car类:
package com.spring.collection;

public class Car {
    private String brand;
    private String corp;
    private int price;
    private int maxSpeed;

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public void setCorp(String corp) {
        this.corp = corp;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public void setMaxSpeed(int maxSpeed) {
        this.maxSpeed = maxSpeed;
    }

    public Car(String brand, String corp, int price) {
        this.brand = brand;
        this.corp = corp;
        this.price = price;
    }

    @Override
    public String toString() {
        return "Car{" +
                "brand='" + brand + '\'' +
                ", corp='" + corp + '\'' +
                ", price=" + price +
                ", maxSpeed=" + maxSpeed +
                '}';
    }
}
  • 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">
   <bean id="car4" class="com.spring.collection.Car">
        <constructor-arg value="Audi1" type="java.lang.String"></constructor-arg>
        <constructor-arg value="Shanghai" type="java.lang.String"></constructor-arg>
        <constructor-arg value="222" type="int"></constructor-arg>
    </bean>
    <bean id="car3" class="com.spring.collection.Car">
        <constructor-arg value="Audi2" type="java.lang.String"></constructor-arg>
        <constructor-arg value="Shanghai" type="java.lang.String"></constructor-arg>
        <constructor-arg value="111" type="int"></constructor-arg>
    </bean>

    <!-- 测试如何配置集合属性-->
    <bean id="person2" class="com.spring.collection.Person">
        <property name="age" value="27"></property>
        <property name="name" value="Cerr"></property>
        <property name="car" >
            <!-- 使用list节点为list类型的属性赋值-->
            <list>
                <ref bean="car4" />
                <ref bean="car3" />
            </list>
        </property>
    </bean>
</beans>
  • 主函数如下:
package com.spring.collection;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        Person person = (Person) ctx.getBean("person2");
        System.out.println(person);
    }
}

使用<map>节点来配置,applicationContext.xml文件部分代码:

<!--配置Map属性值-->
    <bean id="newPerson" class="com.spring.collection.NewPerson">
        <property name="name" value="Rose"></property>
        <property name="age" value="11"></property>
        <property name="cars">
            <map>
                <entry key="AA" value-ref="car3"/>
                <entry key="BB" value-ref="car4"/>
            </map>
        </property>
    </bean>

使用<props><prop>节点来为properties属性赋值,applicationContext.xml文件部分代码如下:

<!-- 配置properties属性值-->
    <bean id="dataSource" class="com.spring.collection.DataSource">
        <property name="properties">
            <props>
                <prop key="user">root</prop>
                <prop key="password">123</prop>
            </props>
        </property>
    </bean>

dataSource类代码如下:

package com.spring.collection;

import java.util.Properties;

public class DataSource {
    private Properties properties;

    public Properties getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    @Override
    public String toString() {
        return "DataSource{" +
                "properties=" + properties +
                '}';
    }
}

使用utility scheme定义集合

为了共享集合定义的Bean的引用,可以用util schema的集合标签定义独立的集合Bean。
applicationContext.xml文件:

<!-- 配置单例的集合Bean,以供多个bean进行引用 -->
    <util:list id="cars1">
        <ref bean="car3"/>
        <ref bean="car4"/>
    </util:list>

    <bean id="person4" class="com.spring.collection.Person">
        <property name="name" value="Jack"></property>
        <property name="age" value="20"></property>
        <property name="car" ref="cars1"></property>
    </bean>

使用p命名空间

为了简化xml文件的配置,越来越多的xml文件采用属性而非子元素配置信息。

使用了p命名空间后,可以通过<bean>元素属性的方式来配置Bean的属性。
例如:

<!-- 通过p命名空间为bean属性赋值,需要先导入p命名空间-->
    <bean id="person5" class="com.spring.collection.Person" p:age="30" p:name="Queen" p:car-ref="cars1"></bean>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值