上一节提到程序的解耦,但是出现了一个问题,就是在
Clinet
类中,如果打印得到的对象:
for(int i=0;i<6;i++){ AccountService accountService = (AccountService) BeanFactory.getBean("accountService"); System.out.println(accountService); }
结果就是得到5个不同的accountService对象。原因是因为
BeanFactory
类中的这句话:
bean = Class.forName(beanPath).newInstance();//每次都会用默认的构造器创建新的对象
所以,这问题怎么解决呢?
利用Map集合处理。
package com.springpractise.demo.factory; import java.io.IOException; import java.io.InputStream; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Properties; /** * 一个创建Bean对象的工厂 * Bean:在计算机英语中有可重用组件的含义 * javaBean:用java语言编写的可重用组件 * 创建javaBean: * 第一个:需要一个配置文件来配置service和dao * 配置的内容:唯一标志 = 全限定类名(key = value) * 第二个:通过读取配置文件中配置的内容,反射创建对象 * * 配置文件可以是xml也可以是properties * */ public class BeanFactory { //定义一个Properties对象 private static Properties properties; //定义一个Map,用于存放我们要创建的对象。我们把它称之为容器 private static Map<String,Object> beans; //使用静态代码块为Properties对象赋值 static { try { //实例化对象 properties = new Properties(); //获取properties文件的流对象(通过BeanFactory来获取文件) InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties"); properties.load(in); beans = new HashMap<>(); Enumeration<Object> keys = properties.keys(); //遍历枚举 while (keys.hasMoreElements()){ //取出每个key String key = keys.nextElement().toString(); //根据key获取value String beanPath = properties.getProperty(key); //反射创建对象 Object value = Class.forName(beanPath).newInstance(); beans.put(key,value); } } catch (IOException e) { throw new ExceptionInInitializerError("初始化properties失败"); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } /** * 根据Bean名称获取对象 * @param beanName * @return */ public static Object getBean(String beanName){ return beans.get(beanName); } }
可以看到,在静态代码块中,初次加载的时候,就把对象放进Map中,以后每次要用对象的时候,直接用key去获取对象就可以了。
这样一来,打印多次对象的时候,都是从同一个key获取的对象,因此就避免了多次实例化。