john's tech blog

hope is coming


  • 首页

  • 标签

  • 归档

scala_abscractoverride

发表于 2017-03-31 | 更新于 2019-05-07

abstract override

前几天在看scalatra源码时,看到FileUploadExample这个实例类时,竟然提示我如下错误:

error: class FileUploadExample needs to be a mixin, since method initialize in trait HasMultipartConfig of type => Unit is marked abstract and override

我在HasMultipartConfig中可以看到如下定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
abstract override def initialize(config: ConfigT) {
super.initialize(config)

providedConfig foreach { _ apply config.context }
}
```

这个initialize其实是定义在Initializable这个trait中的:

```java
trait Initializable {

/**
* A hook to initialize the class with some configuration after it has
* been constructed.
*
* Not called init because GenericServlet doesn't override it, and then
* we get into https://lampsvn.epfl.ch/trac/scala/ticket/2497.
*/

def initialize(config: ConfigT)
}

也就是说HasMultipartConfig 中abstract override了它,那么为什么会报错呢?搜索了相关资料,有如下答案:

My understanding is that while the error message may be confusing, the behaviour is correct. foo is declared as abstract override in StackingTrait, and thus in any concrete class that mixes StackingTrait there must be a concrete (not marked as abstract) implementation of foo before StackingTrait (relative to the linearization order). This is because super refers to the trait just before in the linearization order, so there definitely needs to be a concrete implementation of foo before StackingTrait is mixed in, or super.foo would be nonsensical.

When you do this:

1
2
3
class Impl extends Base with StackingTrait {
def foo {}
}

the linearization order is Base <- StackingTrait <- Impl. The only trait before StackingTrait is Base and Base does not define a concrete implementation of foo.

But when you do this:

1
2
3
4
traitImplHelper extends Base {
def foo {}
}
class Impl extends ImplHelper with StackingTrait

参考资料:
Scala: Trait Mixin with Abstract Base Class

angular1.5.8源码解析之decorator原理

发表于 2017-03-28 | 更新于 2020-03-24

angularjs装饰器的使用

我们定义一个模块,并且配置一个configBlocks

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
angular.module('myapp',[]).config(function($provide){
$provide.decorator('$log',function($delegate){
angular.foreach(['log','debug','info','warn','error'],function(o){
$delegate[o] = decoratorLogger($delegate[o]);
});
function decoratorLogger(orignalFn){
return function(){
var args = Array.prototype.slice.apply(arguments);
args.unshift(new Date().toISPString());
originalFn.apply(null,args);
};
}
});
});

//调用log函数加上时间戳
angular.element(document).injector().get('$log').log('hello')

此处可以有几个疑问:

  1. config函数做了什么?
  2. decorator函数又做了什么?
  3. angular.element(document)为什么能获取injector?

config函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 /*
方法内部调用configBlocks['push'](['$injector','invoke',arguments])
然后返回moduleInstance,config就是一个返回moduleInstance的函数
*/

var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
//此处就是传入配置块
if (configFn) {
config(configFn);
}
function invokeLater(provider, method, insertMethod, queue) {
if (!queue) queue = invokeQueue;
return function() {
queue[insertMethod || 'push']([provider, method, arguments]);
return moduleInstance;
};
}

模块的config函数就是把参数configBlocks放入configBlocks数组中,然后在loadModules的时候
调用runInvokeQueue,获取$injectorProvider也就是instanceInjector后调用invoke函数,
传入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

### $provide.decorator函数

```js
function decorator(serviceName, decorFn) {
var origProvider = providerInjector.get(serviceName + providerSuffix),
orig$get = origProvider.$get;//是个字符串和函数的数组

origProvider.$get = function() { //相当于重新定义了原来的$get方法
var origInstance = instanceInjector.invoke(orig$get, origProvider);
return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
};
}
```

### $LogProvider
```js
$provide.provider({
$log: $LogProvider,
});

function $LogProvider() {
var debug = true,
self = this;
this.$get = ['$window', function($window) {

return {
log:consoleLog('log')
//省略部分代码
}
}]
}
```
执行decorator方法的时候先获取原来的$logProvider和它的$get属性,然后重新赋值$logProvider的
$get属性,把原来的$get属性放入新的$get函数内。

最终调用instanceInjector的getService方法获取,内部先从providerCache中获取后,再调用
对应$logProvider的新的$get函数,函数内部首先调用原先保存的旧的$get属性,获取原来的```{log:consoleLog('log')}```,
然后调用decorFn,传入```{$delegate: origInstance}```,最后就是对原来的$log实例的属性函数做了修改。

装饰器设计模式就是如此奇妙!

文章末尾彩蛋:
### $rootElement.data函数

