arthinking

ChinSyun Pang's blog


  • 首页

  • 分类

  • 关于

  • 归档

  • 标签

AngularJS之module

发表于 2015-12-01   |   分类于 web前端 , Javascript

Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com

AngularJS允许我们使用angular.module()方法来声明模块,这个方法能够接受两个参数,第一个是模块的名称,第二个是依赖列表,也就是可以被注入到模块中的对象列表。

1
2
3
4
5
// 这个方法相当于AngularJS模块的setter方法,是用来定义模块的。
angular.module('myApp', []);

// 这个方法用于获取应用,相当于AngularJS模块的getter方法
angular.module('myApp')

AngularJS之controller

发表于 2015-12-01   |   分类于 web前端 , Javascript

Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com

将控制器命名为[Name]Controller而不是[Name]Ctrl是一个最佳实践。

控制器可以将与一个独立视图相关的业务逻辑封装在一个独立的容器中。尽可能地精简控制器是很好的做法。

AngularJS同其他JavaScript框架最主要的一个区别就是,控制器并不适合用来执行DOM操作、格式化或数据操作,以及除存储数据模型之外的状态维护操作。它只是视图和$scope之间的桥梁。

$scope对象用来从数据模型向视图传递信息。同时,它也可以用来设置事件监听器,同应用的其他部分进行交互,以及创建与应用相关的特定业务逻辑。

AngularJS通过作用域将视图、控制器和指令(本书后面会介绍)隔离开来,这样就很容易为功能的具体部分编写测试。

1
2
3
4
5
6
<div ng-controller="FirstController">
<h4>The simplest adding machine ever</h4>
<button ng-click="add(1)" class="button">Add</button>
<a ng-click="subtract(1)" class="button alert">Subtract</a>
<h4>Current count: {{ counter }}</h4>
</div>
1
2
3
4
5
app.controller('FirstController', function($scope) {
$scope.counter = 0;
$scope.add = function(amount) { $scope.counter += amount; };
$scope.subtract = function(amount) { $scope.counter -= amount; };
});

5.1、控制器嵌套(作用域包含作用域)

控制器的这种嵌套结构和DOM的嵌套结构很相似。

控制器应该尽可能保持短小精悍,而在控制器中进行DOM操作和数据操作则是一个不好的实践。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
angular.module('myApp', [])
.controller('MyController', function($scope) {
$scope.shouldShowLogin = true;
$scope.showLogin = function () {
$scope.shouldShowLogin = !$scope.shouldShowLogin;
};
$scope.clickButton = function() {
$('#btn span').html('Clicked');
};
$scope.onLogin = function(user) {
$http({
method: 'POST',
url: '/login',
data: {
user: user
}
}).success(function(data) {
// user
});
};
});

设计良好的应用会将复杂的逻辑放到指令和服务中。通过使用指令和服务,我们可以将控制器重构成一个轻量且更易维护的形式:

1
2
3
4
5
6
7
angular.module('myApp', [])
.controller('MyController', function($scope,UserSrv) {
// 内容可以被指令控制
$scope.onLogin = function(user) {
UserSrv.runLogin(user);
};
});

AngularJS之data binding

发表于 2015-12-01   |   分类于 web前端 , Javascript

Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com

Hello World

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<!-- ng-app 声明所有被它包含的元素都属于AngularJS 应用 -->
<html ng-app>
<head>
<title>Simple app</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.js"></script>
</head>
<body>
<input ng-model="name" type="text" placeholder="Your name">
<h1>Hello {{ name | number:2 }}</h1>
</body>
</html>

AngularJS之expression

发表于 2015-12-01   |   分类于 web前端 , Javascript

Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com

表达式和eval(javascript)非常相似,但是由于表达式由AngularJS来处理,它们有以下显著不同的特性:

  • 所有的表达式都在其所属的作用域内部执行,并有访问本地$scope的权限;
  • 如果表达式发生了TypeError和ReferenceError并不会抛出异常;
  • 不允许使用任何流程控制功能(条件控制,例如if/eles);
  • 可以接受过滤器和过滤器链。

6.1、解析AngularJS表达式

$parse: AngularJS通过$parse这个内部服务来进行表达式的运算,这个服务能够访问当前所处的作用域。

