scalatra是如何加入servlet的
1 | private def mountServlet( |
1 | private def mountServlet( |
在scalatra启动时,会mount多个servlet ,但是servletContext并没有定义mount方法,那为什么servletContext能调用mount方法呢?
这就是scala隐式转换的魅力。
在看scalatra源码时,看到在trait ServletApiImplicits定义了如下代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22// 用来调用mount
implicit def enrichServletContext(servletContext: ServletContext): RichServletContext =
RichServletContext(servletContext)
```
在RichServletContext中定义了mount方法:
```java
/**
* Mounts a handler to the servlet context. Must be an HttpServlet or a
* Filter.
*
* @param handler the handler to mount
*
* @param urlPattern the URL pattern to mount. Will be appended with `\/\*` if
* not already, as path-mapping is the most natural fit for Scalatra.
* If you don't want path mapping, use the native Servlet API.
*
* @param name the name of the handler
*/
def mount(handler: Handler, urlPattern: String, name: String): Unit = {
mount(handler, urlPattern, name, 1)
}
看如下代码:
implicit def enrichServletContext(sc: String): RichServletContext =
RichServletContext(sc)
case class RichServletContext(sc:String){
def mount():Unit = {
println(sc)
}
}
val ss = "sssss"
ss.mount
在这篇文章中就提到了转换被方法调用的对象
这篇Scala thread-safety question回复
提到如下代码:
1 | object Class { |
“object” initialization is thread safe. “mutable.List” is not thread
safe and needs to be synchronized.
然后我们自己定义一个object用于测试:
1 | object TestObject { |
用以下代码测试:
1 | object TestObjectInitializer extends App { |
打印如下代码:
1 | propinitialize |
propinitialize只执行一次。
参考资料:
Scala Singleton Object with Multi-threading
How to make object (a mutable stack) thread-safe
1 |
|
有如下一段代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14// 创建myModule模块、注册服务
var myModule = angular.module('myModule', []);
myModule.service('myService', function() {
this.my = 0;
});
// 创建herModule模块、注册服务
var herModule = angular.module('herModule', []);
herModule.service('herService', function() {
this.her = 1;
});
// 加载了2个模块中的服务
var injector = angular.injector(["myModule","herModule"]);
alert(injector.get("myService").my);
alert(injector.get("herService").her);
我们先看看service方法是如何定义的
1 |
|
如果是service的话,那么此处的delegate就是外部定义的service方法: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 function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
}
```
再按一定的顺序调用如下方法:
```js
//factoryFn 就是['$injector',function(){$injector}{}]
function factory(name, factoryFn, enforce) {
return provider(name, {
$get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
});//注意 enforceReturnValue只是返回一个方法而已
//如果enforce 为true 或者undefined
//那么factoryFn 最终 被instanceInjector.invoke(factory, this);
}
//provider_就是上面定义的{ $get: function }对象
function provider(name, provider_) {
assertNotHasOwnProperty(name, 'service');
if (isFunction(provider_) || isArray(provider_)) {
provider_ = providerInjector.instantiate(provider_);
}
if (!provider_.$get) {//必须含有$get方法
throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
}
return providerCache[name + providerSuffix] = provider_;
//probider_ 定义了 { $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn }
//enforceReturnValue 返回了 一个调用factoryFn的方法
//相当于调用$get的时候调用
//instanceInjector.invoke(factory)
}
//返回一个方法而已
function enforceReturnValue(name, factory) {
return function enforcedReturnValue() {
var result = instanceInjector.invoke(factory, this);
if (isUndefined(result)) {
throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
}
return result;
};
}
我们来看看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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
首先angular.injector就是调用的createInjector方法
createInjector方法内部有句```var runBlocks = loadModules(modulesToLoad);```
```js
////////////////////////////////////
// Module Loading
////////////////////////////////////
function loadModules(modulesToLoad) {
//判断是否是数组
assertArg(isUndefined(modulesToLoad) || isArray(modulesToLoad), 'modulesToLoad', 'not an array');
var runBlocks = [], moduleFn;
//遍历modulesToLoad数组
forEach(modulesToLoad, function(module) {
if (loadedModules.get(module)) return;
loadedModules.put(module, true);
function runInvokeQueue(queue) {
var i, ii;
for (i = 0, ii = queue.length; i < ii; i++) {
var invokeArgs = queue[i],
provider = providerInjector.get(invokeArgs[0]);//invokeArgs[0]就是$provide
//invokeArgs[1]就是service
//invokeArgs[2]就是 recipeName factoryFunction的数组
provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
// provider['service'] 就是调用```provider[invokeArgs[1]].apply(provider, invokeArgs[2]);```
//invokeArgs[2]就是一个数组,传入了service的key,value
// function(key, value) {
// if (isObject(key)) {
// forEach(key, reverseParams(delegate));
// } else {
// return delegate(key, value);
// }
// }
}
}
try {
if (isString(module)) {
moduleFn = angularModule(module);
runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
runInvokeQueue(moduleFn._invokeQueue);//_invokeQueue是在定义service 等时候push进去的
runInvokeQueue(moduleFn._configBlocks);
} else if (isFunction(module)) {
runBlocks.push(providerInjector.invoke(module));
} else if (isArray(module)) {
runBlocks.push(providerInjector.invoke(module));
} else {
assertArgFn(module, 'module');
}
} catch (e) {
if (isArray(module)) {
module = module[module.length - 1];
}
if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
// Safari & FF's stack traces don't contain error.message content
// unlike those of Chrome and IE
// So if stack doesn't contain message, we create a new string that contains both.
// Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
/* jshint -W022 */
e = e.message + '\n' + e.stack;
}
throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
module, e.stack || e.message || e);
}
});
return runBlocks;
}
```
service调用如下:
```js
//当调用injector.get("myService").my时
var provider = providerInjector.get(serviceName + providerSuffix, caller);
return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);
//此处的provider.$get 就是如下方法
function enforcedReturnValue() {
var result = instanceInjector.invoke(factory, this);
if (isUndefined(result)) {
throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
}
return result;
}
//factory方法就是
['$injector', function($injector) {return $injector.instantiate(constructor);}]
function instantiate(Type, locals, serviceName) {
// Check if Type is annotated and use just the given function at n-1 as parameter
// e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
var ctor = (isArray(Type) ? Type[Type.length - 1] : Type);
var args = injectionArgs(Type, locals, serviceName);
// Empty object at position 0 is ignored for invocation with `new`, but required.
args.unshift(null);
return new (Function.prototype.bind.apply(ctor, args))();
}