bearcat最新版json配置bean不能用了?

今天新建一个demo项目想用bearcat最新版本来管理组件。结果发现DI怎么用都不行,完全不能自动依赖。最后把example里面拿来测试,发现只有"scan": "app"才能工作,原来的配置bean方式DI就有问题。
"version": "0.4.18"
例子的complex_function_annotation里面js没有修改逻辑,加了一句console.log其init而已,改动只是把context.json"scan": "app"改成"beans": []的方式就不能工作了。

原来配置是这样,可以正常运行

{
    "name": "complex_function_annotation",
    "scan": "app"
}

我在每个bean构造函数加了一个log,结果如下:

roy@vmus:~/project/tmp/bc/bearcat-master/examples$ node app.js 
[init] car
[init] engine
[init] light
[init] wheel
[init] wheel
[init] light
[init] engine
[init] car
[2015-05-14 21:27:40.707] [INFO] bearcat - [app] Bearcat startup in dev with 13 ms
run engine...
light shine...
run wheel...
car run...

下面是我的修改:

{
  "name": "complex_function_annotation",
  "beans": [
    {
      "id": "car",
      "func": "./app/car"
    },
    {
      "id": "engine",
      "func": "./app/engine"
    },
    {
      "id": "light",
      "func": "./app/light"
    },
    {
      "id": "wheel",
      "func": "./app/wheel"
    }
  ]
}

结果就不能运行了,错误如下:

roy@vmus:~/project/tmp/bc/bearcat-master/examples$ node app.js 
[init] wheel
[init] light
[init] engine
[init] car
[2015-05-14 21:27:47.055] [INFO] bearcat - [app] Bearcat startup in dev with 11 ms

/home/roy/project/tmp/bc/bearcat-master/examples/complex_function_annotation/app/car.js:12
        this.$engine.run();
                     ^
TypeError: Cannot call method 'run' of null
    at Car.run (/home/roy/project/tmp/bc/bearcat-master/examples/complex_function_annotation/app/car.js:12:15)
    at /home/roy/project/tmp/bc/bearcat-master/examples/app.js:11:14
    at null.<anonymous> (/home/roy/project/tmp/bc/bearcat-master/lib/bearcat.js:136:3)
    at emit (events.js:92:17)
    at ApplicationContext.finishRefresh (/home/roy/project/tmp/bc/bearcat-master/lib/context/applicationContext.js:663:7)
    at /home/roy/project/tmp/bc/bearcat-master/lib/context/applicationContext.js:245:9
    at next (/home/roy/project/tmp/bc/bearcat-master/lib/beans/beanFactory.js:666:11)
    at next (/home/roy/project/tmp/bc/bearcat-master/lib/beans/beanFactory.js:687:4)
    at next (/home/roy/project/tmp/bc/bearcat-master/lib/beans/beanFactory.js:687:4)
    at next (/home/roy/project/tmp/bc/bearcat-master/lib/beans/beanFactory.js:687:4)

可以看到,修改context.json以后,所有bean的初始化bearcat还是正常的,但是DI就不工作了。
还是说不能用配置beans的方式了,只能scan?

标签: bug 反馈 bearcat
roytan 在 2015-5-14 21:46发布 分享到 weibo
14 回复
#1 roytan 2015-5-14 22:56 回复

找到原因了,原来使用json配置的方式,自动DI就失效了,得手动在json的每个bean里面指定DI的对象。这样就可以了:

"beans": [
    {
      "id": "bus",
      "scope": "singleton",
      "func": "./app/bus"
    },
    {
      "id": "car",
      "scope": "singleton",
      "func": "./app/car",
      "props": [
        {
          "name": "$bus",
          "ref": "bus"
        }
      ]
    }
  ]
#2 {2} roytan 2015-5-14 23:04 回复

OK,上个问题解决了,新问题又来了。文档上不是写的默认使用singleton么?这日志怎么显示构造函数被调用了多次?我手动给每个都加了this.$scope = "singleton";也没用

