如何配置一个 IocBean

Jul 10, 2017 10:38:44 AM

作者:zozohwendal

使用Json

NutIoc 包含一个 JsonLoader或者N个IocLoader或者一个ComboIocLoader

  1. Ioc ioc = new NutIoc(new JsonLoader("path/to/mybeans.js")); //示意

JsonLoader 从一个 JS 文件中加载一组 IocBean 的配置信息,这个JS文件的格式通常为

  1. {
  2. "对象名称" : {
  3. type : "对象类型",
  4. parent : "被继承的对象名称",
  5. events : {
  6. fetch : "触发器的类型或者函数名",
  7. create : "触发器的类型或者函数名",
  8. depose : "触发器的类型或者函数名"
  9. },
  10. args : [
  11. 参数1 参数2 ...
  12. ],
  13. fields : {
  14. "字段名称1" : 字段值1 ,
  15. "字段名称2" : 字段值2 ,
  16. ...
  17. },
  18. factory : "xxx.yyy.zzz#create" //工厂类#工厂方法
  19. }
  20. }

比如:

  1. var ioc = {
  2. bean : {
  3. fields : {
  4. x: 100,
  5. y: 80
  6. }
  7. },
  8. myBean : {
  9. // 对象的 Java 类型
  10. type : 'demo.MyBean',
  11. // 如果声明,表对象的属性从 "bean" 对象继承
  12. // 你可以看到 "bean" 对象在上面声明了两个属性 x:100, y:80
  13. // 那么你的 bean 也会继承这个属性。当然你在自己的 fields 字段里
  14. // 可以进行覆盖。同理,任何属性,比如 type, singleton, events, args
  15. // 都是可以在 parent 里声明,以便做到最大限度的复用的。
  16. parent : 'bean',
  17. // 不声明,默认为 true
  18. singleton : true,
  19. // 这里声明对象的三种事件。事件的处理函数可以是一个接口,也可以是自身的
  20. // 一个方法。
  21. events : {
  22. // 当这个对象被创建后,如果你想做点特殊的操作,又不好在构造函数里做
  23. // 你可以实现一个 IocEventTrigger<T>,容器在创建这个对象后
  24. // 会调用这个接口的唯一方法
  25. create: "demo.MyBeanCreateTrigger",
  26. // 如果你 MyBean bean = ioc.get(MyBean.class,"myBean"); 之后都要再调用一个
  27. // 函数来进行一些必要操作,比如计数之类的,你可以声明 "fetch" 事件
  28. // 下面的声明表示容器交还给你前,会调用一下 bean.onFetch()
  29. // 当然你的对象本身要有一个函数 "onFetch()" 它不能有参数
  30. fetch : "onFetch",
  31. // 当对象被容器销毁时触发。
  32. depose : "demo.MyBeanDeposeTrigger"
  33. },
  34. // 构造函数参数,即对象要有对应的构造函数,否则抛错
  35. args : [ 'I am great' ],
  36. // 详细声明每个字段的值
  37. fields : {
  38. name : 'XiaoBai',
  39. number : 49
  40. }
  41. }
  42. };

你如果不喜欢 JSON 怎么办?

我很喜欢 JSON,因为它语法轻巧。当然,我不能保证你也很喜欢 JSON,因为你可能会说:

  • 没有很好的 JSON 编辑器 — 如果是这样,我推荐你试试 Eclipse 自带的 Javascript 编辑器
  • 我更喜欢 XML,我不喜欢大括号
  • 我就是讨厌 JSON
    那么,你想自己规定自己的配置文件格式吗? 你可以定义一个比 JSON 更酷的配置文件语法,当然你得多写一点点代码,解析你的配置文件。但是你就想做点很酷的事情,不是吗?

Nutz.Ioc 提供了一个扩展点:org.nutz.ioc.IocLoader 接口。实际上 JSON 的配置文件语法,不过是我预先为这个接口写的一个实现,所以你当然也可以写一个,请注意 Nutz.Ioc 接口是如何被构建的:

  1. Ioc ioc = new NutIoc(new JsonLoader("文件路径"));

我提供的 JsonLoader 没有任何“特殊待遇”,它和你自己要实现的 IocLoader 地位是完全一样的,你完全可以这么写:

  1. Ioc ioc = new NutIoc(new MyIocLoader());

只要你正确的实现了 IocLoader 接口,如何持有对象,如果解释对象的语义,都由 Nutz.Ioc 的标准实现流程负责,你完全不用操心。

你可能还有一个问题:“那么 IocLoader 接口实现起来复杂吗?