$parse/$eval和$observe/$watch如何区分

6.2、插值表达式

$interpolate服务: 插值允许基于作用域上的某个条件实时更新文本字符串,可接收三个参数:

  • text(字符串):一个包含字符插值标记的字符串。
  • mustHaveExpression(布尔型):如果将这个参数设为true,当传入的字符串中不含有表达式时会返回null。
  • trustedContext(字符串):AngularJS会对已经进行过字符插值操作的字符串通过$sec.getTrusted()方法进行严格的上下文转义。

MySQL

发表于 2015-09-02   |   分类于 database

SQL语句优化

IN语句的优化

demo 1

慢语句

SELECT * FROM t_user WHERE id IN(SELECT MAX(id) FROM t_user GROUP BY country)

优化

SELECT * FROM t_user t1, (SELECT MAX(id) AS id FROM t_user GROUP BY country) t2 WHERE t1.id = t2.id

大表查询优化

随着数据库数据的增加,查询速度会越来越慢,可以开启log_slow_queries慢查询日志,通过查看慢查询日志找到慢语句,进行优化。

问题

数据库中主键设计原则

Java基础

发表于 2015-09-01   |   分类于 Java

Java基础知识

HashMap 与 ConcurrentHashMap

HashMap的扩容机制,ConcurrentHashMap的原理:

HashMap的设计原理和实现分析
HashMap造成的死锁问题
ConcurrentHashMap原理分析

我们可以在单线程时使用HashMap提高效率,而多线程时用Hashtable来保证安全。

HashMap作为缓存导致的思索问题分析

序列化的作用是,序列化id会出现哪些问题

外观模式的例子:Java序列化ID问题
这是一个关于客户端程序版本升级的例子,当服务器端的对象改动,重新生成了id,这个时候客户端解析旧的对象就会失败,这个时候,必须重新从服务器端获取最新的对象序列化文件。

JDK常用库,JDK源代码

Java IO类库结构图,和所用到的设计模式

NIO

阻塞后的通知机制

RuntimeException与CheckedException

checked exception
checked exception是从java.lang.Exception类衍生出来的;
runtime exception是从java.lang.RuntimeException 或java.lang.Error类衍生出来的,RuntimeException又继承自Exception;
checked exception用来指示一种调用方能够直接处理的异常情况;

Runtime Exception
在定义方法时,不需要声明会抛出runtime exception,在调用方法是不需要捕获runtime exception;
定义方法是必须声明所有可能会抛出的checked exception,在调用方法时,必须捕获它的checked exception,或者throws出去;
runtime exception指示一种调用方法无法处理货恢复的程序错误;

反射 动态代理

看看java的反射效率


Java配置文件


JVM虚拟机

深入理解Java虚拟机笔记

  • 走近Java
  • 自动内存管理机制(Java内存区域与内存溢出异常)
    Java堆溢出
    more
    新生代Minor GC的例子:点我

    1. 分配allocation4时,Eden已经被占用6MB,不够了(总共8MB),所以发生了一次Minor GC;
    2. GC期间发现已有的3X2MB大小对象无法全部放入Survivor空间,所以只好通过分配担保机制提前转移到老年代去了;
    3. GC结束后,4MB的allocation4对象被分配到Eden中,Survivor空闲,老年代占用6MB
  • 自动内存管理机制(垃圾收集器与内存分配策略)

  • 自动内存管理机制(虚拟机性能监控与故障处理工具)

下面是Java中的内存泄露分析的例子:Java中内存泄露的分析

  • 自动内存管理机制(调优案例分析与实战)
  • 虚拟机执行子系统(类文件结构)

对于同步指令monitorenter和monitorexit,编译器会自动产生一个异常处理器,这个异常处理器声明可以处理所有的异常,它的目的就是用来执行monitorexit指令。

  • 虚拟机执行子系统(虚拟机类加载机制)

加载 -> (验证 -> 准备 -> 解析) -> 初始化 -> 使用 -> 卸载
其中解析阶段可以在初始化阶段之后再开始,以便支持运行时绑定(动态绑定或晚期绑定)。

JVM中严格规定有且只有一下五中情况必须对类进行“初始化”:detail(加载、验证、准备自然需要在此之前开始)

