4.Spring系列之Bean的配置1

一、配置Bean的两种方式之使用XML配置Bean


1.基于XML配置Bean-属性注入

创建一个Bean,该Bean提供了有参构造器

public class Person {

    private String name;public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Person [name=" + name + "]";
    }

}

在IOC容器内配置属性注入:

<?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">

    <!-- 
        class:bean的全类名,通过反射创建该bean的实例,要求Bean中必须有无参构造器,否则会报:No default constructor found
        id:IOC容器对象引用该bean的标志,例如:ctx.getBean(hello);返回的就是一个Hello对象,即标识容器中的bean,并且id唯一
        注意:若没有定义id,那么自动使用类名首字母小写为id名称
    -->
    <bean id="person" class="com.spring.model.Person">
     <!-- 注意:这里的name必须和Bean属性的setXXX方法中的XXX同名,否则属性无法赋值 --> <property name="name" value="loose"></property> </bean> </beans>

测试属性注入:

public class Main {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        Person person = (Person) ctx.getBean("person");
        System.out.println(person);
        System.out.println(person.getName());
        /**
         * 运行后输出:
         * Person [name=loose]
         * loose
         */
    }
}

说明:

属性注入即通过 setter 方法注入Bean 的属性值或依赖的对象
属性注入使用 <property> 元素, 使用 name 属性指定 Bean 的属性名称,value 属性或 <value> 子节点指定属性值
属性注入是实际应用中最常用的注入方式

2.构造器注入,使用构造器初始化不必提供get和set方法

通过构造方法注入Bean 的属性值或依赖的对象,它保证了 Bean 实例在实例化后就可以使用,构造器注入在 <constructor-arg> 元素里声明属性, <constructor-arg> 中没有 name 属性
以上方的Bean类为例,去掉属性的set和get方法,同时创建一个Bean的带参构造器:
public class Person {

    private String name;
    private int age;

    public Person() {
        super();
    }

    public Person(String name,int age) {
        super();
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }

}

在IOC容器内配置构造器注入:

<?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="person" class="com.spring.model.Person">
        <constructor-arg value="loose" index="0"></constructor-arg>
        <constructor-arg value="20" index="1"></constructor-arg>
    </bean>
</beans>

测试构造器注入:

public class Main {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        Person person = (Person) ctx.getBean("person");
        System.out.println(person);
        /**
         * 运行后输出:
         * Person [name=loose, age=20]
         */
    }
}

同时,我们也可以指定构造器参数类型的匹配入参:

<?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="person" class="com.spring.model.Person">
        <constructor-arg value="loose" type="java.lang.String"></constructor-arg>
        <constructor-arg value="20" type="int"></constructor-arg>
    </bean>
</beans>

3.工厂方法注入这里就省略,用的很少,有兴趣的自己去找下资料

4.属性注入的细节

①.字面值

字面值:可用字符串表示的值,可以通过<value>元素标签或value属性进行注入
<bean id="person" class="com.spring.model.Person">
    <property name="name">
        <value>spring</value>
    </property>
</bean>

说明:基本数据类型和封装类、String等类型都可以采用字面值注入的方式。

②.若字面值包含特殊符号,可以使用<![CDATA[]]>把字面值包裹起来

<bean id="person" class="com.spring.model.Person">
   <property name="name">
        <value><![CDATA[<spring]]></value>
   </property>
</bean>

这里获取到属性值后,输出的是<string,包含了特殊符号<

③.引用其它的Bean

组成应用程序的 Bean 经常需要相互协作以完成应用程序的功能. 要使 Bean 能够相互访问, 就必须在 Bean 配置文件中指定对 Bean 的引用;在 Bean 的配置文件中, 可以通过 <ref> 元素或 ref  属性为 Bean 的属性或构造器参数指定对 Bean 的引用:
在这里我们首先创建两个Bean,一个是Person代表人,一个是Mobile代表手机:
public class Person {

    private String name;
    private int age;

    private Mobile mobile;

    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 Mobile getMobile() {
        return mobile;
    }

    public void setMobile(Mobile mobile) {
        this.mobile = mobile;
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", mobile=" + mobile + "]";
    }

}
public class Mobile {

    private String brand;
    private double price;

    public String getBrand() {
        return brand;
    }

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

    public double getPrice() {
        return price;
    }

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

    @Override
    public String toString() {
        return "Mobile [brand=" + brand + ", price=" + price + "]";
    }

}

在IOC容器中配置这两个Bean,并使Person引用Mobile:

<?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="mobile" class="com.spring.model.Mobile">
        <property name="brand" value="iphone"></property>
        <property name="price" value="5000"></property>
    </bean>

    <bean id="person" class="com.spring.model.Person">
        <property name="name" value="loose"></property>
        <property name="age" value="20"></property>
//这里ref中的mobile为上方配置的Mobile这个Bean的id <property name="mobile" ref="mobile"></property> </bean> </beans>

测试引用其它的Bean:

public class Main {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        Person person = (Person) ctx.getBean("person");
        System.out.println(person);
        // 执行后输出:Person [name=loose, age=20, mobile=Mobile [brand=iphone, price=5000.0]]
    }
}

IOC容器中也可以这么配置:

<?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="mobile" class="com.spring.model.Mobile">
        <property name="brand" value="iphone"></property>
        <property name="price" value="5000"></property>
    </bean>

    <bean id="person" class="com.spring.model.Person">
        <property name="name" value="loose"></property>
        <property name="age" value="20"></property>
        <property name="mobile">
            <ref bean="mobile"/> //使用ref标签引用Bean
        </property>
    </bean>
</beans>

也可以在属性或构造器里包含 Bean 的声明, 这样的 Bean 称为内部 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进行引用 -->
    <!-- <bean id="mobile" class="com.spring.model.Mobile">
        <property name="brand" value="iphone"></property>
        <property name="price" value="5000"></property>
    </bean> -->

    <bean id="person" class="com.spring.model.Person">
        <property name="name" value="loose"></property>
        <property name="age" value="20"></property>
        <property name="mobile">
            <bean class="com.spring.model.Mobile">
                <property name="brand" value="iphone"></property>
                <property name="price" value="5000"></property>
              </bean>
        </property>
    </bean>
</beans>

注意:

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

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

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

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

<bean id="person" class="com.spring.model.Person">
   <property name="name">
     <null></null>
   </property>
  <property name="age" value="20"></property>
</bean>

同时,Spring 支持级联属性的配置,为了方便查看,这里再次给出两个Bean,分别是Person和Mobile:

public class Person {

    private String name;
    private int age;

    private Mobile mobile;

    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 Mobile getMobile() {
        return mobile;
    }

    public void setMobile(Mobile mobile) {
        this.mobile = mobile;
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", mobile=" + mobile + "]";
    }

}
public class Mobile {

    private String brand;
    private double price;

    public String getBrand() {
        return brand;
    }

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

    public double getPrice() {
        return price;
    }

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

    @Override
    public String toString() {
        return "Mobile [brand=" + brand + ", price=" + price + "]";
    }

}

在IOC容器配置级联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 id="mobile" class="com.spring.model.Mobile">
        <!-- 这里不配置mobile的属性值 -->
    </bean>

    <bean id="person" class="com.spring.model.Person">
        <property name="name" value="loose"></property>
        <property name="age" value="20"></property>
        <property name="mobile" ref="mobile"></property>
        <!-- 以级联的形式注入Bean值 -->
        <property name="mobile.brand" value="nokia"></property>
        <property name="mobile.price" value="2000"></property>
    </bean>
</beans>

测试级联程序:

public class Main {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        Person person = (Person) ctx.getBean("person");
        System.out.println(person);
        // 执行后输出:Person [name=loose, age=20, mobile=Mobile [brand=nokia, price=2000.0]]
    }
}

⑤.引用集合属性

在 Spring中可以通过一组内置的 xml 标签(例如: <list>, <set> 或 <map>) 来配置集合属性,配置 java.util.List 类型的属性, 需要指定 <list>  标签, 在标签里包含一些元素. 这些标签可以通过 <value> 指定简单的常量值, 通过 <ref> 指定对其他 Bean 的引用. 通过<bean> 指定内置 Bean 定义. 通过 <null/> 指定空元素. 甚至可以内嵌其他集合,数组的定义和 List 一样, 都使用 <list>,配置 java.util.Set 需要使用 <set> 标签, 定义元素的方法与 List 一样:

===>配置List集合属性,以上方的Person和Mobile为例,不同的是Person里面的Mobile变成了List<Mobile>,代表一个人可以多部手机:

public class Person {

    private String name;

    private List<Mobile> mobiles;

    public String getName() {
        return name;
    }

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

    public List<Mobile> getMobiles() {
        return mobiles;
    }

    public void setMobiles(List<Mobile> mobiles) {
        this.mobiles = mobiles;
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", mobiles=" + mobiles + "]";
    }

}
public class Mobile {

    private String brand;
    private double price;

    public String getBrand() {
        return brand;
    }

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

    public double getPrice() {
        return price;
    }

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

    @Override
    public String toString() {
        return "Mobile [brand=" + brand + ", price=" + price + "]";
    }

}

在IOC容器中配置两个的引用关系:

<?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">

    <!-- 这里配置多个Mobile Bean,然后被person一个个引用 -->
    <bean id="mobile1" class="com.spring.model.Mobile">
        <property name="brand" value="nokia"></property>
        <property name="price" value="2000"></property>
    </bean>
    
    <bean id="mobile2" class="com.spring.model.Mobile">
        <property name="brand" value="iphone"></property>
        <property name="price" value="5000"></property>
    </bean>

    <bean id="person" class="com.spring.model.Person">
        <property name="name" value="loose"></property>
        <property name="mobiles">
            <!-- 使用list标签 -->
            <list>
                <!-- 分别引入多个Bean -->
                <ref bean="mobile1"/>
                <ref bean="mobile2"/>
            </list>
        </property>
    </bean>