我可以负责任的告诉你,虽然那不是极其简单,但是绝对不复杂。你只要理解下面这个知识即可:

在 Nutz.Ioc 定义一个对象的数据结构是怎样的?

在 org.nutz.ioc.meta.IocObject 类中,你如果拿到它的源代码,或者是 JDoc,它描述了在容器中一个对象的全部信息,你会发现它其实也简单:

  1. public class IocObject {
  2. // 对象的 Java 类型
  3. private Class<?> type;
  4. // 声明对象是否为单例
  5. private boolean singleton;
  6. // 对象监听何种事件,对应有
  7. // "fetch" - 每次对象被 ioc.get 的时候,触发
  8. // "create" - 当且仅当对象被 new 的时候触发
  9. // "depose" - 当对象被容器销毁时触发
  10. private IocEventSet events;
  11. // 对象构造函数的参数列表
  12. private List<IocValue> args;
  13. // 对象的字段
  14. private List<IocField> fields;
  15. // 对象的缓存范围,默认为 "app"
  16. private String scope;
  17. // 省略所有的 getter 和 setter 函数

事件集合 IocEventSet

描述了一个对象可以监听的事件。三个属性分别表示:

  • create: 对象创建时触发
  • fetch: 对象获取时触发
  • depose: 对象销毁时触发
    它们的值:

  • 可以是一个函数名,也可以是一个 org.nutz.ioc.IocEventTrigger 的实现类全名

  • 如果 是函数,那么这个函数就是对象内的一个非静态 public 的函数,而且不能有参数
  • 如果是 IocEventTrigger 的实现类,你的实现类必须有一个 public 的默认构造函数

值 IocValue

描述了对象的一个值,这个值可以是构造函数的参数,也可以是一个字段的值。 它由两个属性,一个是值的类型,另外一个是 value。

赋值约定:

  • 如果 type 是 "null",则值会被认为是 null
  • 如果 value 是 字符串,数字,布尔,那么 type 必须为 "normal"或 null
  • 如果 value 是 数组, Collection 或 Map,那么类型也必须是 "normal"或 null,Ioc 容器的实现类 会深层递归集合的每个元素。集合内的每个元素的值也可以是 IocValue,规则符合本约定
  • 如果 value 是 IocObject,则表示这个值是一个内部匿名对象,type 必须为 "inner" 或者 null
  • 如果 value 是字符串,表示另外一个对象的名称,type 必须是 "refer"
  • 如果 value 是字符串,表示一个环境变量,type 必须是 "env"
  • 如果 value 是字符串,表示一个文件路径,type 必须是 "file"
  • 如果 value 是字符串,表示一个 Java 调用,type 必须是 "java",具体值的语法,请参看 JavaValue 类 的 JDoc,当然 Ioc 容器来解析执行它,不需要 IocLoader 操心 说明
  • 你的 ValueProxyMaker 可以扩展这个约定

字段 IocField

描述了一个对象的字段,两个属性分别表示字段名,和字段值

实现你的加载器

你的 IocLoader 的实现类需要实现三个方法:

  1. public interface IocLoader {
  2. /**
  3. * @return 配置信息里所有对象的名称
  4. */
  5. String[] getName();
  6. /**
  7. * 每次这个函数被调用,则要构造一个新的 IocObject
  8. *
  9. * @param name
  10. * @return
  11. * @throws ObjectLoadException
  12. */
  13. IocObject load(String name) throws ObjectLoadException;
  14. /**
  15. * @param name
  16. * @return 配置信息里是否存在一个对象
  17. */
  18. boolean has(String name);
  19. }

最后

没什么要说的了,充分发挥你的想象力吧,如果你愿意,将配置信息放在 PDF 里,放在 excel 表格里都是可以的 如果你完成了一个IocLoader,不妨分享出来,我们将收录到 http://github.com/nutzam/nutzmore/

附:已经可用的IocLoader

  • 使用Json作为配置文件 org.nutz.ioc.loader.json.JsonLoader
  • 使用XML作为配置文件 org.nutz.ioc.loader.xml.XmlIocLoader
  • 使用注解作为配置文件 org.nutz.ioc.loader.annotation.AnnotationIocLoader
  • 使用Map作为配置文件 org.nutz.ioc.loader.map.MapLoader
  • 混合使用多种配置?一样可以! org.nutz.ioc.loader.combo.ComboIocLoader

本页面的文字允许在知识共享 署名-相同方式共享 3.0协议GNU自由文档许可证下修改和再使用。

原文: http://nutzam.com/core/ioc/ioc_loader.html