这5种场景称为对一个类的主动引用,其余的称为被动引用,不会触发初始化,以下是几个例子:

通过子类引用父类的静态字段,不会导致子类初始化

通过数组定义来引用类,不会触发此类的初始化

调用一个类中的常量,不会触发常量的类的初始化

JVM内存模型与GC回收机制

JVM调优和常用工具

如何dump出当前线程的状态
使用jstack pid进行分析,Thread Dumps的分析

线程的状态:
Runnable:
Wait oncondition:
Waiting for monitor entry:
in Object.wait():

案例:死锁 & 热锁
Java5中加强了堆思索的监测线程Dump中科院直接报告出Java级别的思索。

如果在多线程的程序中,大量使用 synchronized,或者不适当的使用了它,会造成大量线程在临界区的入口等待,造成系统的性能大幅下降。如果在线程 DUMP中发现了这个情况,应该审查源码,改进程序。(引用)

JVM调优相关经验

ClassLoader结构,是否可以自定义一个String类

说说ClassLoader的双亲代理机制

修改类加载器实现热部署

ASM修改字节码文件的流程是一个职责链模式,可以通过ASM修改字节码文件的方式,让每次实例化的时候都是用最新版本的Class文件生成实例,从而达到热部署,但是PermGen space还是不可避免。另外,这种方法仅仅是让新实例化的对象是用新的逻辑;
Tomcat中的热部署实现。


框架源码相关

并发框架

多线程并发用过哪些

Spring

OSGi框架

如何在一个bundle中加载另一个bundle的Class对象


Java Web

Servlet与Filter的作用,原理,配置

Session共享机制

HTTP协议

发表于 2015-09-01   |   分类于 网络协议

HTTP协议返回码,301,302

JDK配置与JVM监控

发表于 2015-03-10   |   分类于 Java

Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com

安装JDK

ubuntu 12.04 LTS 安装配置JDK

下载jdk-xxx.bin

解压文件
chmod u+x jdk-xxx.bin
./jdk-xxx.bin

复制解压出jdk-xxx文件夹到/usr/lib下
sudo mkdir -p /usr/lib/jvm/
cp -r jdk-xxx /usr/lib/jvm/jdkxxx

配置JDK

ubuntu 12.04安装jdk

1
2
apt-get install gedit
sudo gedit /etc/profile

or

1
2
cd /etc/
vim profile

1
2
3
4
5
export JAVA_HOME=/usr/lib/jvm/jdk1.7.0_10
export JRE_HOME=/usr/lib/jvm/jdk1.7.0_10/jre
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH

export PATH=$JAVA_HOME/bin:$PATH

关闭,保存,使用source更新一下profile文件

1
source ~/.profile

如果之前系统里面已经安装了openjdk,可以使用如下方法将默认jdk更改过来:

将系统默认的jdk修改过来

1
$ sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/jdk1.7.0_10/bin/java 300

输入sun jdk前的数字就好了

1
2
3
$ sudo update-alternatives --install /usr/bin/javac javac /usr/lib/jvm/jdk1.7.0_10/bin/javac 300
$ sudo update-alternatives --config java
$ sudo update-alternatives --config javac

使用VisualVM监控远程主机JVM

visualvm监控jvm及远程jvm监控方法

直接使用JDK

如果是直接监控JVM,则在 /etc/profile 文件里面添加如下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
export JAVA_OPTS="-Dcom.sun.management.jmxremote.port=<port> -Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=<hostname>
-Dcom.sun.management.jmxremote.ssl=false"
```

详细参考:
> [使用Java自带的VisualVM监控远程主机JVM内存使用情况](http://www.cnblogs.com/chenying99/archive/2012/06/21/2557208.html "使用Java自带的VisualVM监控远程主机JVM内存使用情况")

## 使用resin
在resin.conf配置文件中添加如下配置:
```xml
<jvm-arg>-Xdebug</jvm-arg>
<jvm-arg>-Dcom.sun.management.jmxremote</jvm-arg>
<jvm-arg>-Djava.rmi.server.hostname=192.168.75.34</jvm-arg>
<jvm-arg>-Dcom.sun.management.jmxremote.port=9934</jvm-arg>
<jvm-arg>-Dcom.sun.management.jmxremote.ssl=false</jvm-arg>
<jvm-arg>-Dcom.sun.management.jmxremote.authenticate=false</jvm-arg>