roy@vmus:~/project/tmp/t1$ node app.js
[init] car
[init] engine
[init] light
[init] wheel
[init] wheel
[init] light
[init] engine
[init] car
[2015-05-14 23:02:11.511] [INFO] bearcat - [app] Bearcat startup in dev with 13 ms
run engine...
light shine...
run wheel...
car run...
roytan 2015-5-14 23:11 回复

ok,测试出来了,这个应该是bug。用scan的方式,在js对象构造里面设置this.$scope = "singleton";没用。用json里面手动写beans的属性"scope": "singleton"有用。

这。。。
用json的方式没法自动DI,用js的方式又没法singleton。有点无解了。怎么没法正常使用。

@fantasyni 快修复一下吧

fantasyni 2015-5-14 23:15 回复

@roytan 哈哈,我明天仔细看看,修复下

#3 roytan 2015-5-14 23:40 回复

另外今天用的时候发现的几个问题,希望 @fantasyni 帮忙解答一下

1,什么样的js会在scan的时候认为是bearcat的bean?

2,接着第一个问题。我发现scan只能指定目录,测试发现这样的设置是错误的。这样用不好吗?这样很清晰,清楚的知道我自己的那些js用来做bearcat里面的bean了。比如可以避免有些不会用bearcat的同事在他自己的js文件构造里面写了些$的东西,就被认为是bean导入了,然后一堆错误。应该在scan里面指定目录和文件都可以。

"scan": [
      "./app/car.js",
      "./app/bus.js"
    ]

3,scan使用js的方式很简单好用。但是DI怎么用带namespace的对象呢?this.$n1:o1 = null 这样来使用n1命名空间的o1?我测试了两种方法都没法用this.$n2:bus.run(); this["$n2:bus"].run(); 而奇怪的是,我在n2和n3里面都有bus,结果n1里面car用this.$bus.run();可以跑,发现是用的n2里面的bus。 也就是说在magic javaScript objects方式下,DI配合namespace是不起作用的?

#4 roytan 2015-5-14 23:57 回复

4,能否把bearcat使用的$xxx关键字写个文档。刚刚又重新读了一次,分布在各个文档中。比如$scope, $Tnum, $cid等等。因为从语义上来讲这些内置$xxx和$engine这中用户变量名看不出来任何区别。那么我们使用者就会头痛哪些变量名和bearcat冲突。

#5 roytan 2015-5-15 11:19 回复

5,因为singleton无效的bug,magic javaScript objects方式下给bean构造传参数也没法用。。。

#6 roytan 2015-5-15 11:20 回复

基本上,目前版本bearcat处于不可用状态

#7 {1} roytan 2015-5-15 13:56 回复

现在我这里只能完全手动配置json先用着,不用任何DI,全部显式getBean

fantasyni 2015-5-15 19:38 回复

@roytan
1:magic javaScript objects 下所有关键字的含义都在这里,既可以用 json 配置的形式,也可以直接 内嵌到对象中自描述

2:被bearcat自动扫描出来认为是bean的情况
一种就是老的形式

exports = {
   id: "xxx",
   func: xxx
}

一种就是exports一个function

而这个function是带上 magic 属性的,比如 $id

这个是自动扫描的场景

3:magic 下 namespace 要这样子用

this.$Ncar = "app:car";

例子在 context namespace

#8 {1} fantasyni 2015-5-15 19:48 回复

1:我在 complex_function_annotation 上传了 通过 beans 配置的 context-config.json

同时在 beans 和 magic javascript object 情况下,beans 的配置覆盖magic javascript object的,beans 相当于配置文件,可以修改,而代码就相当于默认值一样

你上面的应该是 beans 没有配置,默认就是 singleton,然后 magic javascript object 虽然配置了 prototype,但是被 beans 覆盖了

2:scan 的语义就是扫描文件夹吧,如果是单个文件,还是用 beans 进行配置