</beans>

测试Bean中引用List集合属性:

public class Main {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        Person person = (Person) ctx.getBean("person");
        System.out.println(person);
        // 执行后输出:Person [name=loose, mobiles=[Mobile [brand=nokia, price=2000.0], Mobile [brand=iphone, price=5000.0]]]
    }
}

===>配置Map集合属性,Java.util.Map 通过 <map> 标签定义, <map> 标签里可以使用多个 <entry> 作为子标签.,每个条目包含一个键和一个值

仍然是以上面的Bean威力,不同的是集合类型变更为Map,请看下方两个Bean的定义:

public class Person {

    private String name;

    private Map<String,Mobile> mobiles;

    public String getName() {
        return name;
    }

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

    public Map<String, Mobile> getMobiles() {
        return mobiles;
    }

    public void setMobiles(Map<String, Mobile> mobiles) {
        this.mobiles = mobiles;
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", mobiles=" + mobiles + "]";
    }

}
public class Mobile {

    private String brand;
    private double price;

    public String getBrand() {
        return brand;
    }

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

    public double getPrice() {
        return price;
    }

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

    @Override
    public String toString() {
        return "Mobile [brand=" + brand + ", price=" + price + "]";
    }

}

在IOC容器中配置两个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">

    <!-- 这里配置多个Mobile Bean,然后被person一个个引用 -->
    <bean id="mobile1" class="com.spring.model.Mobile">
        <property name="brand" value="nokia"></property>
        <property name="price" value="2000"></property>
    </bean>
    
    <bean id="mobile2" class="com.spring.model.Mobile">
        <property name="brand" value="iphone"></property>
        <property name="price" value="5000"></property>
    </bean>

    <bean id="person" class="com.spring.model.Person">
        <property name="name" value="loose"></property>
        <property name="mobiles">
            <!-- 使用map标签 -->
            <map>
                <entry key="nokia" value-ref="mobile1"></entry>
                <entry key="iphone" value-ref="mobile2"></entry>
            </map>
        </property>
    </bean>
</beans>

测试Bean中引用Map集合属性:

public class Main {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        Person person = (Person) ctx.getBean("person");
        System.out.println(person);
        // 执行后输出:son [name=loose, mobiles={nokia=Mobile [brand=nokia, price=2000.0], iphone=Mobile [brand=iphone, price=5000.0]}]
    }
}

===><props> 定义 java.util.Properties, 该标签使用多个 <prop> 作为子标签.,每个 <prop> 标签必须定义 key 属性:

我们新建一个Bean,用于模拟从配置文件中读取数据库连接信息:

public class DataSource {

    private Properties properties;

    public Properties getProperties() {
        return properties;
    }

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

}

将Bean交给IOC容器管理:

<?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 http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <bean id="dataSource" class="com.spring.model.DataSource">
         <property name="properties">
              <props>
                 <prop key="user">root</prop>
                 <prop key="password">1234</prop>
                 <prop key="jdbcUrl">jdbc:mysql:///test</prop>
                 <prop key="driver">com.mysql.jdbc.Driver</prop>
              </props>
       </property>
    </bean>
</beans>

测试程序:

public class Main {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        DataSource ds = (DataSource) ctx.getBean("dataSource");
        System.out.println(ds.getProperties());
        //执行后输出:{user=root, password=1234, driver=com.mysql.jdbc.Driver, jdbcUrl=jdbc:mysql:///test}
    }
}

注意:

引用集合属性都存在一个问题,不能将集合作为独立的 Bean 定义, 导致其他 Bean 无法引用该集合, 所以无法在不同 Bean 之间共享集合,但是可以使用 util schema 里的集合标签定义独立的集合 Bean;

需要注意的是,必须在 <beans> 根元素里添加 util schema 定义:导入util命名空间:xmlns:util="http://www.springframework.org/schema/util"

配置独立的外部list:

<util:list id="mobiles">
  <ref bean="mobile1"/>
  <ref bean="mobile2"/>
</util:list>

引用独立的外部list:

<bean id="person" class="com.sring.model.Person">
    <property name="name" value="loose"></property>
    <property name="mobiles" ref="mobiles"></property>
</bean>

为了简化 XML 文件的配置,越来越多的 XML 文件采用属性而非子元素配置信息,Spring 从 2.5 版本开始引入了一个新的 p 命名空间,可以通过 <bean> 元素属性的方式配置 Bean 的属性,使用 p 命名空间后,基于 XML 的配置方式将进一步简化:

<bean id="person" class="com.spring.model.Person"
p:mobile-ref="mobiles" p:name="loose"></bean>

 

posted @ 2018-04-06 10:05  飘飘来来荡荡去去  阅读(214)  评论(0编辑  收藏  举报