该用户从未签到
|
源代码分析,是一件既痛苦又快乐的事情,看别人写的代码是通过的,但当你能够看明白的时候,相信快乐也会随之而来,为了减少痛苦,更快的带来快乐,在这里希望通过这篇文章对觉得困难的朋友有一个帮助。3 ^; z* [/ ^/ {9 ~
& T* D) }4 T& o. X# T
本文以spring框架的XmlBeanFactory为入手点进行分析,希望能够以尽量简洁明了的方式给予有需要的朋友一定的帮助。
2 ^: u2 z! q h0 R/ s3 w
& @* y+ L5 B# ^+ f1 d$ z 首先来打开该类的代码,我们将看到如下代码:, H. A8 f% D c" \5 P4 f, a
以下内容为程序代码:
3 B9 T! J( C' ~7 d; [ r |; v( ^3 {) o" e# {/ A
public class XmlBeanFactory extends DefaultListableBeanFactory {
% v7 C/ M. N# }6 p. l% {% Y* y* V0 X6 ]# i& |+ L- f4 G
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);( O+ ?5 ]- {; Q: M# ~: w7 k
- m7 o3 V7 H- T) s/ j public XmlBeanFactory(Resource resource) throws BeansException {
0 H7 |% N+ ?3 _4 Y) }% j; j! ` z this(resource, null);
- F4 |- V8 H" p% U$ C }! z9 w4 E, x+ o; ~9 {
! s* U. K. I% d
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
/ {# k+ `- n+ _0 c Q& F super(parentBeanFactory);
3 d8 L" x( @* e$ v4 w this.reader.loadBeanDefinitions(resource);
2 e2 k! B% Q# |0 [9 O. u( ] }
. c2 _4 P9 M0 j
. C6 d- R, A4 ?. V( Y) @+ S}7 ~) A# k, @$ D0 l: Y0 i* \7 \1 W
# [$ _' |& i2 r% b# k* h! M0 e
* t! ]5 T' s* e2 Y, t+ n 这个类的代码很简单,一个成员对象加两个构造函数,从这里我们可以看出,最重要的地方在于最后一个构造函数:
8 w( {7 C6 [, z9 r8 m6 ?" O7 O
1 W& l" Q# t; C& \以下内容为程序代码:0 n4 b' A. x) e/ b
- P& l& |; Y$ s6 j" z7 v9 L1 K super(parentBeanFactory);
2 D9 q- E5 |# p6 L9 Q this.reader.loadBeanDefinitions(resource);2 E+ Q7 r" F5 L9 q" c) y9 l) a/ j
) u$ D/ k) N" Q! S/ `* V; n
& `8 Q7 ?% j: J/ V/ F! F) j 第一句就是将父亲工厂交给父类的构造函数,实际上最后也就是把父工厂保存到类的parentBeanFactory成员对象中,这个对象是在AbstractBeanFactory抽象类中定义的,而这个父工厂也会一直传递到该抽象类进行保存。第二句就是整个类中最重要的地方了,顾名思义,它的目的是通过XmlBeanDefinitionReader这个XML的Reader从资源resource中(也就是你的配置文件)读取bean的定义。接下来我们打开XmlBeanDefinitionReader的loadBeanDefinitions方法,我们可看到在这个方法里代码就一行,调用了一个同名不同参的方法,而参数是EncodedResource的一个实例,这个类实际上是Resource的一个包装类,用来保存资源的Encode的,那接下来我们再看被调用的loadBeanDefinitions方法,这个方法里最主要的部分就是:
# g, a# Z/ Z$ U7 J* X3 x, t9 C9 j! t4 f2 H( T" _/ j7 u
以下内容为程序代码:
6 ?) N1 Y8 d J0 Z* [/ {4 F/ Q/ \: {0 Q
InputSource inputSource = new InputSource(inputStream);) B5 `" D* I, x: B, T- Z' Z$ m
if (encodedResource.getEncoding() != null) {
& A T/ f; U! T. S: n6 z inputSource.setEncoding(encodedResource.getEncoding());9 m, M" a" ~" n
}
3 i |# T; M6 e9 h5 p. y7 Q return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
5 e% u, ~/ }7 Y( G* B. L, O* m n& c9 _. o
2 [0 h: B" r2 i4 n% P3 y 这里的目的是将资源包装成一个InputSource,连同Resource作为参数传递到doLoadBeanDefinitions方法
5 A* |2 q8 h9 @9 y8 X
+ C( Q6 l3 i4 m( P7 B% H1 u- ) t/ r6 M' V z. S4 ~7 q4 I
- DocumentBuilderFactory factory = createDocumentBuilderFactory();
8 w, U' m3 n1 ~) D8 j2 H8 x - if (logger.isDebugEnabled()) {5 @3 \3 \, H3 c/ `3 m0 D* z
- logger.debug("Using JAXP implementation [" + factory + "]");
, X ` ?. g: Z8 p$ |6 H5 x, { - }8 Z5 b# Q b" d1 f2 k! }
- DocumentBuilder builder = createDocumentBuilder(factory);
2 Z4 Y$ C3 B0 n, f" A( m6 H - Document doc = builder.parse(inputSource);4 Y4 ?, n. @% u5 B
- return registerBeanDefinitions(doc, resource);& G" S7 a0 N9 ^
复制代码 * ]5 I6 f+ g6 z% k, u1 {" {8 u
W. P# Q$ C7 g! y8 K" l4 o. @
这个方法的目的一目了然,就是为了将资源解释成为Document对象,然后调用registerBeanDefinitions方法,这里不做详细解释,不了解的话请去看看关于JAXP的介绍。接下来我们打开registerBeanDefinitions方法:0 P) Y3 f1 a8 _! i! d
以下内容为程序代码:3 y8 } {; P/ R
, r. v# _& J5 k3 _ ?3 F public int registerBeanDefinitions(Document doc, Resource resource) throws BeansException {
6 \( L9 [ q5 n5 p* F XmlBeanDefinitionParser parser =
' S1 b5 U' }% ? (XmlBeanDefinitionParser) BeanUtils.instantiateClass(this.parserClass);' R; V' _$ ~, @6 U( Y! e& ?
return parser.registerBeanDefinitions(this, doc, resource);2 E* P# o8 ?0 \% G: X
}
/ @( |3 r- V6 a- L+ @) G- v/ W" d; K6 l( D( C" t6 q+ G4 B
5 F2 N, k+ j+ `( i' m2 \
这里创建了一个XmlBeanDefinitionParser接口的实现,这个接口的具体类是DefaultXmlBeanDefinitionParser,这个接口很简单,只有registerBeanDefinitions一个方法,这个方法的作用也很明了,就是用来注册Bean的定义的,所以说类和方法的名字一定要起得有意义,这样可以让人一看就大概了解其作用,减少了很多阅读代码的痛苦。废话不多说,我们打开DefaultXmlBeanDefinitionParser的registerBeanDefinitions方法,这个类就是解释XML配置文件的核心类了,打开registerBeanDefinitions方法后我们看到如下代码:
- K& O7 _0 Z9 O0 N以下内容为程序代码:
+ H8 J" E6 s, |1 _& p# `% W
9 z3 ^" h U0 T8 F public int registerBeanDefinitions(BeanDefinitionReader reader, Document doc, Resource resource)/ m6 r) a9 l* R
throws BeanDefinitionStoreException {
' _3 w9 ~2 |) |7 G, `# p G& [$ y' i/ T5 t: h0 v" H
this.beanDefinitionReader = reader;
y, Y9 v: A0 [& B! V& ?) q this.resource = resource;
- I2 _ `+ n/ Q1 c; p& `
8 H2 i/ f- B9 a) i% X4 P logger.debug("Loading bean definitions");" v4 ~: i4 E; u$ l; e0 h* s
Element root = doc.getDocumentElement();$ S5 {: _! `* n4 D3 S; Y
//初始化根元素) R) o E; U, Y- |. O) }
initDefaults(root);. m7 n/ ?4 ?, b( ]* J6 E- U, I
if (logger.isDebugEnabled()) {
9 D& K7 b0 ?; i# |( _ logger.debug("Default lazy init '" + getDefaultLazyInit() + "'");
; [8 F j7 Q, B logger.debug("Default autowire '" + getDefaultAutowire() + "'");
: I2 O) o8 b8 J M, d6 p logger.debug("Default dependency check '" + getDefaultDependencyCheck() + "'");
3 W* S- Q$ A, `: y% b( z }
7 F% u& S4 {9 M4 f
, P/ E- ^8 C8 @& q& F* w preProcessXml(root);//一个空方法用于扩展
4 V( C% D j3 S+ K" ? int beanDefinitionCount = parseBeanDefinitions(root);//解释配置的主要方法
m! p; O. |' }0 d0 s" E4 { if (logger.isDebugEnabled()) {
Y, M" |* c+ C& F/ M! Q2 t logger.debug("Found " + beanDefinitionCount + " <bean> elements in " + resource);' v6 x) q3 A" { r
}
4 s$ S! T3 X. o6 j postProcessXml(root); //一个空方法用于扩展8 @& \, X- b y8 P+ I* [) l) h/ r+ o
& u! j0 ~8 E0 l! g8 W( ^0 O
return beanDefinitionCount;
& d: V+ |& l) r/ y8 l6 A }
" h! l- W0 O, p* X5 K& X) Y' _4 R
7 a! H1 P! r+ z8 v* b* s, y7 o: w+ b3 a$ A
在这个方法当中,主要用于解释定义的有两个方法,一个是initDefaults,一个是parseBeanDefinitions,第一个方法是用来解释根元素的属性的,例如lazy-init, autowire等,而parseBeanDefinitions就是用来解释具体的bean定义了,方法代码如下:
4 ~+ @3 {2 ]+ ^9 j- l: E以下内容为程序代码:- w0 w J0 E8 E
0 r! y; W4 y( L9 p
protected int parseBeanDefinitions(Element root) throws BeanDefinitionStoreException {
- C$ Y9 P2 h/ I3 o' ^' p( [( K NodeList nl = root.getChildNodes();. s3 a9 H b8 H+ ^
int beanDefinitionCount = 0;
6 i& z: O# ~& n3 S8 p, Q$ F3 u for (int i = 0; i < nl.getLength(); i++) {, d% ?) M; }/ Y
Node node = nl.item(i);' Q0 o7 H. i7 p# M, b8 f9 x
if (node instanceof Element) {) q. Z0 k) ^$ ~4 W, M4 ^. t7 t+ f
Element ele = (Element) node;$ `0 h. j9 J' P" r( \$ R' E9 Y
if (IMPORT_ELEMENT.equals(node.getNodeName())) {
' V3 D/ A3 V t5 G+ I. _ importBeanDefinitionResource(ele);$ `/ m1 [0 {" J1 S# I2 y9 d" l9 C ]
}
T+ x: e, Y) E8 E: f# C# e& K' G else if (ALIAS_ELEMENT.equals(node.getNodeName())) {8 C8 N& {% L4 p. N8 r: q
String name = ele.getAttribute(NAME_ATTRIBUTE);
4 O( f! x5 s! r String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
& u% N) @1 b& @ l# J this.beanDefinitionReader.getBeanFactory().registerAlias(name, alias);; F/ z* }* W- U* m4 x
}2 v" ?9 A) g. g) o3 s( a) ]* o
else if (BEAN_ELEMENT.equals(node.getNodeName())) {/ V2 F7 S7 v5 \6 X
beanDefinitionCount++;
2 Z! p& S: g3 H' G4 w$ v BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele, false);7 Y' B" Q8 \) ]3 f
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.beanDefinitionReader.getBeanFactory());
' O, U& o/ C4 H5 B, z8 }! O }& H( Y0 E1 h9 V; P
}
! L2 ~! ~1 X/ s4 Q }$ W) r J1 Y# `/ J0 i8 e, x
return beanDefinitionCount;- y; e1 _2 p4 M6 I: O
}' ^& ^$ n9 E' q0 |9 J7 H
$ Q. i4 ^1 D$ p
% x9 J& p' Z6 z5 N& y* L4 ]6 C1 \ 其他标签具体如何被解释这里就不多说,相信大家也能看得懂,这里主要讲一下解释bean的的处理,我们注意以下代码:. o& Q- W2 C" {/ u0 h
以下内容为程序代码:# q: c1 t- V/ B, c& z' A8 e [5 S
" R" v: v) Z& d U! `" {' ?# _& ?% p0 t4 K else if (BEAN_ELEMENT.equals(node.getNodeName())) {! z5 |2 n! M& H- i
beanDefinitionCount++;; H' `6 o; |) _
BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele, false);
" ^$ }, y$ T0 g) B t& S BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.beanDefinitionReader.getBeanFactory());$ t6 N, T( T$ q, i) S- [9 a) y* m8 a- ]
}
4 a0 P7 x9 E! U
8 ? v& x" F e# `: l3 h* f 这里是当碰到一个bean标签的时候所进行的处理,也既是对bean的定义进行解释,可以看到parseBeanDefinitionElement方法的第一个参数就是bean则个元素,第二个参数表示该bean是否为内置的bean,从这里进行解释的bean都不可能是内置的,所以这里直接以false为参数,打开parseBeanDefinitionElement方法,就可以看到这个方法里就是对bean的内部的解释,也很简单,也不多讲了,呵呵(下班时间已经到了,所以就写这么多了,基本的流程也就这样,没什么特别难的地方。),对了,最后还有一点就是解释完后,bean的定义将会被保存到beanFactory中,这个beanFactory的实现就是XmlBeanFactory了,该beanFactory是在new的时候被传递到reader中的,就是该类中以下这行代码:
. B/ y: g: g2 f5 Y; g- a以下内容为程序代码:# O" P" x& G+ \/ I! }& r0 G& b, Q7 O% f
r4 J& C& h! i+ ~" i) n private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);2 |4 x# L: C% I* n+ |4 j% F" x
8 x. J+ l9 n' @8 T, d7 v! L( h7 [, s6 d( ^1 y
好了,就这么多了,本文只作为参考,只讲解了如何加载bean定义这块,只作为一个参考,希望对其他朋友能有所帮助吧,因为时间匆忙,有错漏的地方请指正。 |
|