|
该用户从未签到
|
源代码分析,是一件既痛苦又快乐的事情,看别人写的代码是通过的,但当你能够看明白的时候,相信快乐也会随之而来,为了减少痛苦,更快的带来快乐,在这里希望通过这篇文章对觉得困难的朋友有一个帮助。
5 g Z# s- K5 l9 z0 S* ^/ d+ H( g m: }) [+ L& y/ r! P
本文以spring框架的XmlBeanFactory为入手点进行分析,希望能够以尽量简洁明了的方式给予有需要的朋友一定的帮助。
7 h' R' I9 f$ Y& {" }
1 \% \1 e8 `& x4 g% v. y1 e 首先来打开该类的代码,我们将看到如下代码:
' o8 c4 z3 M2 n% d9 a0 ]7 b8 ^以下内容为程序代码:* X% K7 Y, n+ w7 z& Y2 U
$ d9 v* A5 ^* a" d/ c
public class XmlBeanFactory extends DefaultListableBeanFactory {" i! @- \1 l. K u5 J* K, W2 v
3 a7 \' n) @; S) z* _
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);! G# N$ }' Z: g+ M2 b! F
( j4 f( M q9 h! K
public XmlBeanFactory(Resource resource) throws BeansException {
7 c4 }2 O+ p4 Y this(resource, null);" H; ^& k, w& G+ L' Y2 l
}$ v: p8 b [2 b$ a! o
+ g2 d$ j- K3 j- d D; Y1 [ public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {, U, s% s7 c; {+ o! I
super(parentBeanFactory);
3 \8 f) ~( c( p$ O this.reader.loadBeanDefinitions(resource);" Q4 [4 [- |. O( P/ y) }) J
}
* K3 @+ ~( M; j& C' K6 o) y" e( O: R0 N. Y3 |7 ~
}. H* w& k+ |9 ]1 M) ~2 n
' _; u7 D5 I7 Z# o5 \
8 A6 m9 e0 ]5 I/ ^5 Q3 M2 A
这个类的代码很简单,一个成员对象加两个构造函数,从这里我们可以看出,最重要的地方在于最后一个构造函数:8 X5 ~- o ^ s. F
- _6 Y0 K( g- \! ?
以下内容为程序代码:
2 q7 D% g! m Y! \/ u' g4 X1 n. W4 u+ T* T" H8 u: d
super(parentBeanFactory);# r2 l+ h# Y( v5 J2 [* }* R
this.reader.loadBeanDefinitions(resource);
1 p, _- d. @# |% W7 }6 M" j/ v( ]$ s; c+ h3 ]
/ p3 P4 H" v' E) i% V; Q 第一句就是将父亲工厂交给父类的构造函数,实际上最后也就是把父工厂保存到类的parentBeanFactory成员对象中,这个对象是在AbstractBeanFactory抽象类中定义的,而这个父工厂也会一直传递到该抽象类进行保存。第二句就是整个类中最重要的地方了,顾名思义,它的目的是通过XmlBeanDefinitionReader这个XML的Reader从资源resource中(也就是你的配置文件)读取bean的定义。接下来我们打开XmlBeanDefinitionReader的loadBeanDefinitions方法,我们可看到在这个方法里代码就一行,调用了一个同名不同参的方法,而参数是EncodedResource的一个实例,这个类实际上是Resource的一个包装类,用来保存资源的Encode的,那接下来我们再看被调用的loadBeanDefinitions方法,这个方法里最主要的部分就是:& d8 C; V& r9 T7 e- c" b4 m! L* |
7 l3 v8 M; J# W8 \3 w0 {以下内容为程序代码:- @5 R6 K, R. E
7 s W/ e, t% m/ _6 }4 \
InputSource inputSource = new InputSource(inputStream);3 c- [0 O7 j; v) [4 Q; g- P4 z
if (encodedResource.getEncoding() != null) {
+ c: d# t# ~" P; ]4 h' l3 @3 U inputSource.setEncoding(encodedResource.getEncoding());
5 I! p+ h( W! @6 @ }
6 r" i* S+ ^& u1 @& E return doLoadBeanDefinitions(inputSource, encodedResource.getResource());( Z8 M$ U- j5 K7 B2 a$ J
- f' ^1 p: N/ N7 m/ P0 T& J* D8 E8 A: z8 {. R
这里的目的是将资源包装成一个InputSource,连同Resource作为参数传递到doLoadBeanDefinitions方法
: `; G K$ I) Y0 ^9 \
3 N9 p+ S* h( u% x8 @- 8 ^5 W! T) G- @/ ]/ G0 @
- DocumentBuilderFactory factory = createDocumentBuilderFactory();( v/ p a; l, Y$ a% U; g7 T
- if (logger.isDebugEnabled()) {
2 |: I7 c, \5 ?) ^3 q$ ~" }) W - logger.debug("Using JAXP implementation [" + factory + "]");
) ?* g, l3 N! ~1 L2 u - }
# U* ?# F7 b& a" d - DocumentBuilder builder = createDocumentBuilder(factory);
% m/ l' s% h; Z* X$ ^# f - Document doc = builder.parse(inputSource);
: [& k3 d' q( `' e$ n/ C) p - return registerBeanDefinitions(doc, resource);- C4 T& _5 w( a4 K
复制代码 7 O+ r, \3 j5 M$ T
. m( A# M! {. }; G1 |1 B6 u0 P 这个方法的目的一目了然,就是为了将资源解释成为Document对象,然后调用registerBeanDefinitions方法,这里不做详细解释,不了解的话请去看看关于JAXP的介绍。接下来我们打开registerBeanDefinitions方法:* i; u4 z. G% z- k2 E) g. f/ H& a
以下内容为程序代码:6 D7 J/ y {# M' \
I% o; l0 G# |7 k/ M/ j public int registerBeanDefinitions(Document doc, Resource resource) throws BeansException {, b( C) r& Z, \9 z) T! ?' I. J
XmlBeanDefinitionParser parser =
( }0 I# f* M# ?8 Q2 T8 s+ R (XmlBeanDefinitionParser) BeanUtils.instantiateClass(this.parserClass); {- m! y5 L$ t6 X* ^3 b1 _7 D; Z
return parser.registerBeanDefinitions(this, doc, resource);& X9 A+ f) ~; J: m
}
8 M2 q1 d3 }& m. h& Q8 A& q5 f. ]/ N
8 q9 O& z7 h" j7 m' Z5 L1 I
5 U: C4 [. j; C% ` O 这里创建了一个XmlBeanDefinitionParser接口的实现,这个接口的具体类是DefaultXmlBeanDefinitionParser,这个接口很简单,只有registerBeanDefinitions一个方法,这个方法的作用也很明了,就是用来注册Bean的定义的,所以说类和方法的名字一定要起得有意义,这样可以让人一看就大概了解其作用,减少了很多阅读代码的痛苦。废话不多说,我们打开DefaultXmlBeanDefinitionParser的registerBeanDefinitions方法,这个类就是解释XML配置文件的核心类了,打开registerBeanDefinitions方法后我们看到如下代码:
* Z# C' f" \' M) z+ z3 {. g以下内容为程序代码:
, }! }- f. {/ O2 {- V) b$ L) p) P0 @& o7 R" m0 \
public int registerBeanDefinitions(BeanDefinitionReader reader, Document doc, Resource resource)
! h- U" r1 ^0 x% p. ] throws BeanDefinitionStoreException {
1 D8 \9 ^/ @8 y, @3 k9 Y7 N J' F g% ?
this.beanDefinitionReader = reader;- ^" I0 {& S5 l K
this.resource = resource;2 Z k; W; `8 |# t4 `
3 j7 m7 Q+ Z( Z& ]$ S
logger.debug("Loading bean definitions");
# u, w4 a8 G6 G6 U: M5 d$ A/ u Element root = doc.getDocumentElement();4 \! a+ |: F2 m% ]
//初始化根元素
- h! S/ ]6 ^" T0 p( _3 u initDefaults(root);
, j) l; |9 t" r* V, k* D* g! I7 Q if (logger.isDebugEnabled()) {
# R/ j' f4 _9 s/ L, M$ w" `- ]* v logger.debug("Default lazy init '" + getDefaultLazyInit() + "'");
2 |' j) ^! {% `/ a" W logger.debug("Default autowire '" + getDefaultAutowire() + "'");2 j* K+ d8 J& ^/ [
logger.debug("Default dependency check '" + getDefaultDependencyCheck() + "'");8 C1 p- V- E) H" `- V
}4 N0 J2 E3 m$ p
) i `# [5 e/ K4 D2 P5 B- @
preProcessXml(root);//一个空方法用于扩展+ n3 b8 U& S& V; p2 B
int beanDefinitionCount = parseBeanDefinitions(root);//解释配置的主要方法/ A- b3 y. k7 t" S. I4 i6 }
if (logger.isDebugEnabled()) {% E- _) R% H) V& c4 \% X9 U! P
logger.debug("Found " + beanDefinitionCount + " <bean> elements in " + resource);
, |8 [# C: L) k. k2 j3 j$ s, }. a }6 {5 r3 T7 P8 i5 |; L' f
postProcessXml(root); //一个空方法用于扩展2 v8 e4 B5 d0 D. K$ V: ~1 P
8 ]2 q, l8 F0 N4 i9 i
return beanDefinitionCount;
) \3 ?2 {* Q8 o3 q }
9 d* Y8 X# W4 q" m" C1 a1 J U) y. G5 d! D* S4 |/ b; u
7 x7 t) ?; k8 g7 Q6 t# ]9 W
在这个方法当中,主要用于解释定义的有两个方法,一个是initDefaults,一个是parseBeanDefinitions,第一个方法是用来解释根元素的属性的,例如lazy-init, autowire等,而parseBeanDefinitions就是用来解释具体的bean定义了,方法代码如下:2 M8 Y" E# F7 b; b! Z# o9 m4 k
以下内容为程序代码:
# @3 [( o8 _8 T5 s9 g. H) M. p; V1 H+ F0 a- Q5 K' O4 G% t9 p
protected int parseBeanDefinitions(Element root) throws BeanDefinitionStoreException {
4 \: ]0 f/ u) B# N( `8 A7 d" m" d+ n NodeList nl = root.getChildNodes();7 J8 |9 K9 p l0 }
int beanDefinitionCount = 0;0 k- I8 _* x4 Z! J: b0 n
for (int i = 0; i < nl.getLength(); i++) {% F- }2 ?$ f' @, }( r, N9 ?
Node node = nl.item(i);2 U) T3 B" z' F5 B$ A/ e! \
if (node instanceof Element) {) U% B; A/ y% X8 t
Element ele = (Element) node;
, _9 R) e" c8 ?8 m6 o& a if (IMPORT_ELEMENT.equals(node.getNodeName())) {
" a! V+ |/ h3 m, @ importBeanDefinitionResource(ele);
: m: c! u: d& Z* Z$ Y }. ]1 C# u8 j/ j" }+ X3 W; o
else if (ALIAS_ELEMENT.equals(node.getNodeName())) {
' K+ I$ y) x/ \1 }+ ^2 D String name = ele.getAttribute(NAME_ATTRIBUTE);
$ W8 q4 D7 J' X) @' N1 |6 Y String alias = ele.getAttribute(ALIAS_ATTRIBUTE);' U" D. t$ |/ M! k& g
this.beanDefinitionReader.getBeanFactory().registerAlias(name, alias);
/ K ~4 |/ d' P3 h' b }
( i; p! z8 e& _ else if (BEAN_ELEMENT.equals(node.getNodeName())) {1 \6 _ b7 F2 B& g. |3 L* q
beanDefinitionCount++;
) t& f! B' ^6 C7 T BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele, false);
( w' A5 N+ V( }; a+ Y$ W- v BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.beanDefinitionReader.getBeanFactory());
1 m4 }$ n% w" s8 N6 S( y4 v3 `# r }1 \+ e" a$ v! I' {5 }6 S
}* V% m& ]2 ^4 m) K( e
}2 F- T4 z2 \8 p* [9 }1 y
return beanDefinitionCount;5 A: A) ?( x" x/ E9 G# c7 p! T
}+ s- w- W a" H9 F
) P2 W2 _ x# N0 |0 V6 [" W/ t
4 ^4 d3 p) Q; r/ V! I% h9 Y, I7 @ 其他标签具体如何被解释这里就不多说,相信大家也能看得懂,这里主要讲一下解释bean的的处理,我们注意以下代码:8 c [& t, D, N7 n6 r: U
以下内容为程序代码:" T |: N7 ^4 ?" y
$ F& {3 @ |0 l8 u% e/ w" f3 q1 S! E else if (BEAN_ELEMENT.equals(node.getNodeName())) {7 Y( @2 E: {; ?# e! z$ i
beanDefinitionCount++;; ]( a" z8 b ]& k' w7 P3 a
BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele, false);" h |2 X+ H+ m8 a6 z. L/ X |
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.beanDefinitionReader.getBeanFactory());0 Y7 U5 s+ O' N. b7 k
}
- c" B0 I- W: t4 E' Q9 k% s2 ?3 X ?: B( P& l" j2 Q' t
这里是当碰到一个bean标签的时候所进行的处理,也既是对bean的定义进行解释,可以看到parseBeanDefinitionElement方法的第一个参数就是bean则个元素,第二个参数表示该bean是否为内置的bean,从这里进行解释的bean都不可能是内置的,所以这里直接以false为参数,打开parseBeanDefinitionElement方法,就可以看到这个方法里就是对bean的内部的解释,也很简单,也不多讲了,呵呵(下班时间已经到了,所以就写这么多了,基本的流程也就这样,没什么特别难的地方。),对了,最后还有一点就是解释完后,bean的定义将会被保存到beanFactory中,这个beanFactory的实现就是XmlBeanFactory了,该beanFactory是在new的时候被传递到reader中的,就是该类中以下这行代码:( g$ ]. [+ M& x. z5 p. a
以下内容为程序代码:
" L5 l; K9 k% k: ^: A
' d0 v+ R( f- a0 n private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
' H, q! w1 C2 X1 Y4 J8 B7 M
9 H! A+ Z6 C3 a0 [$ [0 l: t/ \' _4 E6 L* B
好了,就这么多了,本文只作为参考,只讲解了如何加载bean定义这块,只作为一个参考,希望对其他朋友能有所帮助吧,因为时间匆忙,有错漏的地方请指正。 |
|