在客户端使用JMX连接即可

Resin中的热部署

发表于 2015-03-10   |   分类于 Java

Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com

Resin中的热部署

在resin.conf中添加如下的JVM启动参数:

1
<jvm-arg>-Xdebug</jvm-arg>

表示启动debug模式,当更新了类中的方法的时候,控制台会提示reloading class,这是通过JVM的HotSwap功能动态更新的。

1
2
3
4
5
6
... Reloading ...
```

由于JVM的HotSwap不支持新增属性,方法和类的修改,所以进行了这些操作之后,是无法实现热部署的,Resin会自动改用Hot deploy的方式进行应用更新。

当去掉该启动参数的时候,修改一个类,控制台会提示如下的内容:

… WebApp[…] stopping
… WebApp[…] active
```

远程调试相关参数

-Xdebug -Xrunjdwp,transport=dt_socket,server=y,address=5432,suspend=n,onthrow=java.io.IOException,launch=/sbin/echo

为什么不建议调用sun包,如何通过其他方法确定调用者

发表于 2015-03-09   |   分类于 Java

Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com

获取调用者信息的方法

一般的,我们可以通过堆栈信息获取调用当前方法的类名和方法名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 通过堆栈信息获取调用当前方法的类名和方法名
String className = "";
String methodName = "";
Class clazz = null;
StackTraceElement[] elements = new Throwable().getStackTrace();
for (int i = 0; i < elements.length; i++){
if (this.getClass().getName().equals(elements[i].getClassName())){
// 获取堆栈的下一个元素,就是调用者元素
// 如果想要获取当前方法所在类的信息,直接读取elements[i]就可以了
className = elements[i + 1].getClassName();
methodName = elements[i + 1].getMethodName();
break;
}
}
System.out.println(className + "." + methodName + "\n");

该方法也可以获取调用代码所在的行号的类所在的文件,但是这种方法不能获得调用者的类型,因为不知道调用者的的类装载器,所以也就不能使用Class.forName(String)得到类型。

可以尝试使用以下方法获得调用者的类型(但该方法不建议使用,后面有说明)

1
2
clazz = Reflection.getCallerClass(2);
System.out.println("invoker's class loader: " + clazz.getClassLoader() + "\nclass name: " + clazz.getName());

该方法比使用堆栈的效率高,如果想要获取当前方法所在类的信息,调用 Reflection.getCallerClass(1) 就可以了,Reflection.getCallerClass(0) 是Reflection对象

为什么不建议调用sun包

这篇文章中提到了JDK 8弃用 sun.reflect.Reflection.getCallerClass:

http://www.infoq.com/cn/news/2013/07/Oracle-Removes-getCallerClass

但后来又决定保留下来了:

http://www.infoq.com/cn/news/2013/08/Oracle-Resurrects-getCallerClass

JDK 8 实际上新特性如下

http://www.iteye.com/news/28870-java-8-release

其中 JEP 176:自动检测识别Caller-Sensitive方法:

http://openjdk.java.net/jeps/176

JDK 8中在getCallerClass方法加了 @sun.reflect.CallerSensitive 注解,该注解是提供给JVM底层读取处理的,提高了JDK实现感知调用者功能的安全性,详细参考:

http://stackoverflow.com/questions/22626808/what-does-the-sun-reflect-callersensitive-annotation-mean

查看getCallerClass的底层实现#668可以发现,当传入了depth的时候,调用了net.reflect.Reflection类的这个方法:

1
2
@java.lang.Deprecated
public static native java.lang.Class getCallerClass(int arg0);

这个方法在底层实现中还是通过兼容旧版本的代码去执行的,所以这个方法加了一个 @Deprecated 注解,这也是为什么不推荐上面那种方法获取调用者类型的原因。

类似的, JDK8 中的 @java.lang.Class 的 forName(className) 方法也加了这个注解,因为forName方法里面也调用给到了Reflection.getCallerClass()

