Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.comAngularJS允许我们使用angular.module()方法来声明模块,这个方法能够接受两个参数,第一个是模块的名称,第二个是依赖列表,也就是可以被注入到模块中的对象列表。
1 | // 这个方法相当于AngularJS模块的setter方法,是用来定义模块的。 |
ChinSyun Pang's blog
Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.comAngularJS允许我们使用angular.module()方法来声明模块,这个方法能够接受两个参数,第一个是模块的名称,第二个是依赖列表,也就是可以被注入到模块中的对象列表。
1 | // 这个方法相当于AngularJS模块的setter方法,是用来定义模块的。 |
Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com将控制器命名为[Name]Controller而不是[Name]Ctrl是一个最佳实践。
控制器可以将与一个独立视图相关的业务逻辑封装在一个独立的容器中。尽可能地精简控制器是很好的做法。
AngularJS同其他JavaScript框架最主要的一个区别就是,
控制器
并不适合用来执行DOM操作、格式化或数据操作,以及除存储数据模型之外的状态维护操作。它只是视图和$scope之间的桥梁。
$scope
对象用来从数据模型向视图传递信息。同时,它也可以用来设置事件监听器,同应用的其他部分进行交互,以及创建与应用相关的特定业务逻辑。AngularJS通过作用域将视图、控制器和指令(本书后面会介绍)隔离开来,这样就很容易为功能的具体部分编写测试。
1 | <div ng-controller="FirstController"> |
1 | app.controller('FirstController', function($scope) { |
控制器的这种嵌套结构和DOM的嵌套结构很相似。
控制器应该尽可能保持短小精悍,而在控制器中进行DOM操作和数据操作则是一个不好的实践。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21angular.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 | angular.module('myApp', []) |
Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com
1 | <!DOCTYPE html> |
Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com
表达式和eval(javascript)非常相似,但是由于表达式由AngularJS来处理,它们有以下显著不同的特性:
$parse
: AngularJS通过$parse
这个内部服务来进行表达式的运算,这个服务能够访问当前所处的作用域。
$parse/$eval和$observe/$watch如何区分
$interpolate服务
: 插值允许基于作用域上的某个条件实时更新文本字符串,可接收三个参数:
字符插值标记
的字符串。慢语句
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慢查询日志,通过查看慢查询日志找到慢语句,进行优化。
HashMap的扩容机制,ConcurrentHashMap的原理:
HashMap的设计原理和实现分析
HashMap造成的死锁问题
ConcurrentHashMap原理分析
我们可以在单线程时使用HashMap提高效率,而多线程时用Hashtable来保证安全。
HashMap作为缓存导致的思索问题分析
外观模式的例子:Java序列化ID问题
这是一个关于客户端程序版本升级的例子,当服务器端的对象改动,重新生成了id,这个时候客户端解析旧的对象就会失败,这个时候,必须重新从服务器端获取最新的对象序列化文件。
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堆溢出
more
新生代Minor GC的例子:点我
- 分配allocation4时,Eden已经被占用6MB,不够了(总共8MB),所以发生了一次Minor GC;
- GC期间发现已有的3X2MB大小对象无法全部放入Survivor空间,所以只好通过分配担保机制提前转移到老年代去了;
- GC结束后,4MB的allocation4对象被分配到Eden中,Survivor空闲,老年代占用6MB
下面是Java中的内存泄露分析的例子:Java中内存泄露的分析
对于同步指令monitorenter和monitorexit,编译器会自动产生一个异常处理器,这个异常处理器声明可以处理所有的异常,它的目的就是用来执行monitorexit指令。
加载 -> (验证 -> 准备 -> 解析
) -> 初始化 -> 使用 -> 卸载
其中解析阶段可以在初始化阶段之后再开始,以便支持运行时绑定(动态绑定或晚期绑定)。
JVM中严格规定有且只有一下五中情况必须对类进行“初始化”:detail(加载、验证、准备自然需要在此之前开始)
这5种场景称为对一个类的主动引用,其余的称为被动引用,不会触发初始化,以下是几个例子:
通过子类引用父类的静态字段,不会导致子类初始化
通过数组定义来引用类,不会触发此类的初始化
调用一个类中的常量,不会触发常量的类的初始化
如何dump出当前线程的状态
使用jstack pid进行分析,Thread Dumps的分析
线程的状态:Runnable
:Wait oncondition
:Waiting for monitor entry
:in Object.wait()
:
案例:死锁
& 热锁
Java5中加强了堆思索的监测线程Dump中科院直接报告出Java级别的思索。
如果在多线程的程序中,大量使用 synchronized,或者不适当的使用了它,会造成大量线程在临界区的入口等待,造成系统的性能大幅下降。如果在线程 DUMP中发现了这个情况,应该审查源码,改进程序。(引用)
JVM调优相关经验
说说ClassLoader的双亲代理机制
ASM修改字节码文件的流程是一个职责链模式,可以通过ASM修改字节码文件的方式,让每次实例化的时候都是用最新版本的Class文件生成实例,从而达到热部署,但是PermGen space还是不可避免。另外,这种方法仅仅是让新实例化的对象是用新的逻辑;
Tomcat中的热部署实现。
多线程并发用过哪些
Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com
下载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
1 | apt-get install gedit |
or1
2cd /etc/
vim profile
1 | export JAVA_HOME=/usr/lib/jvm/jdk1.7.0_10 |
关闭,保存,使用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 | $ sudo update-alternatives --install /usr/bin/javac javac /usr/lib/jvm/jdk1.7.0_10/bin/javac 300 |
如果是直接监控JVM,则在 /etc/profile
文件里面添加如下配置:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17export 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连接即可
Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com
在resin.conf中添加如下的JVM启动参数:
1 | <jvm-arg>-Xdebug</jvm-arg> |
表示启动debug模式,当更新了类中的方法的时候,控制台会提示reloading class,这是通过JVM的HotSwap功能动态更新的。
1 | ... Reloading ... |
… WebApp[…] stopping
… WebApp[…] active
```
-Xdebug -Xrunjdwp,transport=dt_socket,server=y,address=5432,suspend=n,onthrow=java.io.IOException,launch=/sbin/echo
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 | clazz = Reflection.getCallerClass(2); |
该方法比使用堆栈的效率高,如果想要获取当前方法所在类的信息,调用 Reflection.getCallerClass(1) 就可以了,Reflection.getCallerClass(0) 是Reflection对象
这篇文章中提到了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 实际上新特性如下
其中 JEP 176:自动检测识别Caller-Sensitive方法:
JDK 8中在getCallerClass方法加了 @sun.reflect.CallerSensitive 注解,该注解是提供给JVM底层读取处理的,提高了JDK实现感知调用者功能的安全性,详细参考:
查看getCallerClass的底层实现#668可以发现,当传入了depth的时候,调用了net.reflect.Reflection类的这个方法:
1 | @java.lang.Deprecated |
这个方法在底层实现中还是通过兼容旧版本的代码去执行的,所以这个方法加了一个 @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
19public 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
完整例子:
发表于:
http://www.itzhai.com/get-invoker-by-stacktrace-and-getcallerclass.html
Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.comhttp://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
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
21public 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
16public 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
7public class ProxyMain {
public static void main(String[] args){
LuceneSearcher searcher = new LuceneSearcher();
searcher.searchSong(1); // 调用的语句保持原样
}
}
如果Searcher接口有其他的实现,也可以很方便的使用这个代理方法改写方法了。另外,如果确定需要为接口的所有方法都使用代理进行改写,可以使用动态代理实现,而且通过使用动态代理(JDK动态代理也可以通过invoke方法判断当前是否想要改写的方法而进行处理,CGLib动态代理]对应为intercept方法),可以通过写一个代理处理类,就同时可以代理其他的类了,使用起来更灵活。
如果LuceneSearcher并不是通过实现接口的方式编写的,那么我们可以继承这个LuceneSearcher接口,并覆盖searchSong方法加入处理逻辑,这样也通过改动创建语句就可以很方便的对代码进行了调整。
Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com
通过把对象链接起来,给更多的对象处理请求的机会。
Java语言的异常处理实现使用了职责链模式;
把一个请求封装成一个对象,让请求被当成基于对象的形式进行处理,如回调。
任务队列
为文法提供一个解析的机制。
上个世纪80年代流行的基于文字的冒险游戏。
在不知道集合类实现的情况下,实现访问集合元素的功能。
Java的集合类就很好的用到了迭代器模式,允许用户在不知道集合的实现的情况下遍历各种类型的数据集合。
通过封装不同对象集的交互来达到解耦这些对象。
邮件群发系统,通过中介者模式,发送者无需记录哪些邮件地址是否注册了,把邮件发给中介者,中介者把邮件转发给有效的接收者。
在不违反封装性的前提下,允许捕获并且外化一个对象的内部状态,以便存储下来。
撤销动作,通过建立对象的一个快照实现。
在一个系统中,当一个对象的状态改变的时候,通知其他对象。
在大部分的GUI环境中都有用到这个设计模式,通过把按钮,文本区等注册为观察者,当一个用户触发一个事件,就发送一个通知到所有的观察者。
Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com
common-pool工具库是对池化技术原理的一种具体实现。
apache的连接池工具库common-dbcp是common-pool在数据库访问方面的一个具体应用。
Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com
接口尽量设计的单一职责,会方便代码的扩展和维护。
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 的配置文件中你定义的
Bean 的解析过程非常复杂,功能被分的很细,因为这里需要被扩展的地方很多,必须保证有足够的灵活性,以应对可能的变化。Bean 的解析主要就是对 Spring 配置文件的解析。这个解析过程主要通过下图中的类完成:
Bean的解析类
通过XmlBeanFactory实现启动Spring IoC容器
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的类关系图
正如图 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
39public 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 的原理和功能了。
这段代码主要包含这样几个步骤:
实现AbstractApplicationContext的refreshBeanFactory的refreshBeanFactory()子类的方法,可更新的子类AbstractRefreshableApplicationContext:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20protected 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,这个非常关键,因为他设计到后面对这个对象的多种操作,下面看一下这个类的继承层次类图:
Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com
Spring框架的7个模块:
核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
Author: arthinking
Weibo: arthinking_plus
Posted in:
1 | ResourceUtils.useCachesIfNecessary(con); |
设置URLConnection
的UseCaches
为false,主要是为了防止在Windows下jar包被锁住。
里面包含了JBoss vfs协议URL文件的获取。通过静态内部类 VfsResourceDelegate 进行处理的
是一个策略接口,其 getResource(String location)方法根据传入不同的location,返回不同的Resource。其实现类是一个可以单独使用的ResourceLoader实现类,ResourceEditor也使用了这个类
ResourceLoader的默认实现,可以单独使用,ResourceEditor使用了该类,是AbstractApplicationContext的基类。
XmlBeanFactory通过Resource装载Spring配置信息并启动IoC容器;
然后通过BeanFactory#getBean(beanName)方法从IoC容器获取Bean;
通过BeanFactory启动IoC容器时,并不会初始化配置文件中定义的Bean,初始化动作发生在第一个调用时;
对于单实例的Bean来说,BeanFactory会缓存Bean实例,所以第二次使用getBean()获取Bean的时候将直接从IoC容器的缓存中获取Bean实例。
问题
描述
回答
参考网址
举报test
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 中详细说明。