该用户从未签到
|
源代码分析,是一件既痛苦又快乐的事情,看别人写的代码是通过的,但当你能够看明白的时候,相信快乐也会随之而来,为了减少痛苦,更快的带来快乐,在这里希望通过这篇文章对觉得困难的朋友有一个帮助。
& K U/ E' Q5 a3 x# S( g x2 E! @& @3 r8 @" T0 D) d
本文以spring框架的XmlBeanFactory为入手点进行分析,希望能够以尽量简洁明了的方式给予有需要的朋友一定的帮助。
" b8 ~- k9 J" j1 l* k! { _! ^$ p( q/ S/ }
首先来打开该类的代码,我们将看到如下代码:
7 V( X+ E5 w8 v7 G" _' e以下内容为程序代码:
0 n5 ]5 ^2 c9 o. G# w# F( c" d3 j2 o
0 H/ X+ ~; i* q/ K/ K7 _public class XmlBeanFactory extends DefaultListableBeanFactory {) ]4 A0 R5 U3 ?; O
: l% u$ S s! S private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);5 {8 C/ e' P# P q/ b- E0 _$ t- ?4 p
* D4 G+ Q' _; E7 G
public XmlBeanFactory(Resource resource) throws BeansException {( a% p9 e# Z! w4 X. U
this(resource, null);4 N# T' o; ~) Y8 X8 W
}3 {/ Y3 C* J7 \( T) [
0 t; F6 e1 g3 A) j P3 C public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
+ l+ g# c3 Q' T+ H" T# v' c super(parentBeanFactory);4 N3 i% W$ i9 t% |( m- |1 Z
this.reader.loadBeanDefinitions(resource);
$ g& @- U( G" p' J3 H5 k }! ]9 o+ s6 U1 e, I
" |$ t! m3 ^" V, r2 s# E* M" K% N/ w
}
2 u1 e6 _4 v4 F2 l. A5 j q
/ P: j! b9 Y) \* V' M6 [; O S* \
2 o M Q4 H+ F7 z" U1 v4 N# V' | 这个类的代码很简单,一个成员对象加两个构造函数,从这里我们可以看出,最重要的地方在于最后一个构造函数:( k& ^' Q; r& `7 m2 a+ |) s7 e0 |1 z
$ \% l/ ]# H3 t1 d6 o
以下内容为程序代码:; T9 Y: f- z0 [9 N
7 ]) [) @ p' h$ w9 @7 @ h" z super(parentBeanFactory);
0 a7 K1 ^& v2 k8 D5 [& ? J this.reader.loadBeanDefinitions(resource);
, D1 \) B6 c$ N; o0 a$ ~2 x/ X- E h+ F. f" }* N0 b% @# a/ X f
7 S0 [" j+ k8 n# n4 T0 Y/ ~( R 第一句就是将父亲工厂交给父类的构造函数,实际上最后也就是把父工厂保存到类的parentBeanFactory成员对象中,这个对象是在AbstractBeanFactory抽象类中定义的,而这个父工厂也会一直传递到该抽象类进行保存。第二句就是整个类中最重要的地方了,顾名思义,它的目的是通过XmlBeanDefinitionReader这个XML的Reader从资源resource中(也就是你的配置文件)读取bean的定义。接下来我们打开XmlBeanDefinitionReader的loadBeanDefinitions方法,我们可看到在这个方法里代码就一行,调用了一个同名不同参的方法,而参数是EncodedResource的一个实例,这个类实际上是Resource的一个包装类,用来保存资源的Encode的,那接下来我们再看被调用的loadBeanDefinitions方法,这个方法里最主要的部分就是:
9 K) j. x2 ?' X. p, j
5 j+ b- A3 e. K5 Z以下内容为程序代码:
" V6 Q- Y% e0 s `, a) U1 ?! g2 V! y0 x4 z! J" `
InputSource inputSource = new InputSource(inputStream);, c/ g$ |. P$ N: L6 f. p, n9 @
if (encodedResource.getEncoding() != null) {
. S, i b* c; i, G. _3 f inputSource.setEncoding(encodedResource.getEncoding());
; g/ x% p3 R2 K) x: U }
2 u% ^8 W _2 Z9 L- P return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
# G: ^6 E. ~- [" D" m+ y! U: e
' R' q k: }4 q& J1 ^% S: r2 G4 V8 x
这里的目的是将资源包装成一个InputSource,连同Resource作为参数传递到doLoadBeanDefinitions方法
- \. l3 H" f; ]9 t6 K( b2 {, B" M( I9 s% z. Z6 E
- , i, e: H0 N% g; X+ P7 g- m* Z' R# Q
- DocumentBuilderFactory factory = createDocumentBuilderFactory();. w9 v3 L2 z" c( g8 V2 I, @
- if (logger.isDebugEnabled()) {# e9 L& S. f2 K6 p% n4 k# c3 {* J1 ]
- logger.debug("Using JAXP implementation [" + factory + "]");
9 j& G8 k. q0 l( }5 F9 K! ` - }: [8 R2 A! d: ~' [: P. w+ U
- DocumentBuilder builder = createDocumentBuilder(factory);
: B7 w; B! O+ u% X0 J! t3 r - Document doc = builder.parse(inputSource);6 R; q( V$ r9 z' s1 o6 u0 n. ]! F
- return registerBeanDefinitions(doc, resource);
# p J- o* A& h J( J6 i' z8 f
复制代码
$ D. k( s) ~% |& J6 a: {
2 P8 N) C( O2 D6 `5 l 这个方法的目的一目了然,就是为了将资源解释成为Document对象,然后调用registerBeanDefinitions方法,这里不做详细解释,不了解的话请去看看关于JAXP的介绍。接下来我们打开registerBeanDefinitions方法:
, U" A/ w$ k- G以下内容为程序代码:
% ?" e, R6 c3 H4 q$ c
8 H; L. z+ V9 W# N5 L- S0 r8 p public int registerBeanDefinitions(Document doc, Resource resource) throws BeansException {7 p5 F5 P6 d3 B& D4 O% T2 o8 m% b" H
XmlBeanDefinitionParser parser =2 M" b! ` T C: h6 u& Z; V
(XmlBeanDefinitionParser) BeanUtils.instantiateClass(this.parserClass);0 c& A7 ~9 m% x* t) r
return parser.registerBeanDefinitions(this, doc, resource);1 d( B$ R4 ^ i4 d
}( n7 }9 h2 [% q4 C$ h
5 h2 |& t1 f1 n* P% @# D7 `8 K6 h/ W' E
这里创建了一个XmlBeanDefinitionParser接口的实现,这个接口的具体类是DefaultXmlBeanDefinitionParser,这个接口很简单,只有registerBeanDefinitions一个方法,这个方法的作用也很明了,就是用来注册Bean的定义的,所以说类和方法的名字一定要起得有意义,这样可以让人一看就大概了解其作用,减少了很多阅读代码的痛苦。废话不多说,我们打开DefaultXmlBeanDefinitionParser的registerBeanDefinitions方法,这个类就是解释XML配置文件的核心类了,打开registerBeanDefinitions方法后我们看到如下代码:) w& `2 G2 u$ h! k/ [* l S
以下内容为程序代码:
+ V* ^3 A6 `8 b1 T6 Y) E/ s, g( Y! ^# A
public int registerBeanDefinitions(BeanDefinitionReader reader, Document doc, Resource resource)
5 D+ I$ S$ z& Z6 h0 T throws BeanDefinitionStoreException {
+ C) I: o! u |0 b, X( u4 y2 P" {; }* j9 A# L, P. @3 a" i
this.beanDefinitionReader = reader;2 H, f6 F+ u+ m' v
this.resource = resource;3 s5 _# n1 ~: U8 E; U) r a
1 I {+ l" }3 H% O logger.debug("Loading bean definitions");9 M! L+ N' Q0 e' a: i2 p6 b
Element root = doc.getDocumentElement();
" Y- }. r7 \- a% r. r //初始化根元素; t, N( X& @$ C
initDefaults(root);5 h5 g- d) X0 @; L. ?( I
if (logger.isDebugEnabled()) {
5 G9 c. u9 s2 `4 S8 f logger.debug("Default lazy init '" + getDefaultLazyInit() + "'");0 W* T/ @: z5 r+ [3 ]
logger.debug("Default autowire '" + getDefaultAutowire() + "'");" d+ V, K- v Z$ c
logger.debug("Default dependency check '" + getDefaultDependencyCheck() + "'");1 M8 ?+ x l( I V
}
! |* J- ?) O" h" q5 Z
1 O z* x' X' h preProcessXml(root);//一个空方法用于扩展
+ f# r1 f9 G3 {- I int beanDefinitionCount = parseBeanDefinitions(root);//解释配置的主要方法
1 Y! z; V7 @9 q/ T if (logger.isDebugEnabled()) {
; q% r9 p" p. e$ d' \& S$ w4 `8 I logger.debug("Found " + beanDefinitionCount + " <bean> elements in " + resource);9 ?6 n0 t1 {9 M) T) t+ O7 q
}
" `" W/ a& Y7 ?/ w. ] postProcessXml(root); //一个空方法用于扩展
- V9 b5 u$ S3 Y B0 h& p5 ^% A( d9 k& A5 w8 r2 K
return beanDefinitionCount;
; C1 Q( y9 X6 a; i9 Q; P3 j }
- ?1 R+ i' I' P6 R) l
; |/ i& w, L: |" A$ x% l& e: x- |/ [" a7 J% v
在这个方法当中,主要用于解释定义的有两个方法,一个是initDefaults,一个是parseBeanDefinitions,第一个方法是用来解释根元素的属性的,例如lazy-init, autowire等,而parseBeanDefinitions就是用来解释具体的bean定义了,方法代码如下:
0 R/ ^- L* z* f- ^- E以下内容为程序代码:
: _* L, x: r3 G* c. n, `
# R" R! F: H- {$ }: C& I protected int parseBeanDefinitions(Element root) throws BeanDefinitionStoreException {
2 @- U/ [) B5 ? \5 c1 Y+ _( G NodeList nl = root.getChildNodes();& Y. V5 \+ q0 a/ N
int beanDefinitionCount = 0;3 P1 P5 O9 Q: }( O
for (int i = 0; i < nl.getLength(); i++) {+ a6 k8 G& I7 }: S
Node node = nl.item(i);3 A2 Q# V, ]6 D b' `5 ]' D
if (node instanceof Element) {
: O- I' K0 A( U Element ele = (Element) node;* l/ W2 \1 e8 u( W" f
if (IMPORT_ELEMENT.equals(node.getNodeName())) {
1 V- L, g3 B, Z% y4 E importBeanDefinitionResource(ele);
' ^* _: Y. v- r9 `; U# a. v }
. G- G. @% o. p5 o+ q else if (ALIAS_ELEMENT.equals(node.getNodeName())) {
/ L( J5 _! E7 ?8 r" D; S# m6 H String name = ele.getAttribute(NAME_ATTRIBUTE);6 C* U+ N: C6 ^9 Y4 I
String alias = ele.getAttribute(ALIAS_ATTRIBUTE);4 C2 O4 v* W4 K# t" U& y
this.beanDefinitionReader.getBeanFactory().registerAlias(name, alias);. E1 c( H( b. N5 y( N
}4 I4 Z5 y( @$ f: p$ ^6 V2 q
else if (BEAN_ELEMENT.equals(node.getNodeName())) {
3 t7 [: }) G' d' p) q* ~* V! N/ R2 ~9 p beanDefinitionCount++;( |8 ]" [. J9 d, |) s5 U9 l4 D
BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele, false);; i( C) U5 ?" H% Z. o- ^
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.beanDefinitionReader.getBeanFactory());
$ Q# s0 E* @- F# e( [! l }' [" X( }- N$ V# L
}
2 D$ h9 d" k' B& D7 R- V! P! f }* F" N5 S5 i/ a1 X5 ? F) N
return beanDefinitionCount;; z! {4 W+ ]: A; A, e1 l7 s( L. s
}
6 t0 e$ n- y; V+ }( `; l7 v, A2 z) H3 D7 _! T: J! b. I5 t
+ z8 G+ l: ?5 t4 _2 E2 L 其他标签具体如何被解释这里就不多说,相信大家也能看得懂,这里主要讲一下解释bean的的处理,我们注意以下代码:
8 P- l8 n: F* F* E8 d; f- z6 X以下内容为程序代码:$ X/ c( L. h+ t8 S" J3 R7 S1 O
/ L. U' b- e- w. y4 s6 y' `* {' G
else if (BEAN_ELEMENT.equals(node.getNodeName())) {
- k6 ]& V, k+ { a$ W w' y7 r beanDefinitionCount++;
+ C2 t; Z& s0 n5 x BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele, false);2 G f: M0 K7 Z' a/ a& c' m
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.beanDefinitionReader.getBeanFactory());' I' m' l3 D5 D
}+ d; V+ J+ y2 R# T, p I. m
y/ @2 n; d" ^7 ^7 E- Q 这里是当碰到一个bean标签的时候所进行的处理,也既是对bean的定义进行解释,可以看到parseBeanDefinitionElement方法的第一个参数就是bean则个元素,第二个参数表示该bean是否为内置的bean,从这里进行解释的bean都不可能是内置的,所以这里直接以false为参数,打开parseBeanDefinitionElement方法,就可以看到这个方法里就是对bean的内部的解释,也很简单,也不多讲了,呵呵(下班时间已经到了,所以就写这么多了,基本的流程也就这样,没什么特别难的地方。),对了,最后还有一点就是解释完后,bean的定义将会被保存到beanFactory中,这个beanFactory的实现就是XmlBeanFactory了,该beanFactory是在new的时候被传递到reader中的,就是该类中以下这行代码:
% N: b* z. {& b' ~以下内容为程序代码:
7 z' ^( s9 J3 X
$ z- n2 ` G% ~/ F, ^7 c" Z private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
; g q' O! t; [) g* i8 [* a( H! w0 m5 N2 ~( o5 g) ~1 A
# V8 Q5 _3 ~* O- y 好了,就这么多了,本文只作为参考,只讲解了如何加载bean定义这块,只作为一个参考,希望对其他朋友能有所帮助吧,因为时间匆忙,有错漏的地方请指正。 |
|