Oracle建议开发人员不要使用sun包,但是有一系列的项目都依赖于getCallerClass()方法,如Jigsaw和Lambda,Intellij IDEA。在spring-loaded的源码,这里也调用了getCallerClass()方法,作为临时的方案去兼容JDK 7u25,需要添加系统属性:jdk.reflect.allowGetCallerClass,参考这里:

http://permalink.gmane.org/gmane.comp.java.openjdk.jdk7u.devel/6573

其实查看JDK 7 Reflection的字节码可以发现对这个属性的处理逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static java.lang.Class getCallerClass(int arg0);
0 invokestatic sun.misc.VM.allowGetCallerClass() : boolean [216]
3 ifeq 13
6 iload_0 [arg0]
7 iconst_1
8 iadd
9 invokestatic sun.reflect.Reflection.getCallerClass0(int) : java.lang.Class [217]
12 areturn
13 new java.lang.UnsupportedOperationException [112]
16 dup
17 ldc <String "This method has been disabled by a system property"> [7]
19 invokespecial java.lang.UnsupportedOperationException(java.lang.String) [206]
22 athrow
Line numbers:
[pc: 0, line: 68]
[pc: 6, line: 69]
[pc: 13, line: 71]
Stack map table: number of frames 1
[pc: 13, same]

开发者不应该调用sun包,Oracle一直在提醒开发者,调用sun.*包里面的方法是危险的。上面用到的Reflection.getCallerClass()也是在这个包里面的,因为sun包并不包含在Java平台的标准中,它与操作系统相关,在不同的操作系统如Solaris,Windows,Linux,Mac等中的实现也各不相同,并且可能随着JDK版本而变化。详细说明:

http://www.oracle.com/technetwork/java/faq-sun-packages-142232.html

完整例子:

https://github.com/arthinking/java-code/blob/master/src/main/java/me/arthinking/question/Q_07_stack_trace.java

发表于:

http://www.itzhai.com/get-invoker-by-stacktrace-and-getcallerclass.html

API文档编辑工具

发表于 2015-02-10   |   分类于 工具

Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com

http://turnapi.com/
这是基于一款markdown语法的文档生成器,没有提供实体和返回值的统一管理。

http://www.programering.com/a/MDN5MjMwATg.html

http://blog.csdn.net/doctor_who2004/article/details/50816208

swagger配置在线编辑:http://editor.swagger.io/#/

http://symfony.com/doc/current/components/yaml/yaml_format.html

给一个多处使用到的类中的某些方法添加额外的处理动作

发表于 2015-02-10   |   分类于 设计模式

Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com

现有如下程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public interface Searcher {
List<String> searchSong(int songType);
}

public class LuceneSearcher implements Searcher{

@Override
public List<String> searchSong(int songType) {
List<String> result = new ArrayList<String>();
result.add("Wings you are the hero");
return result;
}
}

public class ProxyMain {

public static void main(String[] args){
LuceneSearcher searcher = new LuceneSearcher();
searcher.searchSong(1);
}
}

LuceneSearcher在项目中的很多地方都用到了,现在想在LuceneSearcher的searchSong()方法添加一个处理逻辑,为了进行全局的改动,避免在多处地方分别改动,现在使用代理模式,创建一个Searcher的代理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class CustomSearcher implements Searcher{

private Searcher searcher;

public CustomSearcher(Searcher searcher){
this.searcher = searcher;
}

@Override
public List<String> searchSong(int songType) {
List<String> result = searcher.searchSong(songType);
result.add("big blue ocean");
return result;
}

}

这样就可以只在对象的声明创建语句改动下,程序中调用的地方就可以保持原样了:

1
2
3
4
5
6
7
public class ProxyMain {

public static void main(String[] args){
LuceneSearcher searcher = new LuceneSearcher();
searcher.searchSong(1); // 调用的语句保持原样
}
}

如果Searcher接口有其他的实现,也可以很方便的使用这个代理方法改写方法了。另外,如果确定需要为接口的所有方法都使用代理进行改写,可以使用动态代理实现,而且通过使用动态代理(JDK动态代理也可以通过invoke方法判断当前是否想要改写的方法而进行处理,CGLib动态代理]对应为intercept方法),可以通过写一个代理处理类,就同时可以代理其他的类了,使用起来更灵活。

