5.Spring系列之Bean的配置2

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


1.Bean的自动装配

①.Spring IOC 容器可以自动装配 Bean. 需要做的仅仅是在 <bean> 的 autowire 属性里指定自动装配的模式
②.byType(根据类型自动装配): 若 IOC 容器中有多个与目标 Bean 类型一致的 Bean. 在这种情况下, Spring 将无法判定哪个 Bean 最合适该属性, 所以不能执行自动装配.
③.byName(根据名称自动装配): 必须将目标 Bean 的名称和属性名设置的完全相同.
④.constructor(通过构造器自动装配): 当 Bean 中存在多个构造器时, 此种自动装配方式将会很复杂. 不推荐使用
 
首先创建两个Bean,Person和Mobile:
public class Person {

    private String name;
    private Mobile mobile;

    public String getName() {
        return name;
    }

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

    public Mobile getMobile() {
        return mobile;
    }

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

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

}
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容器中配置byName自动装配:

<?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"
    xmlns:p="http://www.springframework.org/schema/p"
    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="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" autowire="byName">
       <property name="name" value="loose"></property>
    </bean>
</beans>

byName: 若属性名和某一个 bean 的 id 名一致, 即可完成自动装配. 若没有 id 一致的, 则无法完成自动装配

在IOC容器中配置byType自动装配:

<?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"
    xmlns:p="http://www.springframework.org/schema/p"
    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">
    
    <!-- 无需id,根据Bean的类型自动装配 -->
    <bean 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" autowire="byType">
       <property name="name" value="loose"></property>
    </bean>
</beans>

byType: 根据类型进行自动装配. 但要求 IOC 容器中只有一个类型对应的 bean, 若有多个则无法完成自动装配

总结:
自动装配,即将实体内的实体(例如Person类中的Car类)自动引用;
使用byName,只要实体内的实体名称的setXxx方法名中的Xxx和IOC容器中配置的bean id一致,即自动装配;
使用byType,只要实体内的实体类型和IOC容器中的bean定义的类型一致即自动装配上。
自动装配的缺点:
--->在 Bean 配置文件里设置 autowire 属性进行自动装配将会装配 Bean 的所有属性. 然而, 若只希望装配个别属性时, autowire 属性就不够灵活了.
--->autowire 属性要么根据类型自动装配, 要么根据名称自动装配, 不能两者兼而有之.
注意:本身自动装配实际开发中运用不多,所以其他属性不再说明,有兴趣自己去查阅相关资料。
 
2.继承Bean配置
注意:
①.这不是java上的继承,而是配置上的继承。
②.Spring 允许继承 bean 的配置, 被继承的 bean 称为父 bean. 继承这个父 Bean 的 Bean 称为子 Bean
③.子 Bean 从父 Bean 中继承配置, 包括 Bean 的属性配置
④.子 Bean 也可以覆盖从父 Bean 继承过来的配置
⑤.父 Bean 可以作为配置模板, 也可以作为 Bean 实例. 若只想把父 Bean 作为模板, 可以设置 <bean> 的abstract 属性为 true, 这样 Spring 将不会实例化这个 Bean
⑥.并不是 <bean> 元素里的所有属性都会被继承. 比如: autowire, abstract 等.
⑦.也可以忽略父 Bean 的 class 属性, 让子 Bean 指定自己的类, 而共享相同的属性配置. 但此时 abstract 必须设为 true
首先创建一个Bean:
public class Person {

    private String name;
    private String province;
    private String city;

    public String getName() {
        return name;
    }

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

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

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

}

接着在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"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    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="personParent" class="com.spring.model.Person">
       <property name="name" value="loose"></property>
    </bean>
    <!-- 使用parent声明继承哪个Bean的配置 -->
    <bean id="personSon" parent="personParent"></bean>
</beans>

测试简单继承程序:

public class Main {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        Person person = (Person) ctx.getBean("personSon");
        System.out.println(person);
        //输出:Person [name=loose, province=null, city=null]
    }
}

在IOC容器中配置子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"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    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="personParent" class="com.spring.model.Person">
       <property name="name" value="loose"></property>
    </bean>
    
    <bean id="personSon" parent="personParent">
     <!-- 覆盖父Bean的name属性 --> <property name="name" value="loose2"></property> </bean> </beans>

测试子Bean覆盖父Bean程序:

public class Main {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        Person person = (Person) ctx.getBean("personSon");
        System.out.println(person);
        //输出:Person [name=loose2, province=null, city=null]
    }
}

在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"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    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">
    
    <!-- 定义为模板可以不配置class属性,但子Bean必须配置class -->
    <bean id="personParent" abstract="true">
       <property name="name" value="loose"></property>
    </bean>
    
    <bean id="personSon" class="com.spring.model.Person" parent="personParent"></bean>
</beans>

测试将父Bean定义为模板程序:

public class Main {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        Person person = (Person) ctx.getBean("personSon");
        System.out.println(person);
        //输出:Person [name=loose2, province=null, city=null]
    }
}

3.Bean的依赖配置

Spring 允许用户通过 depends-on 属性设定 Bean 前置依赖的Bean,前置依赖的 Bean 会在本 Bean 实例化之前创建好,如果前置依赖于多个 Bean,则可以通过逗号,空格或的方式配置 Bean 的名称。
 
4.Bean的作用域
在 Spring 中,可以在 <bean> 元素的 scope 属性里设置 Bean 的作用域,默认情况下, Spring 只为每个在 IOC 容器里声明的 Bean 创建唯一一个实例, 整个 IOC 容器范围内都能共享该实例:所有后续的 getBean() 调用和 Bean 引用都将返回这个唯一的 Bean 实例.该作用域被称为 singleton, 它是所有 Bean 的默认作用域,常见的值有4个,分别是:
singleton:在IOC容器中仅存在一个实例,Bean以单例的形式存在;
prototype:每次调用getBean()都会返回一个全新的实例;
request:每次Http请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境;
session:同一个HttpSession共享同一个Bean,不同的HttpSession使用不同的Bean,该作用域仅适用于WebApplicationContext环境;
最常用的是singleton和prototype!
我们创建一个Bean为Person来测试一下:
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容器中,将该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"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    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="person" class="com.spring.model.Person" scope="singleton">
        <property name="name" value="loose"></property>
    </bean>
</beans>

测试Bean单例:

public class Main {

    @SuppressWarnings("resource")
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        Person person1 = (Person) ctx.getBean("person");
        Person person2 = (Person) ctx.getBean("person");
        System.out.println(person1 == person2);
        //输出true,证明是单例子
    }
}

在IOC容器中,将该Bean配置为prototype类型:

<?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"
    xmlns:p="http://www.springframework.org/schema/p"
    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="person" class="com.spring.model.Person" scope="prototype">
        <property name="name" value="loose"></property>
    </bean>
</beans>

测试Bean prototype:

public class Main {

    @SuppressWarnings("resource")
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        Person person1 = (Person) ctx.getBean("person");
        Person person2 = (Person) ctx.getBean("person");
        System.out.println(person1 == person2);
        //输出false,证明非单例
    }
}

上面的例子仅仅是获取两个id一致的Bean,比较无法直观的看出IOC容器为我们的Bean创建实例的过程,接下来,我们通过一个例子再来看单例和prototype的区别:我们将Person的无参构造器显示出来

public class Person {

    private String name;

    public String getName() {
        return name;
    }

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

    public Person() {
        System.out.println("我是person无参构造器");
    }
    
    @Override
    public String toString() {
        return "Person [name=" + name + "]";
    }

}

接着将IOC容器中的Bean配置为单例模式:

<bean id="person" class="com.spring.model.Person" scope="singleton">
  <property name="name" value="loose"></property>
</bean>

测试单例,看看控制台的输出:

public class Main {

    @SuppressWarnings("resource")
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //运行后输出:我是person无参构造器
    }
}

说明:单例模式是IOC一启动就帮我们实例化了Person。

再将Bean配置为prototype,然后在看测试程序的控制台输出:

<bean id="person" class="com.spring.model.Person" scope="prototype">
  <property name="name" value="loose"></property>
</bean>
public class Main {

    @SuppressWarnings("resource")
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //运行后输出:没有任何输出
    }
}

说明:prototype模式,IOC容器启动并不会帮我们实例化Person。

最后,我们通过获取Bean再来对比下两者的区别:

<bean id="person" class="com.spring.model.Person" scope="singleton">
  <property name="name" value="loose"></property>
</bean>
public class Main {

    @SuppressWarnings("resource")
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        Person person1 = (Person) ctx.getBean("person");
        Person person2 = (Person) ctx.getBean("person");
        System.out.println(person1 == person2);
        //运行后输出:
        //我是person无参构造器
        //true
    }
}
<bean id="person" class="com.spring.model.Person" scope="prototype">
  <property name="name" value="loose"></property>
</bean>
public class Main {

    @SuppressWarnings("resource")
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println("前面没有帮忙实例化...");
        Person person1 = (Person) ctx.getBean("person");
        Person person2 = (Person) ctx.getBean("person");
        System.out.println(person1 == person2);
        //运行后输出:
        //我是person无参构造器
        //我是person无参构造器
        //false
    }
}

总结:

单例模式的Bean,IOC容器启动会自动帮我们创建了该Bean的实例,并且只创建一次;而prototype模式下IOC容器启动不会帮我们创建该Bean的实例,而是每次去getBean的时候,每次都实例化一个对象出来。

注意:常用的是单例和prototype模式,其它的了解就行,有兴趣的自行翻阅资料。

 
原文地址:https://www.cnblogs.com/Json1208/p/8727635.html