初识angularjs

初识angularjs

该框架是一个jsmvc框架,具备以下特点:

  1. 把应用程序数据绑定到 HTML 元素;
  2. 可以克隆和重复 HTML 元素。
  3. 可以隐藏和显示 HTML 元素。
  4. 可以在 HTML 元素”背后”添加代码。
  5. 支持输入验证。

观察者模式

观察者模式:

​ 定义了对象的一对多依赖,这样一来,当一个对象改变状态的时候,它的所有依赖者都会收到通知并作出相应的动作;

subject状态更新的时候,如果想要通知观察他的对象,那么subject本身势必要持有观察他的对象的集合,这样才会自身有状态更新的时候,根据集合去通知观察者;观察者众多,通知的时候肯定是通过统一的接口来调用观察者的方法,这个统一的接口可以看做observersubject本身拥有观察者的集合,那么自身会有一些管理观察者的动作,这些动作可以集合在subject接口;

observer角度来说,要实施观察动作,那么就需要持有一个subject对象;

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.vayne.design;

/**
* @author Volcanno
*/
public interface Subject {

boolean registerObserver(Observer observer);

boolean removeObserver(Observer observer);

void notifyObserver();
}

观察者:

1
2
3
4
5
6
7
8
9
10
package com.vayne.design;

/**
* @author Volcanno
*/
public interface Observer {

boolean update(String name,int age);

}

各自的一个实现:

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
package com.vayne.design;

import java.util.ArrayList;
import java.util.List;

/**
* @author Volcanno
*/
public class WeatherData implements Subject {

private List<Observer> observers = new ArrayList<>();

private String name;
private int age;

public void Do(String name, int age) {
this.name = name;
this.age = age;
notifyObserver();
}

@Override
public boolean registerObserver(Observer observer) {
if (observer != null) {
observers.add(observer);
return true;
}
return false;
}

@Override
public boolean removeObserver(Observer observer) {
if (observer != null) {
observers.remove(observer);
return true;
}
return false;
}

@Override
public void notifyObserver() {
for (Observer observer : observers) {
observer.update(this.name, this.age);
}
}
}
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
package com.vayne.design;

/**
* @author Volcanno
*/
public class CenterOne implements Observer {

private Subject subject;

private String name;
private int age;

public CenterOne(Subject subject) {
this.subject = subject;
subject.registerObserver(this);
}

@Override
public boolean update(String name, int age) {
this.name = name;
this.age = age;
display();
return true;
}

public void display() {
System.out.println("name:");
System.out.println(name);
System.out.println("age");
System.out.println(age);

}
}

几个原则:

  1. 封装变化;
  2. 多用组合,少用继承;
  3. 针对接口编程;不针对具体实现编程;

参考《headfirst设计模式》

ApplicationContext之prepareRefresh

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
/**
* Prepare this context for refreshing, setting its startup date and
* active flag as well as performing any initialization of property sources.
*/
protected void prepareRefresh() {
//开始时间
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);

if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}

// Initialize any placeholder property sources in the context environment.
//初始化一些属性,默认里面的实现是空的,留给子类使用,扩展点之一
initPropertySources();

// Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties
//得到环境信息,默认的是StandardEnvironment。然后来验证一些必要的属性是否存在,如果不存在,那么此处就会
//抛出异常
//StandardEnvironment用的是委托模式,validateRequiredProperties的时候委托给了自己内部的属性解析器,也就是
//propertyResolver。
//propertyResolver在实例化的时候,会接收属性源,解析器的父类有一个私有集合对象用于储存key;
//validate的时候,会通过解析器的getProperty取值然后验证是否存在;
getEnvironment().validateRequiredProperties();

// Store pre-refresh ApplicationListeners...
//添加一些监听器
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}

// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<>();
}

下面是一个使用示例:

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
package com.vayne.boot;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.env.SystemEnvironmentPropertySource;

import java.util.HashMap;
import java.util.Map;

/**
* @author Volcanno
*/
public class Boot {

public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");
Map<String, Object> map = new HashMap<>();
map.put("vay", "vayne");
map.put("alis", "alison");
SystemEnvironmentPropertySource seps = new SystemEnvironmentPropertySource("env", map);
context.getEnvironment().getPropertySources().addFirst(seps);
//这里会把vay和alis添加到AbstractPropertyResolver的一个list里面。然后validate的时候,会调用子类的getProperty
context.getEnvironment().setRequiredProperties("vay");
context.getEnvironment().setRequiredProperties("alis");
context.refresh();
Object object = context.getEnvironment().getProperty("alis");
String string = String.valueOf(object);
System.out.println("hello, " + string);
}
}

总结:

可以将一些需要使用的必要的属性设置到contextenvironment里面,然后使用的时候直接取用就可以了。

ApplicationContext的refresh过程

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
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//进行一些准备工作,比如环境变量的操作等等
prepareRefresh();

// Tell the subclass to refresh the internal bean factory.
//获取beanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.
//对beanFactory进行一些必要的设置
prepareBeanFactory(beanFactory);

try {
// Allows post-processing of the bean factory in context subclasses.
//beanFactory的后处理
postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.
//调用beanFactory的后处理器,扩展点之一
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
//注册bean处理器,扩展点之一
registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.
//实例化消息源,
initMessageSource();

// Initialize event multicaster for this context.
//初始化广播器
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.
//留出为子类提供的扩展点,扩展点之一
onRefresh();

// Check for listener beans and register them.
//注册监听器
registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.
//实例化非懒加载的单例
finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.
//发布相关事件
finishRefresh();
}

catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}

// Destroy already created singletons to avoid dangling resources.
//销毁bean
destroyBeans();

// Reset 'active' flag.
cancelRefresh(ex);

// Propagate exception to caller.
throw ex;
}

finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}

可以看到,spring的代码风格,先用方法列出逻辑框架,然后逐一进行填充,值得学习;

后面就每一步进行详细的补充。

探究java中的异常

之前对java中的异常如何使用一直存在疑问。
问题:自己写的代码什么时候抛出异常,当偏离程序主流逻辑的时候应该如何返回?

这篇文章就是对这类问题下一个定论。

先来看官方对Exception的总结:

异常的三个优点

概括一下:

  1. Advantage 1: Separating Error-Handling Code from "Regular" Code

    分离regular代码和错误处理代码,这里的regular代码不知道怎么翻译,不过可以理解成我们期望发生的的代码的主要逻辑。

  2. Advantage 2: Propagating Errors Up the Call Stack

    把异常传播到调用栈栈顶

  3. Advantage 3: Grouping and Differentiating Error Types

    分组和细分错误类型

所以确定以下几个原则:

  1. 破坏调用方和被调用方的协议,那么抛出运行时异常;在公司编码规范里,public方法要对自己的入参负责,即需要进行null判断;
  2. 如果调用方已经遵守了协议,在被调用方内部发生了一些异常,或者一些不是主程序逻辑的事情,那么就要考虑几点:①该异常内部是否能够处理②该异常要以什么样的形式通知调用方
  3. 编写被调用方的代码时,要考虑到方法内部是否会发生一些异常的逻辑,对于这些可能发生的非主逻辑且自身无法处理是, 要在方法签名处就声明,让调用方注意到这些异常情况;

总而言之:

  1. 破坏协议,抛出运行时异常;
  2. 方法内部异常,能处理,则处理;不能处理,抛出非运行时异常;

可见性与原子性

可见性

线程对变量的修改,在任意时刻对其他线程都是可见的。

原子性

我们说某个操作具有原子性,是指某个线程执行这个操作的时候,不会被其他线程影响。线程执行这个操作的时候,里面用到的所有的变量,其修改只能由自己进行。

数字证书等概念

公钥与私钥

公钥可以到处分发,属于易得的东西,私钥只能自己持有。公钥加密的东西,只有对应的私钥可以解开;

概括:

公钥用来加密消息,私钥解密消息,也就是用于加解密;

私钥签名,公钥验证签名,也就是用于签名;

所以,公钥加密的东西,私钥可以解开;私钥加密的东西,公钥也可以解开;

数字签名

一句话概括: 数字签名是用来验证传输的内容是否被篡改。

内容通过hash算法计算出摘要,然后用私钥进行加密,公钥拥有方获得之后,可以解出来,然后通过相同的hash算法计算摘要,如果摘要相同,说明内容未被篡改。一句话再概括, 数字签名是对摘要内容经过公私钥加密之后的一段信息,也叫指纹。

CA

一个受信任的机构,比如公安局,政府这种(手动狗头);

CA证书(数字证书)

一句话概括: CA证书是经过权威机构认证的公钥,注意,是公钥;相当于数字签名过的信息。前面讲过,私钥签名,公钥解密然后验证签名;

其他

既然CA证书是用来保证公钥的有效性和可靠性,那CA公钥的可靠性谁来保证呢;操作系统内部一般都集成了可用的CA机构的公钥;想要自己的公钥被CA认证,也就是被CA用自己的私钥签名,就需要把自己的公钥和身份等相关信息交给CA,由CA给你签名,当然,一般都是收费的;

读《线程模型》

这篇博客非常不错:Goroutine并发调度模型深度解析

关于这篇博客的一些总结:

线程

用户级线程模型

这种模型在内核看来,用户只有进程。也就是说,用户进程请求内核操作时,内核使用一个内核线程为其服务。用户进程内的线程划分,是由进程内用户自调度的,内核线程无感知。坏处是,用户线程发起某个阻塞性的内核操作时,内核方面是为用户进程服务的,那么用户内自划分的其他的线程实际上也是阻塞的,因为在内核看来,用户进程已经发起调用,占用一个内核线程了。

内核级进程模型

java.lang.Thread使用的就是这种模型。这种模型是,一个内核线程对应一个用户进程内的一个线程。如果创建很多用户线程,那么就对应的会创建很多内核线程,此时调度开销会急剧上升。不过现在java好像是开始支持n-m模型了。在网络性能上,讲道理应该与GO不相上下,劣势可能就在于java这种半解释半编译型语言内存方面的消耗了,毕竟有得就有失嘛。

未完待续…

方法集

方法集规定了方法的接收规则。

从值的角度,也就是被调用的方法里面参数的角度来说:

  • 值的方法集,只包含接收者是值的情况;
  • 指针的方法集,包含接收者是值和接收者是指针的情况;

从接收者角度:

  • 如果方法绑定在值上面,那么方法中的参数为值,或者为指针,都可以使用;
  • 如果方法绑定在指针上面,那么方法中的参数为指针时才可以使用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
type notifier interface{
notify()
}
type user struct{
name string
email string
}

func (u *user) notify(){
dosomething()
}
//调用do方法,那么上面这种绑定指针的方式,不能使用,只能使用下面的方式;
func do(n notifier){
n.notify()
}
func (u user) notify(){
dosomething()
}