john's tech blog

hope is coming


  • 首页

  • 标签

  • 归档

scalatra_mount

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

scalatra是如何加入servlet的

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
private def mountServlet(
servlet: HttpServlet,
urlPattern: String,
name: String,
loadOnStartup: Int): Unit
= {

val reg = Option(sc.getServletRegistration(name)) getOrElse {
val r = sc.addServlet(name, servlet)
servlet match {
case s: HasMultipartConfig => //如果有HasMultipartConfig 特质
r.setMultipartConfig(s.multipartConfig.toMultipartConfigElement)
case _ =>
}
if (servlet.isInstanceOf[ScalatraAsyncSupport])
r.setAsyncSupported(true)
r.setLoadOnStartup(loadOnStartup)
r
}

reg.addMapping(urlPattern)
}

private def mountServlet(
servletClass: Class[HttpServlet],
urlPattern: String,
name: String,
loadOnStartup: Int): Unit
= {

val reg = Option(sc.getServletRegistration(name)) getOrElse {
val r = sc.addServlet(name, servletClass)
// since we only have a Class[_] here, we can't access the MultipartConfig value
// if (classOf[HasMultipartConfig].isAssignableFrom(servletClass))
if (classOf[ScalatraAsyncSupport].isAssignableFrom(servletClass)) {
r.setAsyncSupported(true)
}
r.setLoadOnStartup(loadOnStartup)
r
}
reg.addMapping(urlPattern)
}

scala之隐式servletContext

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

scala 转换被方法调用的对象

在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_object

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

scala object 线程安全

这篇Scala thread-safety question回复

提到如下代码:

1
2
3
object Class {
val students = new mutable.List()
}

“object” initialization is thread safe. “mutable.List” is not thread
safe and needs to be synchronized.

然后我们自己定义一个object用于测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  object  TestObject {

val prop1 = "sad"

lazy val prop2 = "testLazy"
println("propinitialize")
private val props: java.util.Map[String, Object] = new java.util.HashMap[String, Object]

props.put("prop2",prop2)//访问prop2的时候会给prop2赋值

def initialize() = {
println("initialize")
}

def apply() ={

println(props.get("prop2").toString)
println("initializing")
}
}

用以下代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
object  TestObjectInitializer extends  App {

val exce = Executors.newFixedThreadPool(6)

for (i <- 0.to(100)){
val runner = new Runnable {
def run(): Unit = {

TestObject()
}}
exce.submit(runner)
}

println("initialized")
}

打印如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
propinitialize
initialized
testLazy
testLazy
initializing
testLazy
testLazy
initializing
testLazy
testLazy
initializing
initializing

propinitialize只执行一次。

参考资料:
Scala Singleton Object with Multi-threading
How to make object (a mutable stack) thread-safe

scalatra_LifeCycle

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

scalatra是如何启动的

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

class ScalatraListener extends ServletContextListener {

import org.scalatra.servlet.ScalatraListener._

private[this] val logger: Logger = Logger[this.type]

private[this] var cycle: LifeCycle = _

private[this] var servletContext: ServletContext = _

override def contextInitialized(sce: ServletContextEvent): Unit = {

try {
//contextInitialized 后赋值给servletContext
configureServletContext(sce)
configureCycleClass(Thread.currentThread.getContextClassLoader)
} catch {
case e: Throwable =>
logger.error("Failed to initialize scalatra application at " + sce.getServletContext.getContextPath, e)
throw e
}
}

def contextDestroyed(sce: ServletContextEvent): Unit = {
if (cycle != null) {
logger.info("Destroying life cycle class: %s".format(cycle.getClass.getName))
cycle.destroy(servletContext)
}
}

protected def configureExecutionContext(sce: ServletContextEvent): Unit = {
}

//寻找LifeCycle
protected def probeForCycleClass(classLoader: ClassLoader): (String, LifeCycle) = {

}

protected def configureServletContext(sce: ServletContextEvent): Unit = {
//定义servletContext 从sce获取
servletContext = sce.getServletContext
}

protected def configureCycleClass(classLoader: ClassLoader): Unit = {

}
}

object ScalatraListener {

// DO NOT RENAME THIS CLASS NAME AS IT BREAKS THE ENTIRE WORLD
// TOGETHER WITH THE WORLD IT WILL BREAK ALL EXISTING SCALATRA APPS
// RENAMING THIS CLASS WILL RESULT IN GETTING SHOT, IF YOU SURVIVE YOU WILL BE SHOT AGAIN
val DefaultLifeCycle: String = "ScalatraBootstrap"
val OldDefaultLifeCycle: String = "Scalatra"
val LifeCycleKey: String = "org.scalatra.LifeCycle"

}

angular_injector_module

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

angular 1.5.8源码解读

有如下一段代码:

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
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

var moduleInstance = {
//service
service: invokeLaterAndSetModuleName('$provide', 'service')
}

/**
* @param {string} provider
* @param {string} method
* @returns {angular.Module}
*/

function invokeLaterAndSetModuleName(provider, method) {
return function(recipeName, factoryFunction) {
if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
invokeQueue.push([provider, method, arguments]);
return moduleInstance;
};
}
```
也就是如果加入了个module,那么module.service就是
```js

module.service = function(recipeName, factoryFunction) {
if (factoryFunction && isFunction(factoryFunction))
factoryFunction.$$moduleName = name;

//arguments就是 recipeName 和factoryFunction的数组
invokeQueue.push([provider, method, arguments]);
return moduleInstance;
};
```

invokeQueue就push 进去了```$provide service recipeName, factoryFunction```
provider定义的时候 定义了service方法:

```js

$provide: {
provider: supportObject(provider),//supportObject返回了
factory: supportObject(factory),
service: supportObject(service),
value: supportObject(value),
constant: supportObject(constant),
decorator: decorator
}
```

supportObject方法:
```js

function supportObject(delegate) {
return function(key, value) {
if (isObject(key)) {
forEach(key, reverseParams(delegate));
} else {
return delegate(key, value);
}
};
}
```
$provide.service 就是```function(key,value){ }

如果是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))();
}

1…282930…47

John

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