如果LuceneSearcher并不是通过实现接口的方式编写的,那么我们可以继承这个LuceneSearcher接口,并覆盖searchSong方法加入处理逻辑,这样也通过改动创建语句就可以很方便的对代码进行了调整。

设计模式笔记

发表于 2015-02-09   |   分类于 设计模式

Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com

职责链模式

说明:

通过把对象链接起来,给更多的对象处理请求的机会。

使用场景:

  • 多个对象需要处理一个请求,并且处理请求的对象不是特定的;
  • 运行期才能决定哪些对象需要处理这个请求;
  • 允许出现一个请求可能不被其中一个对象处理的情况;

实例:

Java语言的异常处理实现使用了职责链模式;

命令模式

说明:

把一个请求封装成一个对象,让请求被当成基于对象的形式进行处理,如回调。

使用场景:

  • 你需要回调函数的时候;
  • 请求需要在不同的时间或者通过不同的顺序进行处理;
  • 需要请求的历史记录;
  • 调用者需要和执行者解耦的时候

命令模式在MVC框架中的应用

实例:

任务队列

解析器模式

说明:

为文法提供一个解析的机制。

使用场景:

  • 需要把文法解析成一个大的语法树;
  • 文法比较简单;
  • 解析的过程中性能并不是很重要;
  • 需要把文法和解析式进行解耦;

实例

上个世纪80年代流行的基于文字的冒险游戏。

迭代器模式

说明:

在不知道集合类实现的情况下,实现访问集合元素的功能。

使用场景:

  • 不访问对象的情况下,需要访问到对象里面的元素
  • 需要支持多线程或者并发遍历集合
  • 需要一个同一个遍历接口
  • 不同的迭代器实现由细微的差别

实例:

Java的集合类就很好的用到了迭代器模式,允许用户在不知道集合的实现的情况下遍历各种类型的数据集合。

中介者模式

说明:

通过封装不同对象集的交互来达到解耦这些对象。

使用场景:

  • 对象间的交流动作有明确的定义,并且很复杂;
  • 对象间存在复杂的交互关系,并且需要一个中央的控制节点来转发这些交互。

实例:

邮件群发系统,通过中介者模式,发送者无需记录哪些邮件地址是否注册了,把邮件发给中介者,中介者把邮件转发给有效的接收者。

备忘录模式

说明:

在不违反封装性的前提下,允许捕获并且外化一个对象的内部状态,以便存储下来。

使用场景:

  • 一个对象的内部状态需要存储下来;
  • 一个对象的内部状态没有提供对外暴露的接口;
  • 封装的边界必须被保存

实例:

撤销动作,通过建立对象的一个快照实现。

观察者模式

说明:

在一个系统中,当一个对象的状态改变的时候,通知其他对象。

使用场景:

  • 一个或多个对象状态的改变触发其他对象的处理事件
  • 需要广播的能力

实例:

在大部分的GUI环境中都有用到这个设计模式,通过把按钮,文本区等注册为观察者,当一个用户触发一个事件,就发送一个通知到所有的观察者。

状态模式

说明:

使用场景:

实例:

策略模式

模板模式

访问者模式

适配器模式

桥接模式

组合模式

装饰者模式

门面模式

享元模式

代理模式

抽象工厂模式

构建者模式

工厂方法模式

原型模式

单例模式

数据库连接池

发表于 2015-01-16   |   分类于 JDBC

Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com

数据库连接池工具:

common-pool工具库是对池化技术原理的一种具体实现。

apache的连接池工具库common-dbcp是common-pool在数据库访问方面的一个具体应用。

common-dbcp

接口设计原则

发表于 2015-01-06   |   分类于 设计模式

Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com

接口尽量设计的单一职责,会方便代码的扩展和维护。

Spring beans

发表于 2014-12-24   |   分类于 Java , Spring

Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com

Bean 组件在 Spring 的 org.springframework.beans 包下。这个包下的所有类主要解决了三件事:Bean 的定义、Bean 的创建以及对 Bean 的解析。对 Spring 的使用者来说唯一需要关心的就是 Bean 的创建,其他两个由 Spring 在内部帮你完成了,对你来说是透明的。

Spring Bean 的创建是典型的工厂模式,他的顶级接口是 BeanFactory,下图是这个工厂的继承层次关系:

