在学习Spring中程序解耦时使用properties+BeanFactory+Map创建保存bean对象时遇到的问题

问题描述:

最近在学习Java Spring框架,关于程序解耦方法中遇到的问题。

  • 在表现层通过使用BeanFactory类获取一个业务层serviceImpl对象。
  • 在BeanFactory中使用静态代码块去预先读取properties配置文件,将所有键值对的对应对象创建出来放入Map容器。
  • 最后在BeanFactory中创建一个get方法,通过传入的name参数,获取BeanFactory类中Map容器里对应name的对象。
  • 但是由于在业务层serviceImpl中同样调用了BeanFactory类去创建持久层daoImpl,导致在BeanFactory类的静态代码块中根据properties文件读取的键值对信息去反射创建对象时,先读取并创建的是业务层serviceImpl,而业务层serviceImpl的创建必然会导致其中的成员变量持久层daoImpl的创建,但是此时BeanFactory类的Map容器还未填入任何对象,因此当业务层serviceImpl调用BeanFactory类的get方法获取Map容器内的对象时,得到的持久层daoImpl为null。

通过new关键字创建对象会导致程序耦合度过高,运行时可能在编译期就出现错误;而通过properties配置文件的方法可以保障编译期通过,程序出错发生在缺类的错误上。但是在实验使用beanfactory进行多个bean的创建和储存时,完成单例创建并用Map进行储存,以实现以后调用service实现类仍然是同一个。在这里遇到了nullpointer的exception,debug后发现map中dao的信息为Null。

public class BeanFactory {
    private static Properties props;
    //存放我们要创建的对象,也就是容器
    private static Map<String,Object> beans;

    static{
        try {
            props = new MyProper();//props = new Properties();
            InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
            props.load(in);
            beans = new HashMap<String,Object>();
            //取出所有的key
            Enumeration keys = props.keys();
            //遍历枚举
            while(keys.hasMoreElements()){
                String key = keys.nextElement().toString();
                String beanPath = props.getProperty(key);
                Object value = Class.forName(beanPath).getDeclaredConstructor().newInstance();
                System.out.println(value);
                beans.put(key,value);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new ExceptionInInitializerError("初始化properties失败!");
        }
    }

//    public static Object getBean(String beanName){
//        Object bean = null;
//        try {
//            String beanPath = props.getProperty(beanName);
//            System.out.println(beanPath);
//            bean = Class.forName(beanPath).getDeclaredConstructor().newInstance();
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        return bean;
//    }

    public static Object getBean(String beanName){
        return beans.get(beanName);
    }

}

bean.properties

accountDao=com.itheima.dao.impl.AccountDaoImpl
accountService=com.itheima.service.impl.AccountServiceImpl
public class AccountServiceImpl implements IAccountService {

    //模拟业务层调用持久层
    private IAccountDao accountDao = (IAccountDao) BeanFactory.getBean("accountDao");

    public void saveAccount() {
        accountDao.saveAccount();
    }

}
//模拟表现层用于调用业务层
public class Client {
    public static void main(String[] args) {
       // IAccountService as = new AccountServiceImpl();
        IAccountService as = (IAccountService) BeanFactory.getBean("accountService");
        as.saveAccount();
    }
}

原因分析:

由https://blog.csdn.net/AnYi_2333/article/details/95546587 尝试将配置文件中的service和dao换一个位置(将service放在dao之前)
但是失效,仍然空指针。

解决方案:

由https://blog.csdn.net/g327513353/article/details/105920385
在bean.properties文件中,键值对信息明明就是daoImpl在先,serviceImpl在后,但是读取到的顺序却是反的。
即在创建service的实现类的时候,beanfactory还没来得及创建dao的bean,导致service实现类对象中的dao属性为空。
解决方法就是使beanfactory先创建dao的bean 再创建service的bean。
使用Myproper.class

import java.util.*;

public class MyProper extends Properties {
    //LinkedHashSet有序,可以保证读取出来顺序不变
    private final LinkedHashSet<Object> keys = new LinkedHashSet<Object>();
    /**
     * 读取key集合
     */
    @Override
    public Set<String> stringPropertyNames() {
        Set<String> set = new LinkedHashSet<String>();
        for (Object key : keys) {
            set.add((String) key);
        }
        return set;
    }

    @Override
    public Set<Object> keySet() {
        return keys;
    }

    /**
     * 枚举可以直接进行遍历,但是和iterator一样,遍历过程中不能进行修改删除等操作<br/>
     * 若要在遍历过程中进行修改擦除等操作,建议使用stringPropertyNames方法
     */
    @Override
    public synchronized Enumeration<Object> keys() {
        return Collections.enumeration(keys);
    }

    @Override
    public synchronized Object put(Object key, Object value) {
        keys.add(key);
        return super.put(key, value);
    }
    /**
     * 若要移除元素,要重写remove方法
     */
    @Override
    public Object remove(Object o) {
        keys.remove(o);
        return super.remove(o);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值