该用户从未签到
|
源代码分析,是一件既痛苦又快乐的事情,看别人写的代码是通过的,但当你能够看明白的时候,相信快乐也会随之而来,为了减少痛苦,更快的带来快乐,在这里希望通过这篇文章对觉得困难的朋友有一个帮助。- h: v3 g R- Y$ z) l5 g3 S
5 u& z9 X1 V, O0 A: J( m( |' k
本文以spring框架的XmlBeanFactory为入手点进行分析,希望能够以尽量简洁明了的方式给予有需要的朋友一定的帮助。
' U# a4 g$ q- Y1 i
2 y6 I) L4 V X2 t" O# K+ M 首先来打开该类的代码,我们将看到如下代码:
# R F& y4 ^' a以下内容为程序代码:
& f! l) \+ P! |4 q" {& G
K5 Q: H/ i& p/ B5 bpublic class XmlBeanFactory extends DefaultListableBeanFactory {
5 R' H3 \: V. Z9 q8 O8 T- A! e( G) F( R2 p
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);8 ~1 h) b, D7 h! L+ ~* q
9 ^; X- N, a/ E4 e) y* n2 y
public XmlBeanFactory(Resource resource) throws BeansException {
( ~' X2 Y. A- J5 J$ J this(resource, null);
$ f! T$ ?' A; ]* W" C& ` }
; I9 f' c/ F W" S/ i$ e$ p' d7 R( n; F0 F) F! F& i3 c
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {" g7 _ h1 X ?; Z R
super(parentBeanFactory);
4 ~6 x5 l4 R, ~& b8 W* } this.reader.loadBeanDefinitions(resource);$ g& T: R0 v. i+ H! Q$ }6 o
} a: o) J% G5 c
3 Y, d; H8 b! x; }; Z+ C}; A. o- C6 p. t" p
|1 n; u& c' A
, a) @. Q" C( l4 T! R: p6 J 这个类的代码很简单,一个成员对象加两个构造函数,从这里我们可以看出,最重要的地方在于最后一个构造函数:) _) q3 ^8 T& j- F/ L
9 _/ E! l: q' [2 s
以下内容为程序代码:
+ f( y( |! j: @3 D5 V
8 F3 V( v j( ^' D k- W3 x- M6 @ super(parentBeanFactory);
/ L, @9 O: Q" w3 W this.reader.loadBeanDefinitions(resource);
3 ?! q, y0 k( g# |3 Q v( P/ V6 w: B c% u- ?( |2 {! {, W
8 m, A: C. ]$ l$ y: C" F! Q 第一句就是将父亲工厂交给父类的构造函数,实际上最后也就是把父工厂保存到类的parentBeanFactory成员对象中,这个对象是在AbstractBeanFactory抽象类中定义的,而这个父工厂也会一直传递到该抽象类进行保存。第二句就是整个类中最重要的地方了,顾名思义,它的目的是通过XmlBeanDefinitionReader这个XML的Reader从资源resource中(也就是你的配置文件)读取bean的定义。接下来我们打开XmlBeanDefinitionReader的loadBeanDefinitions方法,我们可看到在这个方法里代码就一行,调用了一个同名不同参的方法,而参数是EncodedResource的一个实例,这个类实际上是Resource的一个包装类,用来保存资源的Encode的,那接下来我们再看被调用的loadBeanDefinitions方法,这个方法里最主要的部分就是:" F5 _% ~6 P1 S' j7 [
5 V2 G+ G5 w+ H V6 D$ m7 l以下内容为程序代码:* I- T- `; ?$ h! @7 K2 V
) q6 n! J7 j( w6 q; a
InputSource inputSource = new InputSource(inputStream);4 z* n6 n5 q- Z# X
if (encodedResource.getEncoding() != null) {- ~! x" ?0 a( ?- d7 w
inputSource.setEncoding(encodedResource.getEncoding());
5 |8 }, |" k& i5 L }/ b s. I$ x# n: j! i9 p }) N8 ]3 j
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());7 p0 i" U0 [4 \" N0 h8 C
$ G0 F. {4 o* E H) ?/ ^! [$ t2 p$ |6 L4 c: l2 l8 j% L5 g( U
这里的目的是将资源包装成一个InputSource,连同Resource作为参数传递到doLoadBeanDefinitions方法, N4 y* E: i/ ]; V# K5 U# c2 e
& X% M) x2 b1 \; d/ z; H
8 n- K1 w2 K0 s q. B- DocumentBuilderFactory factory = createDocumentBuilderFactory();9 b+ z9 h4 p) R0 a8 F$ j
- if (logger.isDebugEnabled()) {7 {1 v+ s ~/ k$ b' V
- logger.debug("Using JAXP implementation [" + factory + "]");
; X# k* W! j9 r5 M" m7 R - }% h& }3 t7 A0 _
- DocumentBuilder builder = createDocumentBuilder(factory);* X& J- Q( z+ E
- Document doc = builder.parse(inputSource);4 z/ d* a8 c! Y
- return registerBeanDefinitions(doc, resource);0 L# H& q; Z, N" }' j" l" k
复制代码 1 C7 |) t, @3 ^( k8 C" @& I& z! }
8 t ~& L2 t$ s+ [. M4 D& ? 这个方法的目的一目了然,就是为了将资源解释成为Document对象,然后调用registerBeanDefinitions方法,这里不做详细解释,不了解的话请去看看关于JAXP的介绍。接下来我们打开registerBeanDefinitions方法:
0 Y* ~5 v) o% m& O) x以下内容为程序代码:
* b+ W. V/ {: U' R" z5 j1 F' T# A* ?" G9 z- l5 A+ K8 a
public int registerBeanDefinitions(Document doc, Resource resource) throws BeansException {
0 h$ b" }1 ^) z) D XmlBeanDefinitionParser parser =
, C! ~+ {4 \% A: [" k) F, Y6 e (XmlBeanDefinitionParser) BeanUtils.instantiateClass(this.parserClass);3 `) T- ]9 ?5 v' W
return parser.registerBeanDefinitions(this, doc, resource);
" o) H* P9 ` d5 J" N }
5 X$ l- X7 N/ g" p* i1 Q8 {) ]5 `" n1 {/ A
* e; P9 L' `6 {1 T9 J
这里创建了一个XmlBeanDefinitionParser接口的实现,这个接口的具体类是DefaultXmlBeanDefinitionParser,这个接口很简单,只有registerBeanDefinitions一个方法,这个方法的作用也很明了,就是用来注册Bean的定义的,所以说类和方法的名字一定要起得有意义,这样可以让人一看就大概了解其作用,减少了很多阅读代码的痛苦。废话不多说,我们打开DefaultXmlBeanDefinitionParser的registerBeanDefinitions方法,这个类就是解释XML配置文件的核心类了,打开registerBeanDefinitions方法后我们看到如下代码:- f$ F' e9 _( \7 [: `$ a
以下内容为程序代码:
9 J/ z; m2 {5 K7 j, R/ ?/ D) {$ U, _8 N! ?
public int registerBeanDefinitions(BeanDefinitionReader reader, Document doc, Resource resource)
( d) z! W4 o+ _' S+ A- n throws BeanDefinitionStoreException {
: [, Y8 a) l) Z* H. T& w* ?1 ], M c" X0 I* x8 }
this.beanDefinitionReader = reader;
- J' p7 J. d& p7 B this.resource = resource;
7 g. L E0 P' N0 `3 p) {% K) }' ^: ~$ v
logger.debug("Loading bean definitions");/ S2 a, M6 Q2 _! }- V- @* u
Element root = doc.getDocumentElement();) p F8 d8 E$ n, [
//初始化根元素/ c1 e0 Y# e- p2 | ]# u# d
initDefaults(root);: R% p$ G. l$ D, A* P1 x3 ?8 c
if (logger.isDebugEnabled()) {) v4 a! ~8 `+ W
logger.debug("Default lazy init '" + getDefaultLazyInit() + "'");/ y2 V) @2 D/ @/ ?( [
logger.debug("Default autowire '" + getDefaultAutowire() + "'");
- l: d1 ]4 T. Z& p) m! b7 ` logger.debug("Default dependency check '" + getDefaultDependencyCheck() + "'");
! N: K: c# z' K. w }& \2 O2 |& X3 r2 n3 l. @
! w. Z5 y' ]& c+ d
preProcessXml(root);//一个空方法用于扩展3 K6 m9 d# @* y9 ?; W& q
int beanDefinitionCount = parseBeanDefinitions(root);//解释配置的主要方法* I: O" t" a8 s; N2 _) Y) d9 W; H
if (logger.isDebugEnabled()) {9 B3 `: t6 R7 W' e- E% I- L
logger.debug("Found " + beanDefinitionCount + " <bean> elements in " + resource);' n+ `, }3 W0 S; u" `+ S$ X
}$ ~, D/ U2 S# e2 w( d9 K
postProcessXml(root); //一个空方法用于扩展
$ ?6 V0 W( G4 ]: a& k
& P9 P5 ~, L' o. C" P; d return beanDefinitionCount;
; z z; C( k# Z% J5 P: ` d }
$ {. @% a$ J1 O, a* j$ q, S
8 X; |$ N+ o% R* S" z' d* d: ~# q; H4 `" Z! h+ ]2 b. v
在这个方法当中,主要用于解释定义的有两个方法,一个是initDefaults,一个是parseBeanDefinitions,第一个方法是用来解释根元素的属性的,例如lazy-init, autowire等,而parseBeanDefinitions就是用来解释具体的bean定义了,方法代码如下:
( P, s5 u" D9 z1 B6 M; x9 n6 o$ c0 R以下内容为程序代码:
3 k6 [8 a3 n* Q5 Q, n* G v/ K' n: y" l8 o; u, r8 e5 R2 j: ^
protected int parseBeanDefinitions(Element root) throws BeanDefinitionStoreException {
* i$ c6 v9 f4 o' S7 c- u NodeList nl = root.getChildNodes();
# C3 a$ Y F7 e: o5 L+ f, [# | int beanDefinitionCount = 0;. S; c- C3 b2 [. |) I- E
for (int i = 0; i < nl.getLength(); i++) {) |$ g/ E' ]; l! S6 T/ G! a
Node node = nl.item(i);
- p @3 z3 ^, N$ ]0 e if (node instanceof Element) {9 o# U p* [" I. r+ r
Element ele = (Element) node;
) d4 Y6 _2 I4 _( o' n' z$ r% [ if (IMPORT_ELEMENT.equals(node.getNodeName())) {
+ l- q- p0 i4 x9 @- A$ |- l importBeanDefinitionResource(ele);4 L/ O% Z, e* f5 {
}* B# c; k* a: B0 G P0 |$ I$ b! {
else if (ALIAS_ELEMENT.equals(node.getNodeName())) {( D# {2 ]( d' ]$ \* b" y
String name = ele.getAttribute(NAME_ATTRIBUTE);8 ^9 N6 Y! z# o
String alias = ele.getAttribute(ALIAS_ATTRIBUTE);) _, S3 N; s! n' K+ L& N
this.beanDefinitionReader.getBeanFactory().registerAlias(name, alias);
3 F2 m4 M5 E+ K& M# h* Y; t/ j }$ ^; V% J* y& j, o
else if (BEAN_ELEMENT.equals(node.getNodeName())) {0 q& P# ]4 v: [, @
beanDefinitionCount++;' z1 L4 B2 R2 D
BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele, false);! Y, C3 c8 _( L8 p) \ x: S J
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.beanDefinitionReader.getBeanFactory());
7 p$ R; C# T3 m0 K: v( `" \ }
3 m$ b$ q) k* Q) D9 d }- ^3 h8 m f- N+ ~. }9 q
} C, ?* ]1 y6 |) m
return beanDefinitionCount;6 S+ ?# A }1 C7 H8 \+ f
}
6 J' @ b8 [* Y/ {% a& Y: y% o* R H* j* G
. z L( H8 R1 G3 `& [; D- p4 z9 | 其他标签具体如何被解释这里就不多说,相信大家也能看得懂,这里主要讲一下解释bean的的处理,我们注意以下代码:$ H3 p1 V9 T6 n( c
以下内容为程序代码:
% }8 k8 K8 q/ i0 w6 W1 m' e+ [! ^( A
else if (BEAN_ELEMENT.equals(node.getNodeName())) {" G- A8 C( A. P; K6 \
beanDefinitionCount++;. I; e P6 R( g8 {
BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele, false);
4 A' O8 Z3 D9 d; `" s2 T BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.beanDefinitionReader.getBeanFactory());
: j( I4 d* h, R4 t }
: b$ d- {: q* u4 z. I1 v7 L+ N4 ]4 h) G7 e* i5 E
这里是当碰到一个bean标签的时候所进行的处理,也既是对bean的定义进行解释,可以看到parseBeanDefinitionElement方法的第一个参数就是bean则个元素,第二个参数表示该bean是否为内置的bean,从这里进行解释的bean都不可能是内置的,所以这里直接以false为参数,打开parseBeanDefinitionElement方法,就可以看到这个方法里就是对bean的内部的解释,也很简单,也不多讲了,呵呵(下班时间已经到了,所以就写这么多了,基本的流程也就这样,没什么特别难的地方。),对了,最后还有一点就是解释完后,bean的定义将会被保存到beanFactory中,这个beanFactory的实现就是XmlBeanFactory了,该beanFactory是在new的时候被传递到reader中的,就是该类中以下这行代码:
' \' ?- ^, M. ?+ C. b; K, p以下内容为程序代码:# v& _$ Q' _& p. @: P0 C
3 m2 X) i' b. n9 ~
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);0 A9 {) K% |$ m1 T. h
: h! g. |5 \6 H, y
1 o5 U- G: a$ ~- u5 @
好了,就这么多了,本文只作为参考,只讲解了如何加载bean定义这块,只作为一个参考,希望对其他朋友能有所帮助吧,因为时间匆忙,有错漏的地方请指正。 |
|