美文网首页
Blade - 1.4版本重大更新

Blade - 1.4版本重大更新

作者: 琼珶和予 | 来源:发表于2019-04-08 22:27 被阅读0次

  在1.4版本之前,Blade有一个很大的弊端,就是注入源和注入目标有耦合。其中注入目标必须有一个@Module的注解,这个导致同一个注入目标不能被复用。我举一个简单的例子:


  这两个页面有一部分相同的内容需要加载,所以对于注入目标来说,数据提供者(数据源)都是同一个。但是在1.4版本之前,每个注入目标必须带一个@Module注解,会导致在不同的界面,针对相同的一部分内容,会有一部分代码会被重新的书写,这种问题非常不好。
  而在1.4版本开始,去掉了@Module注解,如此就不会死板从一个注入源里面去寻找数据,换句话说,在注入的时候,我们给的是哪个数据源,注入时就从哪个数据源去寻找数据。而1.4版本是怎么实现的呢?接下来我们将简单的看一下整个Blade实现原理。
  基本使用请参考:Blade - 基本使用

1. Provider接口

  从1.4版本开始新增了一个接口--Provider接口,在编译时,每个Context都会对应生成一个叫Context类名ProviderImpl名字的类,这个类实现了Provider接口。然后在这个生成类里面,进行了数据的存储,主要是将对应的Context数据放在这个生成类的一个HashMap成员中。例如,如下的Context

public class Context {
    @Provides(deepProvides = true, value = "contextString1")
    public Demo string1 = new Demo();
    @Provides(value = "contextString2")
    public String string2;
    @Provides(value = "int")
    public int code = 2;
}

  对应生成的ProviderImpl类是:

public class ContextProviderImpl implements Provider {
  private Map<String, Object> pathMap;

  public ContextProviderImpl() {
    pathMap = new HashMap<>();
  }

  @Override
  public Object find(String id) {
    return pathMap.get(id);
  }

  @Override
  public void put(Map<String, Object> map) {
    pathMap.putAll(map);
  }

  public void init(Context source) {
    pathMap.put("contextString1", source.string1);;
    pathMap.put("contextString2", source.string2);;
    pathMap.put("strings", source.string1.string3.strings);;
    pathMap.put("demoDemoString", source.string1.string3.demo.demoDemoString);;
    pathMap.put("demoString", source.string1.string3);;
    pathMap.put("com.example.pby.injectdemo.demo.Demo", source.string1.string3.demo);;
    pathMap.put("demo3String", source.string1.string3.string);;
    pathMap.put("java.lang.String[]", source.string1.string3.string1);;
    pathMap.put("int", source.code);;
  }
}

  在生成的ProviderImpl类中,主要实现了Provider的两个方法--put方法和find方法。
  其中put方法表示可以将我们自定义的某些数据存在一个Map里面,然后在注入的时候可以从这个数据源来寻找数据。这样做的好处就是,一个注入目标没必要再次定义一个Context类,只需要在基类里面定义一个Context类就行了,然后子类只需要维护一个Map数组就OK了。
  find方法在这里就没必要解释了,很明显就是从存储数据的Map去寻找数据,这个方法在生成的Inject类里面会被调用。
  在生成的ProviderImpl类中,还有一个方法比较重要,那就是init方法。这个方法主要将Context里面的数据放在Map数组里面去,需要注意的是,这里进行了递归,也就是说将子节点的数据也放在了Map数组里面的。

2. Inject类

  在整个框架当中,每个注入目标都会生成一个Inject类,而对注入目标的数据初始化就是这个Inject类里面完成的。我们来看看一个例子:

public class MainActivity_Inject {
  public void inject(MainActivity target, Provider source) {
    target.strings = (java.lang.String[])(source.find("strings"));
    target.demoDemoString = (java.lang.String)(source.find("demoDemoString"));
    target.pby = (java.lang.String)(source.find("pby"));
    target.string1 = (java.lang.String)(source.find("demo3String"));
    target.strings1 = (java.lang.String[])(source.find("java.lang.String[]"));
    target.code = (int)(source.find("int"));
  }
}

  在1.4版本中,彻底的重构了Inject类的结构。在上面的例子当中,我们会发现数据源参数直接是一个Provider接口,初始化代码调用的是Provider接口的find方法。所以从这里,我们可以看出来,在1.4版本中,Context不再持有数据,进而让Provider接口的实现类来持有数据。

3. Blade类

  Blade类也进行了重构,其中,重构之后的代码如下:

public class Blade {

    public static void inject(Object target, Object source) {
        inject(target, source, null);
    }

    private static void inject(Object target, Map<String, ?> extraMap) {
        inject(target, new EmptyProviderImpl(), extraMap);
    }

    public static void inject(Object target, Object source, Map<String, ?> extraMap) {
        try {
            Object targetObject = Class.forName(target.getClass().getName() + "_Inject").newInstance();
            Provider sourceObject = (Provider) Class.forName(source.getClass().getName() + "ProviderImpl").newInstance();
            if (extraMap != null && !extraMap.isEmpty()) {
                sourceObject.getClass().getMethod("put", Map.class).invoke(sourceObject, extraMap);
            }
            sourceObject.getClass().getMethod("init", source.getClass()).invoke(sourceObject, source);
            targetObject.getClass().getMethod("inject", target.getClass(), Provider.class).invoke(targetObject, target, sourceObject);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

  在Blade类里面主要做了如下几件事:

  1. 根据传递进来的注入源找到对应的ProviderImpl类, 然后创建它的对象,初始化数据。
  2. 根据传递进来的注入目标找到对应的Inject类,然后调用它的inject方法,同时将ProviderImpl对象传递进去。

  经过如上两步就完成了整个注入过程。

相关文章

  • Blade - 1.4版本重大更新

      在1.4版本之前,Blade有一个很大的弊端,就是注入源和注入目标有耦合。其中注入目标必须有一个@Module...

  • 千变远程通知栏

    【】 〖千变有新版本哦〗 〔请立即更新1.4版本哦!〕

  • 2018-06-23

    版本2版本 更新内容发现新版本 1.4 充值通道恢复 新增功能专区 ...

  • 2018-07-14

    版本1版本 更新内容发现新版本 1.4 充值通道恢复 新增功能专区 ...

  • 哈奇更新

    【更新内容】 哈奇plus(1.7内测) 邀你体验! 【更新内容】【软件版本】3.7.8【软件版本】【大小】1.4...

  • PyTorch中Transformer模型的使用

    PyTorch最近版本更新很快,1.2/1.3/1.4几乎是连着出,其中:1.3/1.4版本主要是新增并完善了Py...

  • Kotlin升级1.5版本synthetic引发的血案分析

    场景重现 因为项目里面Kotlin版本还停留在1.4,看到1.5版本更新记录[https://Kotlinlang...

  • mengmei - 草稿

    /mengmei| 最新版本=1.4| 更新说明=9月29日修复,请点击更新下载最新版本观看| 下载地址=http...

  • iapp远程更新例子

    版本判断2版本判断 截取内容软件名称:星星博客【换行】软件大小:1.4MB【换行】软件版本:1.1.0【换行】更新...

  • 更新fabric 1.4版本

    更新fabric到1.4版本 刚开始接触区块链,跟着网上的教程搭建hyperledger fabric ,下载的是...

网友评论

      本文标题:Blade - 1.4版本重大更新

      本文链接:https://www.haomeiwen.com/subject/dssnbqtx.html