Bean工厂的继承关系

BeanFactory 有三个子类:ListableBeanFactory、HierarchicalBeanFactory 和 AutowireCapableBeanFactory。但是从上图中我们可以发现最终的默认实现类是 DefaultListableBeanFactory,他实现了所有的接口。那为何要定义这么多层次的接口呢?查阅这些接口的源码和说明发现,每个接口都有他使用的场合,它主要是为了区分在 Spring 内部在操作过程中对象的传递和转化过程中,对对象的数据访问所做的限制。例如 ListableBeanFactory 接口表示这些 Bean 是可列表的,而 HierarchicalBeanFactory 表示的是这些 Bean 是有继承关系的,也就是每个 Bean 有可能有父 Bean。AutowireCapableBeanFactory 接口定义 Bean 的自动装配规则。这四个接口共同定义了 Bean 的集合、Bean 之间的关系、以及 Bean 行为。

Bean定义的类层次关系图

Bean 的定义主要由 BeanDefinition 描述,如下图说明了这些类的层次关系:

Bean 的定义就是完整的描述了在 Spring 的配置文件中你定义的 节点中所有的信息,包括各种子节点。当 Spring 成功解析你定义的一个 节点后,在 Spring 的内部他就被转化成 BeanDefinition 对象。以后所有的操作都是对这个对象完成的。

Bean 的解析过程非常复杂,功能被分的很细,因为这里需要被扩展的地方很多,必须保证有足够的灵活性,以应对可能的变化。Bean 的解析主要就是对 Spring 配置文件的解析。这个解析过程主要通过下图中的类完成:

Bean的解析类

通过XmlBeanFactory实现启动Spring IoC容器

Spring 框架的设计理念与设计模式分析

Spring core

发表于 2014-12-24   |   分类于 Java , Spring

Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com

Core 组件作为 Spring 的核心组件,他其中包含了很多的关键类,其中一个重要组成部分就是定义了资源的访问方式。这种把所有资源都抽象成一个接口的方式很值得在以后的设计中拿来学习。下面就重要看一下这个部分在 Spring 的作用。

Resource相关的类结构图:

从上图可以看出 Resource 接口封装了各种可能的资源类型,也就是对使用者来说屏蔽了文件类型的不同。对资源的提供者来说,如何把资源包装起来交给其他人用这也是一个问题,我们看到 Resource 接口继承了 InputStreamSource 接口,这个接口中有个 getInputStream 方法,返回的是 InputStream 类。这样所有的资源都被可以通过 InputStream 这个类来获取,所以也屏蔽了资源的提供者。另外还有一个问题就是加载资源的问题,也就是资源的加载者要统一,从上图中可以看出这个任务是由 ResourceLoader 接口完成,他屏蔽了所有的资源加载者的差异,只需要实现这个接口就可以加载所有的资源,他的默认实现是 DefaultResourceLoader。
下面看一下 Context 和 Resource 是如何建立关系的?首先看一下他们的类关系图:

Context和Resource的类关系图

如何创建BeanFactory工厂

正如图 2 描述的那样,Ioc 容器实际上就是 Context 组件结合其他两个组件共同构建了一个 Bean 关系网,如何构建这个关系网?构建的入口就在 AbstractApplicationContext 类的 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
public void refresh() throws BeansException, IllegalStateException { 
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// 创建和配置BeanFactory
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
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) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}

这个方法就是构建整个 Ioc 容器过程的完整的代码,了解了里面的每一行代码基本上就了解大部分 Spring 的原理和功能了。

这段代码主要包含这样几个步骤:

  • 构建 BeanFactory,以便于产生所需的“演员”
  • 注册可能感兴趣的事件
  • 创建 Bean 实例对象
  • 触发被监听的事件

实现AbstractApplicationContext的refreshBeanFactory的refreshBeanFactory()子类的方法,可更新的子类AbstractRefreshableApplicationContext:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
protected final void refreshBeanFactory() throws BeansException { 
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException(
"I/O error parsing bean definition source for "
+ getDisplayName(), ex);
}
}

BeanFactory 的原始对象是 DefaultListableBeanFactory,这个非常关键,因为他设计到后面对这个对象的多种操作,下面看一下这个类的继承层次类图:

