工厂创建模式

一、Spring配置动态工厂

1.我们只需自定义一个工厂类,用于对象的实例化,然后将该工厂类注册到 Spring 容器中;

2.对需要进行实例化的类进行注册,添加 factory-bean 以及 factory-method 属性即可 

 (1)自定义工厂类:

public class CarFactory {

    public CarcreateCar() {
        Car car= new Car();
        System.out.println("CarFactory 负责创建 Car 实例对象!");
        return car;
    }

}

(2)注册工厂类,spring_config.xml:

<!-- 注册动态工厂 -->
<bean id="factory1" class="com.demo.factory.CarFactory"></bean>
<!-- Spring容器,当前car类的实例化操作,由动态工厂来执行 -->
<bean id="car" class="com.demo.beans.Car" factory-bean="factory1" factory-method="createCar"></bean>

(3)测试代码:

public static void main(String[] args) {
	ApplicationContext factory = new ClassPathXmlApplicationContext("spring_config.xml");
	Car car= (Car ) factory.getBean("car");
	System.out.println(car);
}

(4)测试结果:

可以看到,get实例化对象是走的我们自定义的 CarFactory 类,这就是动态工厂

 

二、Spring配置静态工厂

动态工厂在高并发的情况下会占用较多的内存,所有也就有了静态工厂,就是把工厂中的方法改为静态方法,使用 static 关键字进行修饰即可,如下所示:

public static Car createCar() {
	Car car = new Car ();
	System.out.println("CarFactory 负责创建 Car 实例对象!");
	return car;
}

注册工厂的时候,就直接注册工厂类即可:

<bean id="car" class="com.demo.factory.Car" factory-method="createCar"></bean>

很简单的改动,却可以减少很多内存的浪费

三、手动实现动态工厂

这里只实现动态工厂

上面的 Spring 配置动态工厂就可以看出,我们又用到了 <bean> 标签的两个新属性,factory-bean 以及 factory-method,所以我们要在 BeanDefined类中添加上这两个属性,代码如下所示:

(1)BeanDefined.java

public class BeanDefined {

    private String beanId; // bean的id

    private String classPath; // bean的文件路径

    private String scope = "singleton";

    private String factoryBean = null; // 工厂对象

    private String factoryMethod = null; // 工厂方法

    此处省略setter和getter方法
}

(2)自定义一个工厂:CarFactory.java

public class CarFactory {

    public static Car createCar() {
        Car car = new Car();
        System.out.println("使用CarFactory 负责创建 Car 实例对象!");
        return car;
    }
}

(3)手动创建:BeanFactory

在 Spring 中,自定义工厂类要注册到 Spring 容器中,我们自己实现的动态工厂的功能也需要把自定义工厂类添加到我们对应的容器中,也就是 BeanFactory 类中的 springIoc 集合中,这里我们只对 scope 属性为 prototype 的情况进行的拓展,如下所示:

public class BeanFactory {

    private List<BeanDefined> beanDefinedList; // 存放bean的集合

    private Map<String, Object> springIoc; // 存放已经创建好的实例对象(用于单例模式)

    public BeanFactory(List<BeanDefined> beanDefinedList) throws Exception {
        this.beanDefinedList = beanDefinedList;
        springIoc = new HashMap<String, Object>(); // 所有scope="singleton"采用单例模式管理bean对象
        for (BeanDefined bean : beanDefinedList) {
            if ("singleton".equals(bean.getScope())) {
                String classPath = bean.getClassPath();
                Class classFile = Class.forName(classPath);
                Object instance = classFile.newInstance();
                springIoc.put(bean.getBeanId(), instance);
            }
        }
    }

    /**
     * 获取bean实例
     *
     * @param beanId
     * @return
     * @throws Exception
     */
    public Object getBean(String beanId) throws Exception {
        Object instance = null;
        for (BeanDefined bean : beanDefinedList) {
            if (beanId.equals(bean.getBeanId())) {
                String classPath = bean.getClassPath();
                Class classFile = Class.forName(classPath);
                String scope = bean.getScope();
                String factoryBean = bean.getFactoryBean();
                String factoryMethod = bean.getFactoryMethod();
                if ("prototype".equals(scope)) {
                    /************ 动态工厂拓展 begin ************/
                    if (factoryBean != null && factoryMethod != null) {
                        // 用户希望指定工厂来创建实例对象
                        Object factoryObj = springIoc.get(factoryBean);
                        Class factoryClass = factoryObj.getClass();
                        Method methodObj = factoryClass.getDeclaredMethod(factoryMethod, null);
                        methodObj.setAccessible(true);
                        instance = methodObj.invoke(factoryObj, null);
                    } else {
                        // 如果scope是prototype(原型模式),每一次都创建一个新的实例对象
                        instance = classFile.newInstance();
                    }
                    /************ 动态工厂拓展 end ************/
                } else {
                    // 如果scope是singleton(单例模式),返回同一个实例对象
                    instance = springIoc.get(beanId);
                }
                return instance;
            }
        }
        return null;
    }

}

如果 BeanDefined 对象的 factoryBean 和 factoryMethod 属性都不为空,就是用自定义工厂来实例化对象;如果为空,则直接返回一个新的实例化对象。这里我们将自定义工厂类以及需要被实例化的对象都添加到了 自定义Map集合 springIoc 中,不用再单独创建集合来存放自定义工厂类。

(4)测试代码:

public static void main(String[] args) throws Exception {
	// 1、声明注册bean
	BeanDefined beanObj = new BeanDefined();
	beanObj.setBeanId("car");
	beanObj.setClassPath("com.demo.factory.CarFactory");
	beanObj.setScope("prototype");
	beanObj.setFactoryBean("factory");
	beanObj.setFactoryMethod("createCar");
	// 获取工厂类
	BeanDefined beanObj1 = new BeanDefined();
	beanObj1.setBeanId("factory");
	beanObj1.setClassPath("com.demo.factory.CarFactory");
	List<BeanDefined> configuration = new ArrayList<BeanDefined>();
	configuration.add(beanObj);
	configuration.add(beanObj1);
	// 2、声明一个BeanFactory,类似于Spring中的ApplicationContext
	BeanFactory factory = new BeanFactory(configuration);
	// 3、开发人员向BeanFactory索要实例对象
	Car car = (Car) factory.getBean("car");
	System.out.println("car =" + car);
}

(5)测试结果:

从结果可以看出,Car对象是由 CarFactory 进行创建的,这样就达到了我们的目的,能够和 Spring 注册动态工厂达到相同的效果。


四、总结

通过本章节我们可以了解到 Spring 动态工厂以及静态工厂的使用和简易的内部实现,根据类的反射机制,拿到我们自定义的工厂类对象,来进行对象的实例化。

猜你喜欢

转载自blog.csdn.net/Byd_chao/article/details/83339485