2-Spring-基于xml配置bean

Spring-基于xml配置bean


一. Bean实例化的4种方式

前提:要求Spring管理的类都要提供 公开的无参的构造。
通过Bean标签告诉Spring该用什么方式获得类的对象

1.1 无参数构造方法(开发最常用)

首先写一个pojo类

public class User {
    private Integer id;
    private String name;

    public User(){
        System.out.println("调用默认构造");
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

然后告诉Spring如何管理

    <!--    让Spring管理当前的User类-->
    <bean id = "user" class="org.buaa.pojo.User">
    </bean>

最后使用它

    public void testUser(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        User user = (User) context.getBean("user");
        System.out.println(user);
        /* 结果
            调用默认构造
            User{id=null, name='null'}
        */
    }

1.2 静态工厂方法

静态工厂方法: 在一个类中书写静态方法,再这个方法中返回某个 Bean 的对象。

首先写一个基本的工厂

public class UserFactory {
    public static User getUserInstance(){
        return new User();
    }
}

告诉Spring如何配置

    <!--演示通过静态工厂获取某个类的对象-->
    <!--通过factory-method标签告知,我们使用的是静态工厂-->
    <bean id = "user" class = "org.buaa.factory.UserFactory" factory-method="getUserInstance"></bean>

实际上Spring管理的不是UserFactory类,而是User类

编写测试

    public void testStaticFactory(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 这个方法最终得到的是一个User对象,所以应该接收一个User对象
        // 通过静态工厂方法得到User
        User user = (User) context.getBean("user");
        System.out.println(user);
        /*
            调用默认构造
            调用默认构造
            User{id=null, name='null'}
        */
    }

可以看到构造方法执行了两次。原因: 在加载核心配置文件时,Spring会加载每一个标签,而我们没有删除 #1.1 中的标签,所以目前核心配置文件如下。可以看到Spring管理了两个User,都会初始化一次,所以会调用两次构造。

    <!--    让Spring管理当前的User类-->
    <bean id = "user" class="org.buaa.pojo.User"></bean>

    <!--    
        演示通过静态工厂获取某个类的对象
        id:当前静态工厂返回的Bean的唯一标识
        class:静态工厂的class
        factory-method:配置的静态工厂的静态方法
    -->
    <bean id = "userFactory" class = "org.buaa.factory.UserFactory" factory-method="getUserInstance"></bean>

实际上,我们仅书写加载核心配置文件的代码,也会出现调用两次构造的情况。
所以,核心配置文件只应加载一次。但是一个Spring的核心容器中可以管理多个相同的class而new出来的对象

1.3 实例工厂方法

实例工厂方法:和静态工厂类似,但工厂本身是一个实例。
在类中提供非静态的方法,在这个方法中返回需要获取的Bean对象

实例工厂

public class InstanceFactory {
    public User getUserInstance(){
        return new User();
    }
}

配置

    <!--  配置实例工厂自己的Bean  -->
    <bean id = "instanceFactory" class = "org.buaa.factory.InstanceFactory"></bean>
    <!--
        实例工厂本身已经被Spring管理,而实例工厂返回另一个Bean对象,
        在配置时需要通过factory-bean属性来引用已经存在的工厂Bean
        需要通过factory-method 来指定实例工厂bean中返回别的bean的方法
    -->
    <bean id = "user2" factory-method="getUserInstance" factory-bean="instanceFactory"></bean>

测试

    public void testInstanceFactory(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        User user = (User) context.getBean("user2");
        System.out.println(user);
    }

1.4 FactoryBean方式(Spring底层使用较多)

经常面试到
是一种实例化Bean的方式。

首先编写自定义类,实现 FactoryBean接口

/**
 *  使用 Spring 底层提供的 FactoryBean接口 来实例化某个类的对象
 *  自定义一个类,实现 FactoryBean接口
 */
public class UserInstance implements FactoryBean<User> {
    
    // getObject方法中创建出需要管理的Bean对象
    @Override
    public User getObject() throws Exception {
        return new User();
    }

    @Override
    public Class<?> getObjectType() {
        return User.class;
    }
}

配置

    <!--
        配置通过FactoryBean接口获取User实例
        目前配置Bean的虽然不是User,但它实现了FactoryBean接口,且泛型书写的是User,
        Spring在实例化的时候,会发现它实现了FactoryBean接口,那么就可以从复写的getObject方法中获得对象
    -->
    <bean id = "user3" class = "org.buaa.factory.UserInstance"></bean>

测试


1.5 FactoryBean 与 BeanFactory区别

FactoryBean:是用来创建指定的一个Bean实例的接口,用来告诉Spring如何实例化一个具体的类的对象
BeanFactory:是管理Bean的,它是Spring中最的顶层接口之一(ApplicationContext 是它的子接口的子接口),代表的是Spring容器加载spring核心配置文件的对象

二. Bean相关知识

2.1 Bean的作用域

在配置 bean 的时候,有一个标签为 scope,代表它的作用域

<bean id = "user4" class = "org.buaa.pojo.User" scope="singleton"></bean>`
<bean id = "user5" class = "org.buaa.pojo.User" scope="prototype"></bean>`
  • 默认:singleton
  • singleton: 单例,当前的Bean标签关联的对象永远是唯一的,(常用)
  • prototype: 多例,将某个Bean配置为多例后,只要通过Spring核心对象获取Bean,都会重新创建Bean对象

singleton下每次getBean,获取的结果都是同一个。
prototype下每次getBean,都会新建一个对象。

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user1 = (User) context.getBean("user4");
User user2 = (User) context.getBean("user4");
user1 == user2;// true

User user3 = (User) context.getBean("user5");
User user4 = (User) context.getBean("user5");
user3 == user4;// false

2.2 Bean的生命周期

Bean在创建/销毁时,让它执行一些方法。
pojo如下:

public class User {
    ...
    public void init(){
        System.out.println("初始化时可以执行的方法");
    }
    public void destory(){
        System.out.println("销毁时可以执行的方法");
    }
    ...
}

配置

    <!--  配置Bean被Spring管理时,可以指定自己的一些初始化、销毁方法 -->
    <bean id = "user5" class = "org.buaa.pojo.User" init-method="init" destroy-method="destory"></bean>

测试

    public void testUserInitAndDestory(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        User user = (User) context.getBean("user5");
        System.out.println(user);
        /*
            调用默认构造
            初始化时可以执行的方法
            User{id=null, name='null'}
        */
        ((ClassPathXmlApplicationContext)context).close();
        /* 销毁时可以执行的方法 */
    }

注意 并没有执行销毁的方法,想要执行它,需要手动关闭Spring容器,而ApplicationContext接口没有提供close方法,所以必须强制幻化为ClassPathXmlApplicationContext对象,然后调用close。

注意 如果Bean设置为prototype多例,那么即使手动关闭也不会执行。

2.3 Bean的属性注入

2.3.1 构造方法

缺点:在xml文件中写死了传入什么值。当然也可以改为"${}"通过引配置文件解决,但是很麻烦
pojo

public class User {
    ...
    public User(Integer id, String name){
        this.id = id;
        this.name = name;
    }
    ...
}

配置

    <!--
        演示通过构造方法给Bean的属性注入数据
        使用constructor-arg标签配置构造方法需要的参数
            name:变量名
            value:值
            index:第index个参数
            ref:可以传一个复杂对象
    -->
    <bean id = "car" class = "org.buaa.pojo.Car"/>
    <bean id="user6" class = "org.buaa.pojo.User">
        <constructor-arg name = "name" value = "jackl"/>
        <constructor-arg index = "1" value ="1"/>
        <constructor-arg name = "car" ref = "car"/>
    </bean>

2.3.2 setter方法注入

首先要在pojo类中书写set方法,然后配置文件
pojo

public class Car {
    ...
    private String color;
    private Integer price;
    private String type;

    public void setColor(String color) {
        this.color = color;
    }

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

    public void setType(String type) {
        this.type = type;
    }
    ...
}

配置

    <!--
        演示通过set方法给Bean的属性注入数据
        使用property标签配置构造方法需要的参数
            name:set后的XXX名称,如setColor方法,对应 name = "Color"
            value:值
            ref:可以传一个复杂对象
    -->
    <bean id = "car" class = "org.buaa.pojo.Car">
        <property name = "Color" value = "黄色"/>
        <property name = "Price" value = "100"/>
        <property name = "Type" value = "黄色"/>
    </bean>

2.3.3 集合属性注入

其实本质还是前两种注入方式,只是想注入集合有些不太一样

    <!--
        演示通过set方法给Bean的集合注入属性,要求pojo类中存在一个 setLists的方法。
    -->
    <bean id = "student" class = "org.buaa.pojo.Student">
        <property name = "lists">
            <list>
                <value>爬山</value>
                <value>下海</value>
            </list>
        </property>
        <!--演示下map如何注入-->
        <property name = "maps">
            <map>
                <entry key = "addr" value = "北京"/>
            </map>
        </property>
    </bean>
    <!--
        演示通过set方法给Bean的集合注入属性
    -->
    <bean id = "student" class = "org.buaa.pojo.Student">
        <constructor-arg name = "set"/>
            <set>
                <value>爬山</value>
                <value>下海</value>
            </set>
        </constructor-arg>
    </bean>

xml配置中的标签及属性

bean标签中的属性

  • class: 本质上是为反射提供服务,告诉框架这个类是什么类,举例: class=“com.service.UserDao”
  • id:唯一标识
  • factory-method:配置的静态工厂的静态方法
  • factory-bean: 引用已经存在的工厂bean
  • scope:用于声明Bean的作用域,singleton: 单例;prototype: 多例
  • init-method: 声明创建Bean时执行某个方法
  • destroy-method: 声明销毁Bean时执行某个方法,要求Bean为单例且需要手动关闭Spring时才执行

constructor-arg标签

是bean的子标签,用于使用构造方法传入数据

  • name:构造方法上的参数名
  • value:传入的值
  • index:构造方法上第index个参数
  • ref:可以传一个复杂对象如自定义、包装对象

property标签set

是bean的子标签,用于使用set方法传入数据

  • name:set后的XXX名称,如setColor方法,对应 name = “Color”
  • value:传入的值
  • ref:可以传一个复杂对象如自定义、包装对象

集合标签

如果注入的数据是集合,那么要使用特定的集合标签

<list>
    <value></value>
</list>
<set>
    <value></value>
</set>
<map>
    <entry key = "k", value = "v"/>
</map>
<array>
    <value>11</value>
    <value>12</value>
    <value>13</value>
</array>
<props>
    <!--Properties类,类似map,用于持久的保存属性如环境变量-->
    <prop key = "sex"></prop>
    <prop key = "height">2.0</prop>
</props>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值