roytan 2015-5-16 23:32 回复

嗯,感谢回答了很多问题,清晰了很多。

附上几个问题:
1, http://bearcatjs.org/guide/magic-javaScript-objects-in-details.html 这里不全吧,比如你说的this.$Ncar这种东西里面就没写。$Nxxx, $Txxx这种东西还有多少呢?
个人觉得这种bearcat系统关键字和用户自定义DI变量都用$开头从根本上就是冲突的,bearcat定义的所有系统配置变量都可以用比如$$开头,这样可以用户的$就区别开了。举例来讲,cid,mid这种东西很多原来系统中都有这种变量名的,比如我原来的一个项目里面。cid,sid,mid都有,这样很容易有歧义。

2,你确认magic javascript object是默认singleton?刚刚拿了github最新你的代码"version": "0.4.18",跑demo。只在构造函数加些console.log('Car init'); 你看看结果:

Car init
Engine init
Light init
Wheel init
Wheel init
Light init
Engine init
[2015-05-16 23:12:59.461] [INFO] bearcat - [app] Bearcat startup in dev with 45
ms
Car init
run engine...
light shine...
run wheel...
car run 2 ...

即使我给每个js手动都改成了this.$scope = "singleton";仍然结果一样,被初始化多次。

var contextPath = require.resolve('./' + example_dir + '/context.json');
{
    "name": "complex_function_annotation",
    "scan": "app"
}

这是你的运行环境没错吧,不存在beans覆盖js $的问题吧?这问题就在构造函数加一个log就明明白白了,发版本前好歹测试一下吧。为什么我都这样明确指出了bug,为什么都不愿意加一句log看一下客观结果呢。。。。。。

#9 roytan 2015-5-16 23:55 回复

哦,是不是这样子的,这个函数

var Engine = function() {
    console.log('Engine init');
    this.$id = "engine";
    this.$scope = "singleton";
}

这个函数我认为是对象的构造函数,但是在bearcat的magic javascript object里面认为不是,而Engine.prototype.init才是bearcat认为的构造函数?

因为magic javascript object方式的加载bean,那么必然Engine = function()会被调用1+次,即使是singleton,该函数还是会被调用2次。

那么这个坑就更大了,大家普遍都会认为Engine = function() 是构造函数,然后在里面写很多自己的初始化代码。结果却不知道bearcat后台却要该函数调用两次。那么文档一定要写清楚,不能在Engine = function()构造函数里面写任何逻辑代码,只能定义变量。所有初始化代码都必须放init里面。不然这两次构造肯定是天坑!!!