Spring 框架的设计理念与设计模式分析

Spring架构设计

发表于 2014-12-24   |   分类于 Java , Spring

Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com

Spring框架的7个模块:

Spring Core:

核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。

Spring Context:

Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。

Spring AOP:

通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。

Spring DAO:

JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。

Spring ORM:

Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。

Spring Web模块:

Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。

Spring MVC框架:

MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。

Spring源码整体架构

Spring源码解读笔记

发表于 2014-12-24   |   分类于 Java

Author: arthinking
Weibo: arthinking_plus
Posted in:

Spring-core

org/springframework/core/io/相关内容

UrlResource.getInputStream() #166

1
ResourceUtils.useCachesIfNecessary(con);

设置URLConnection的UseCaches为false,主要是为了防止在Windows下jar包被锁住。

AbstractFileResolvingResource

里面包含了JBoss vfs协议URL文件的获取。通过静态内部类 VfsResourceDelegate 进行处理的

ResourceLoader

是一个策略接口,其 getResource(String location)方法根据传入不同的location,返回不同的Resource。其实现类是一个可以单独使用的ResourceLoader实现类,ResourceEditor也使用了这个类

DefaultResourceLoader

ResourceLoader的默认实现,可以单独使用,ResourceEditor使用了该类,是AbstractApplicationContext的基类。

说说Spring容器的加载过程

XmlBeanFactory通过Resource装载Spring配置信息并启动IoC容器;
然后通过BeanFactory#getBean(beanName)方法从IoC容器获取Bean;
通过BeanFactory启动IoC容器时,并不会初始化配置文件中定义的Bean,初始化动作发生在第一个调用时;
对于单实例的Bean来说,BeanFactory会缓存Bean实例,所以第二次使用getBean()获取Bean的时候将直接从IoC容器的缓存中获取Bean实例。

Spring MVC一次执行的原理

列举出5种常用的SQL语句优化方式

说说两种数据库引擎的区别

猿题库

问题
描述
回答
参考网址
举报test

Spring context

发表于 2014-12-24   |   分类于 Java , Spring

Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com

Context 在 Spring 的 org.springframework.context 包下,前面已经讲解了 Context 组件在 Spring 中的作用,他实际上就是给 Spring 提供一个运行时的环境,用以保存各个对象的状态。下面看一下这个环境是如何构建的。

ApplicationContext 是 Context 的顶级父类,他除了能标识一个应用环境的基本信息外,他还继承了五个接口,这五个接口主要是扩展了 Context 的功能。下面是 Context 的类结构图:

Context相关的类结构图

从上图中可以看出 ApplicationContext 继承了 BeanFactory,这也说明了 Spring 容器中运行的主体对象是 Bean,另外 ApplicationContext 继承了 ResourceLoader 接口,使得 ApplicationContext 可以访问到任何外部资源,这将在 Core 中详细说明。

ApplicationContext 的子类主要包含两个方面:

  • ConfigurableApplicationContext 表示该 Context 是可修改的,也就是在构建 Context 中用户可以动态添加或修改已有的配置信息,它下面又有多个子类,其中最经常使用的是可更新的 Context,即 AbstractRefreshableApplicationContext 类。
  • WebApplicationContext 顾名思义,就是为 web 准备的 Context 他可以直接访问到 ServletContext,通常情况下,这个接口使用的少。
    再往下分就是按照构建 Context 的文件类型,接着就是访问 Context 的方式。这样一级一级构成了完整的 Context 等级层次。

总体来说 ApplicationContext 必须要完成以下几件事:

  • 标识一个应用环境
  • 利用 BeanFactory 创建 Bean 对象
  • 保存对象关系表
  • 能够捕获各种事件
  • Context 作为 Spring 的 Ioc 容器,基本上整合了 Spring 的大部分功能,或者说是大部分功能的基础。

Spring 框架的设计理念与设计模式分析

1…456
arthinking

arthinking

Struggle for HighPay zoom.
主站 http://www.itzhai.com/

120 日志
33 分类
51 标签
itzhai GitHub Twitter Weibo
Creative Commons
© 2016 arthinking
由 Hexo 强力驱动
主题 - NexT.Pisces