当 "反射" 遇到 "IO" 触发的 "基情"

344 阅读3分钟
原文链接: www.jianshu.com

表情.jpg

前言

别看短,因为很精简

会有什么基情啊?

如果你是大神当你点进来的看的时候,你已经猜 的大概了,那就是Spring的核心机密(通过文件配置对象),为了满足一下好奇心,下文我们将一起简单的破译一下Spring的核心机密.

那他是怎么实现的?

下面我们将使用三步走的战略,一步一步的破译Spring的机密

需要的材料

名称 说明
ObjectPool 对象向容器
POJO 简单对象
Config 配置文件

实现的步骤

  1. 创建简单对象
    我们就写个Person类就可以了:

    public class Person {
    private String name;
    private String age;
    public Person(String name, String age) {
         this.name = name;
         this.age = age;
     }
    @Override
     public String toString() {
         return "此人的姓名: "+name+",年龄: "+age+"岁";
     }
     //省略get,set方法
     ''''''
    }
  2. 创建对象容器
    下面可是重头戏了,可得集中注意力了,下面将讲解大体思路:

    • 创建对象池(通过Map集合实现)
    • 将配置文件(装有对象信息)装换成输入流并获取其信息
    • 根据其信息通过反射调用设置对象的值
    • 最后获取对象
    /**对象容器*/
    public class ExtendedObjectPoolFactory {
    //对象容器池
     private Map<String, Object> objectPool = new HashMap<>();
    //文件配置对象
     private Properties config = new Properties();
    /**
    *初始化
    */
     public void init(String fileName) {
         try {
             //将文件转换成输入流
             FileInputStream fis = new FileInputStream(fileName);
             {//文件配置对象加载输入流
                 config.load(fis);
             }
    
         } catch (FileNotFoundException e) {
             e.printStackTrace();
         } catch (IOException e) {
             e.printStackTrace();
         }
         initPool()
     }
    
     /**
      * 创建对象
      *
      * @param name
      * @return
      * @throws ClassNotFoundException
      * @throws IllegalAccessException
      * @throws InstantiationException
      */
     private Object createObject(String name) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
         //通过反射创建对象
         return Class.forName(name).newInstance();
     }
    
     /**
      * 初始化对象池
      */
     private void initPool() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
         for (String name : config.stringPropertyNames()) {
             //将文件里的对象放入我们的对象池
             if (!name.contains("%")) objectPool.put(name, createObject(config.getProperty(name)));
         }
         initProperty();
     }
    
     /**
      * 初始化文件配置
      */
     private void initProperty() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
         for (String name : config.stringPropertyNames()) {
             if (name.contains("%")) {
                 String [] objAndProp=name.split("%");
                 //获取setter方法的参数值
                 Object target=getObject(objAndProp[0]);
                 //拼接字符串toUpperCase()保证大写
                 String mtName="set"+objAndProp[1].substring(0,1).toUpperCase()+objAndProp[1].substring(1);
                 //获取实现类对应的
                 Class<?> targetClass=target.getClass();
                 //获取对应的方法 
                 Method mtd=targetClass.getMethod(mtName,String.class);
                 //调用方法
                 mtd.invoke(target,config.getProperty(name));
             }
         }
     }
    
     /**
      * 获取对象
      *
      * @param name
      * @return
      */
     public Object getObject(String name) {
    
         return objectPool.get(name);
     }
  3. 编写配置文件
    文件名称: exobj.txt
    文件内容:
    a=com.bean.Person
    b=com.bean.Person
    #分别设置a,b对象的姓名和年龄注意格式
    a%name=Zuckerberg
    a%age=30
    b%name=James
    b%age=50
  4. 测试结果
    public class Test {
     public static void main(String[] args) throws IllegalAccessException, ClassNotFoundException, InstantiationException, NoSuchMethodException, InvocationTargetException {
         ExtendedObjectPoolFactory eopf=new ExtendedObjectPoolFactory();
         //初始化
         eopf.init("exobj.txt");
         System.out.println("文件里的对象:");
         System.out.println(eopf.getObject("a"));
         System.out.println(eopf.getObject("b"));
     }
    }
  5. 输出结果

    文件里的对象:
    此人的姓名: Zuckerberg,年龄: 30岁
    此人的姓名: James,年龄: 50

    总结与优化

    下面我们在回顾一下我们的整个流程

    • 编写简单对象类和对象容器类.
    • 通过txt文件配置对象的属性.
    • 创建对象容器类的对象(好像有点绕口),并初始化.

    接下来我们怎么优化呢,无非就是从性能实用性和扩展性这两个方向:

    • 从性能实用性上考虑,我们可以采用更高效的Java io Api,和使用xml代替txt文件等,这个就是仁者见仁智了.
    • 从扩展性上考虑,那设计模式再合适不过了,我们可以采用工厂和建造者等等设计模式去实现了,这个灵活性很高,需要对设计模式有一定的了解.

通过一步步的分析,你现在是不是感慨很多东西也不是特别的困难,那就不要停留在感慨了,赶快动起你发财的小手敲代码吧.


表情.jpg


另外本人对扯蛋有独到见解,欢迎前来本人博客扯蛋,我有酒,就差你的故事了