#10 {3} roytan 2015-5-17 00:05 回复
"name": "complex_function_annotation",
    "beans": [{
        "id": "car",
        "func": "./app/car",
        "scope2": "prototype",

这里面的"scope2"是什么东西,和"scope"有什么区别?笔误还是隐藏属性?

fantasyni 2015-5-17 12:37 回复

@roytan
1:那个文档里面确实 $N 这种没写上,马上补上
2:后面版本的bearcat对function里面的 $ 解析是通过 new Function() 的形式,那么 new 的过程中就会执行 构造函数里面的内容,这样子的好处就是 $ 可以支持各种形式,之前是字符串解析的,会存在不少问题,这个文档也说明下

3:scope2 是因为 json 不支持注释,方便测试用的

roytan 2015-5-17 13:22 回复

@fantasyni
2, 我猜的也是引用分析function带来的问题。理论上,都已经new Function()了,对象都有了,如果是singleton那么没有必要再new一次了。但是这又和lazy冲突了。那么后面的问题又来了,自动DI到底是在哪个时刻注入的呢?是在第二次构造之后呢还是init或者其它函数用到$xx的时候才注入?通过这几天使用bearcat的感觉,json配置bean和magic js是完全两种不同的运行方式,从构造到使用到生命周期都有很多区别。光看目前的文档感觉两种方式仅仅是写法不同,但是测试使用结果却大不一样。这种歧义我感觉需要你专门写一篇文档来介绍两种运行方式的区别。

3,我现在都不用.json当配置,用.js。可以注释,exports一个json对象就行了 ,方便许多。

fantasyni 2015-5-17 19:57 回复

@roytan
1:要想用老方式,就是采用字符串解析function
在 createApp 的时候,设置 BEARCAT_FUNCTION_STRING 为 true 就没这个问题了

#11 {5} roytan 2015-5-17 22:07 回复

这magic $用起来真是步步惊心啊。。。
又一个我看不懂的:

var Car = function(value) {
    console.log('Car constructor');
    this.$id = "car";
    this.$init = "init";
    this.$scope = "singleton";
    this.$lazy = true;
    //this.$scope = "prototype";
    //this["$engine"] = null; // use []
    this.$engine = null;
    //this.$wheel = null;
    this.$light = null;
    var wheelName = "$wheel";
    this[wheelName] = null; // use variable
    this.num = num++;
    this.$Tvalue = value;
};

var car = bearcat.getBean('car',100); // get bean
var r = car.run(); // call the method

在加了this.$Tvalue以后,

var wheelName = "$wheel";
this[wheelName] = null; // use variable

这样就运行报错。改成

this.$wheel = null;

就运行正常。话说这$Tvalue和$wheel两个不同的变量有什么关系?怎么就会导致this[wheelName] 出问题呢?

fantasyni 2015-5-18 08:54 回复

@roytan
你这里配置改了?

设置 BEARCAT_FUNCTION_STRING 为 true ?

roytan 2015-5-18 09:37 回复

没有设置function string,其它什么都没改就是在你的example里面加了一个Tvalue而已

fantasyni 2015-5-18 16:41 回复

@roytan 因为你这里 function 有 参数 value,那么只能采用 function string 的形式,不然 new funciton 是不知道 arguments 的信息的,所以那种复杂的方式就不行了

fantasyni 2015-5-18 16:43 回复

@roytan 这块逻辑实现主要在这里 resolveFuncAnnotation

roytan 2015-5-18 23:01 回复

@fantasyni
magic $现在的问题是,不知道什么时候哪种写法会带来什么问题。其实你看我这帖子里面的大部分问题,都是跑的example的代码加点调试而已。结果就暴露出很多与文档不符的情况,文档都是讲$可以这样写也可以那样写,但是却没有写什么不能写。比如两次构造,比如参数value和this[wheelName] = null;的冲突,这是文档上找不到的,除非自己去测试去看源码,学习使用成本有点高。

这是我第二次尝试使用magic $方式来用bearcat,不过就这样简简单单调试一下就发现这么多问题,于是我又不得不用最原始的json beans的方式来使用了,起码能稳定按预期来运行

#12 roytan 2015-5-17 22:15 回复

继续步步惊心

//this.$Tvalue = value;
this.Dvalue = value;

输出

car = { '$id': 'car',
  '$init': 'init',
  '$scope': 'singleton',
  '$lazy': true,
  '$engine':
   { '$id': 'engine',
     '$init': 'init',
     '$scope': 'singleton',
     '$lazy': true },
  '$wheel':
   { '$id': 'wheel',
     '$init': 'init',
     '$scope': 'singleton',
     '$lazy': true },
  '$light':
   { '$id': 'light',
     '$init': 'init',
     '$scope': 'singleton',
     '$lazy': true },
  num: 1,
  Dvalue: 100 }

发现不按文档写的use the attribute with the prefix $T to specify the variable to be injected into the constructor 我随便写一个Dvalue一样可以使用。那用this.$Tvalue和this.Dvalue有区别在哪里?

#13 fantasyni 2015-5-18 08:52 回复

在一个版本中,对于配置的注入,可以不加 $T ,通过 value 的 ${car.num} 来判断

#14 roytan 2015-5-18 09:42 回复

代码都贴了,手写的Dvalue,什么$都没有

回到顶部