在angular调用```doBootstrap```启动函数的时候,内部会调用```element.data('$injector', injector);

把创建好的instanceInjector放入element的data缓存中,所以能直接调用injector()函数,此部分的
源码设计我们会在之后的文章中进行剖析。

angular_provider

发表于 2017-03-27 | 更新于 2019-05-07

angular provider 注入

1
2
3
4
5
6
7
8
angularModule('ng', ['ngLocale'], ['$provide',
function ngModule($provide) {
// $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
$provide.provider({
$anchorScroll: $AnchorScrollProvider
});
}
]);

注意 ['$provide',function ngModule($provide){}] 这段代码,
在定义angular.module方法时 就加入了configFn参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
* @param {Function=} configFn Optional configuration function for the module. Same as
* {@link angular.Module#config Module#config()}.
* @returns {angular.Module} new module with the {@link angular.Module} api.
*/
return function module(name, requires, configFn) {

//configFn有可能就是['$provide',function($provide){}]
//config 就是调用configBlocks[insertMethod || 'push']([provider, method, arguments]);
//这里的arguments就是configFn
if (configFn) {
config(configFn);
}
}
```

config定义如下:

```js
/*返回一个方法
方法内部调用configBlocks['push'](['$injector','invoke',arguments])
然后返回moduleInstance

config就是一个返回moduleInstance的函数
*/
var config = invokeLater('$injector', 'invoke', 'push', configBlocks);

function invokeLater(provider, method, insertMethod, queue) {
if (!queue) queue = invokeQueue;
return function() {
queue[insertMethod || 'push']([provider, method, arguments]);
return moduleInstance;
};
}

configBlocks push了[‘$injector’,’invoke’,[‘$provide’,function($provide){}]]

然后在bootstrap方法中createInjector

createInjector中再调用loadModules

loadModules中runInvokeQueue(moduleFn._configBlocks); 调用providerCache.$injector 返回

{
    invoke: invoke,
    instantiate: instantiate,
    get: getService,
    annotate: createInjector.$$annotate,
    has: function(name) {
      return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
    }
  }

继续调用invoke函数 -> injectionArgs -> getService(key) 返回$provide 对象

AngularJs自定义服务

node_proxy

发表于 2017-03-26 | 更新于 2019-05-07

node proxy代理中间件

今天在研究node-proxy-middleware这款代理插件,

用于在browsersync使用,如下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const conf = require('./gulp.conf');
var url = require('url');
var proxy = require('proxy-middleware');
module.exports = function () {

var proxyOptions = url.parse('http://localhost:8089/api');
proxyOptions.route = '/api';

var proxyOptions1 = url.parse('http://localhost:8089/api1');
proxyOptions1.route = '/api1';
return {
server: {
baseDir: [
conf.paths.tmp,
conf.paths.src
],
middleware: [proxy(proxyOptions),proxy(proxyOptions1)]
},
open: true
};
};

route下的所有请求都会代理到本地8089端口,如果不配置route那么所有请求都会走代理,看代码:

1
2
3
4
5
6
7
8
9
10
if (typeof options.route === 'string') {
if (url === options.route) {
url = '';
} else if (url.slice(0, options.route.length) === options.route) {
url = url.slice(options.route.length);
//一个新的字符串。包括字符串 stringObject 从 start 开始(包括 start)到 end 结束(不包括 end)为止的所有字符。
} else {
return next();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
/*
如果p1 是 / 结束的
而且p2是/ 开始的
那么就把p2开始的斜线去掉
*/

function slashJoin(p1, p2) {
var trailing_slash = false;

if (p1.length && p1[p1.length - 1] === '/') { trailing_slash = true; }
if (trailing_slash && p2.length && p2[0] === '/') {p2 = p2.substring(1); }

return p1 + p2;
}

linux_php

发表于 2017-03-25 | 更新于 2019-05-07

ubuntu14.04 安装php

###先安装apache2:

sudo apt-get install apache2

安装php5:

sudo apt-get install php5

安装mysql:

sudo apt-get install mysql-server

查看ip地址:

ifconfig -a

查看ssh是否启动

sudo ps -e |grep ssh

ubuntu 终端修改中文乱码

修改Ubuntu的配置文件/etc/default/locale
将原来的配置内容修改为
LANG=”en_US.UTF-8″
LANGUAGE=”en_US:en”
再在终端下运行:
$ locale-gen -en_US:en
注销或重启后,Ubuntu Server真正服务器实体终端就恢复成了英文的语言环境。
所以,此方法不是真正意义上的中文化,而是恢复英文的默认编码

参考资料:
Ubuntu Server 命令行下的默认语言 中文乱码

1…272829…47

John

232 日志
43 标签
GitHub Twitter
欢迎关注我的公众号:沉迷Spring
© 2023 johnwonder
由 Hexo 强力驱动 v3.2.0
|
主题 – NexT.Pisces v7.1.1
|
0%