【Spring源码解析】FactoryBean-工厂方法模式的实现及使用

1、工厂方法模式中的三种模式的特色

工厂模式中的三种模式,分别是:简单工厂模式、工厂方法模式、抽象工厂模式,三种分别是什么,以及适合场景是什么?spring

(1)简单工厂模式:一个抽象接口对应一个产品接口,特定产品实现这个接口,针对不一样产品均可以在同一个工厂中生产,同一个工厂生产产品能够经过多种方式,单生产方法(经过类型断定具体是要哪一个产品,并进行new返回),多生产方法(工厂中有多个产品的不一样生产方法,每个生产方法对应一个new 产品的return),或者是静态方法简单工厂(将工厂中的返回某个产品的方法类设置为static,则直接经过类调用静态方法便可,不须要new工厂类的对象实例)缓存

该方法的问题是:若是要新增一个产品,必须对工厂类进行修改,可是若是经过反射或者其余方式能够作统一处理,其实也不会涉及到这个问题,若是要新增一个产品必需要对工厂类修改的时候,此时针对简单工厂模式的修改以为比较麻烦的话或者想要使扩展性更好的话,能够经过工厂方法模式(备注:简单工厂模式比较像一个集中厂,各类不一样的东西都能产)ide

Client端去调用的时候,须要知道:工厂的类名,及提供的生产方法从而能够得到具体产品的实例,以及产品的接口,能够经过实例调用接口获得须要的产品的信息this

其实就是:一个工厂类名Fatory,从工厂的生产方法获取具体产品实例,getProduct()其中会返回new ProductA()或者new ProductB(),以后想要真正去进行产品的使用,还须要经过产品的接口,进行调用,例如ProductA.getProductInfo()等spa

(2)工厂方法模式:能够看作是简单工厂模式的升级版;工厂方法模式就是一个工厂接口和多个工厂实现类,要增长一个新的产品,增长一个新的工厂实现类便可,针对以前的老的工厂实现类也不须要修改.net

工厂方法模式至关于在简单工厂模式的基础上,增长了对于不一样的产品进行多个不一样工厂的实现类的添加,不一样的工厂用于Get不一样的产品,用于进行不一样产品的具体生产代理

Client进行调用的时候,直接经过识别不一样工厂,而后经过工厂接口类提供的公共方法,便可进行接口方法调用,获取产品;还须要知道具体的产品接口,用于进行具体的产品信息的获取code

(3)抽象工厂模式:针对有多个接口的状况,应用于有多个产品族产生的状况xml

抽象工厂模式中能够定义不止一个接口,一个工厂也能够生产不止一个产品类,可是即便是这样,若是要新增一个新的接口,在其中须要修改的部分也是不少的,抽象工厂类的接口须要增长,其余工厂对于该类型的产品的工厂实现要增长,同时能够经过新建其余产品类进行具体产品类的返回;可是若是针对某一个接口对应的产品门类的话,是能够很方便的添加的,并且对老的工厂接口和具体的工厂类,都没有影响,也就是说我想要建一个新的工厂,进行产品的生产,很容易。对象

2、Spring中的工厂方式模式的使用FactoryBean

FactoryBean是一个接口,具体包含的接口以下因此:

这三个接口具体含义是:

T getObject() throws Exception;    //返回此工厂管理的对象的实例
Class<?> getObjectType();    //返回此FactoryBean建立的对象的类型
//这个工厂返回的对象是不是单例,默认返回true;如果单例则由getObject返回的//是相同的对象,是能够缓存的引用
default boolean isSingleton() {     
   return true;
}

基于此,咱们知道这个FactoryBean也用于生成对象实例,那么其实也是一种Bean,该类型的Bean能够做为对经过xml或者普通的注解直接进行生成Bean的一种补充,简单的说就是:能够经过FactoryBean来返回你想要的Bean,该类的Bean的生成多是会比较复杂,或者你想要在作一些扩展操做的,均可以使用该方式

后面,能够重点说明一下ProxyFactoryBean,这个部分会在代理模式的时候说明~

下面经过对FactoryBean的实现,看一下本身使用的效果,FactoryBean的代码以下:

package factorybean.demo;

/**

 * Created by xiami on 2019/6/3.

 */

public interface FactoryBean <T> {

    T getObject();

    Class<?> getObjectType();

    default boolean isSingleton(){return true;}

}

下面是User类对FactoryBean的实现:

package factorybean.demo;

/**

 * Created by xiami on 2019/6/3.

 */

public class User implements FactoryBean {

    private String name;

    private String passWd;

    private int age;


    public void setAge(int age) {

        this.age = age;

    }

    public void setPassWd(String passWd) {

        this.passWd = passWd;

    }

    public void setName(String name) {

        this.name = name;

    }

    @Override

    public Object getObject() {

        if (age <= 0){

            return new Exception("年龄输入错误");

        }

        else {

            return "输入参数正确";

        }

    }

    @Override

    public Class<?> getObjectType() {

        return User.class;

    }

    public String getName() {

        return name;

    }

    public String getPassWd() {

        return passWd;
    }

    public int getAge() {

        return age;

    }

}

重点关注:在getObject()中针对输入的不一样age参数作了一个判断,用于输出参数是否异常

接下来是:

在springtest.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"

       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.xsd">

    <bean id="factorybeanUser" class="factorybean.demo.User">

        <property name="name" value="lxlx" />

        <property name="passWd" value="111" />

        <property name="age" value="1"/>

    </bean>

</beans>

注意,由于在简单工厂模式中实现的GetBean还没法解析FactoryBean的类型,所以这里直接用的Spring-Framework做为lib库方便对Spring中的xml解析和GetBean的调用,Client调用类代码以下:

package factorybean.demo;

import org.springframework.beans.BeansException;

import org.springframework.context.support.ClassPathXmlApplicationContext;

/**

 * Created by 58 on 2019/6/3.

 */
public class Client {
    public static void main(String[] args) throws BeansException {

        ClassPathXmlApplicationContext classPathXmlApplicationContext =
                new ClassPathXmlApplicationContext("classpath:factorybean/demo/springtest.xml");
        User user = (User)classPathXmlApplicationContext.getBean("factorybeanUser");
        System.out.println(user.getObject());
    }
}

当springtest.xml中配置age的值为-1时,运行结果为:

当springtest.xml中配置age的值为12时,运行结果为:

可见:经过对FactoryBean的接口的实现,在getObject()中可以返回本身想要的内容,经过GetBean()就能够获取到,以后的文章会对FactoryBean在GetBean中是何时被获取作介绍

参考文章:

http://www.javashuo.com/article/p-tdvbctkv-kx.html

https://blog.csdn.net/zknxx/article/details/79588391

https://www.jianshu.com/p/6f0a59623090

相关文章
相关标签/搜索