让Spring的FactoryBean成为真正的万能Bean工厂

简述创建Bean的普通方式

        创建Spring config的xml配置文件,在此配置文件中对bean进行定义,如:

    <!--配置Bean,目的是让spring帮我们创建java对象。一个bean标签创建一个对象
        id属性:配置一个唯一的标识
        class属性:设置类的全类名,spring利用反射创建对象-->
    <bean id="helloWorld" class="spring.HelloWorld">
        <!--设置属性值 name的值为setXXX中的XXX-->
        <property name="name" value="Spring"></property>
    </bean>

        其中,class = "spring.HelloWorld"固定了此bean的类型为HelloWorld类型的。验证如下:

public class HelloWorldDemo {
    @Test
    public void testHelloWorld() {
        //1、创建IOC容器对象
        ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2、从IOC容器中获取HelloWorldI对象
        /*方式一*/
        Object object = ioc.getBean("helloWorld");
        System.out.println("object.getClass() = " + object.getClass());
        //输出结果:object.getClass() = class spring.HelloWorld
        /*方式二*/
        HelloWorld helloWorld1 = ioc.getBean("helloWorld", HelloWorld.class);
        System.out.println("helloWorld1.getClass() = " + helloWorld1.getClass());
        //输出结果:helloWorld1.getClass() = class spring.HelloWorld
    }
}

使用FactoryBean创建万能Bean

FactoryBean的源码非常简单,其中包含两个抽象方法和一个默认方法。其中getObject()方法用于获取实例,即创建bean,当xml配置文件中bean标签的class属性为FactoryBean的实现类是,使用getBean()方法获取bean时会调用该方法来创建,相当于getObject()代理了getBean();getObjectType()方法用于获取bean的类型。

package org.springframework.beans.factory;

import org.springframework.lang.Nullable;

public interface FactoryBean<T> {
    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

    @Nullable
    T getObject() throws Exception;

    @Nullable
    Class<?> getObjectType();

    default boolean isSingleton() {
        return true;
    }
}

        要想使用工厂Bean,首先就要创建一个FactoryBean接口的实现类,然后在实现类中重写的getObject()和getObjectType()方法中做文章。

创建过程

        由于我们希望得到一个万能的工厂Bean,所以在实现FactoryBean接口时仍然使用泛型,并且创建此泛型的实例用于接收从xml配置文件中传递来的值,这样的话,xml配置文件中传递什么类型的值,这个泛型就会是什么类型。

        本例创建了一个Book类型的Bean,并以级联的形式赋值给FactoryBeanImpl的Bean中的 t 属性。这样,FactoryBeanImpl中的泛型属性 t 就会接收到传递过来的Book类型的bean——book,然后泛型就会成为Book类型。

        最后在测试类FactoryBeanImplTest中进行测试,通过ClassPathXmlApplicationContext创建ioc容器对象,然后通过ioc容器对象创建bean,其getBean()方法的第二个参数并不必须得按照xml配置文件中的类型写,比如我这里可以不用非得写FactoryBeanImpl.class(并且这样写会报BeanNotOfRequiredTypeException错,因为这样的话就会创建一个FactoryBeanImpl类型的bean,但是由于传递过来的为Book类型,两个类型不同),而是写Book.class才可以

public class FactoryBeanImpl<T> implements FactoryBean {
    private T t;

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }

    public T getObject() throws Exception {
        return t;
    }

    public Class<?> getObjectType() {
        return t.getClass();
    }
}
<?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="book" class="spring2.Book">
        <property name="name" value="西游记"></property>
        <property name="ID" value="1"></property>
        <property name="sales" value="99"></property>
        <property name="author" value="施耐庵"></property>
        <property name="price" value="55.34"></property>
    </bean>

    <bean id="FactoryBeanImpl" class="spring4.FactoryBeanImpl">
        <property name="t" ref="book"></property>
    </bean>
</beans>
public class FactoryBeanImplTest {
    @Test
    public void Demo() throws Exception {
        ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext4.xml");
        /*方式一*/
        Book book = ioc.getBean("beanFactoryImpl", Book.class);
        /*方式二*/
        Book book2 = (Book) ioc.getBean("FactoryBeanImpl");
        System.out.println("beanFactory = " + book2);
        //输出结果:beanFactory = Book{ID=1, name='西游记', author='施耐庵', price=55.34, sales=99}
    }
}

图解

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我的Y同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值