该用户从未签到
|
源代码分析,是一件既痛苦又快乐的事情,看别人写的代码是通过的,但当你能够看明白的时候,相信快乐也会随之而来,为了减少痛苦,更快的带来快乐,在这里希望通过这篇文章对觉得困难的朋友有一个帮助。
4 p, d! R& A/ `# F7 |! v' M: n
" X1 m9 Q8 \$ ~4 q* O4 Q9 h 本文以spring框架的XmlBeanFactory为入手点进行分析,希望能够以尽量简洁明了的方式给予有需要的朋友一定的帮助。
& _) ~1 f& k! N) N
) \0 x/ ~9 k+ o7 ~4 [' I' H 首先来打开该类的代码,我们将看到如下代码:( P0 V# X; l& a4 G: d ^- B6 ]4 P9 v
以下内容为程序代码:
3 _+ K& h/ k+ [: s+ `. K/ j4 o! M. A& j' C0 I! e* I3 q% u
public class XmlBeanFactory extends DefaultListableBeanFactory {. L& A+ f' h) ~7 l2 U. X4 H9 A+ K
/ y7 n K- z. W8 Y( z private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);0 _8 Q+ x, N% X8 Z; M! L5 h
) a. l( T% S7 c' Z1 r/ D+ @ public XmlBeanFactory(Resource resource) throws BeansException {' {# n. H+ L2 J9 b; }
this(resource, null);, T9 W% S4 y3 ~
}
0 p+ t7 S% H! Q) ?2 W7 V
I- A% T! I% r8 V" B public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {$ G- L6 a& Y9 V4 w
super(parentBeanFactory);
+ j$ I( G& e* [) I$ p this.reader.loadBeanDefinitions(resource);5 N; V+ F9 P$ t; `
}4 @: j$ d8 g! `1 V, m
! o* t2 Y( ^5 Z, |5 H% m
}% q3 f' i; N2 S2 O
8 C4 f: ^2 c0 W3 a2 G# x8 O
! n" w$ S" r( H: T
这个类的代码很简单,一个成员对象加两个构造函数,从这里我们可以看出,最重要的地方在于最后一个构造函数:3 C3 m* u$ U' N. M. y# H! \1 r
/ g }' d' ?6 @6 D+ p. Y以下内容为程序代码:& d4 o% D$ @$ ^" A& D7 ]- J
) q, T: r. D' g super(parentBeanFactory);
) ?, `1 U2 w5 K! G this.reader.loadBeanDefinitions(resource);3 G$ I1 _8 Q; {
: H+ y0 ~- w* }; W0 K: N8 L/ }
2 p o: I. ]; `; I 第一句就是将父亲工厂交给父类的构造函数,实际上最后也就是把父工厂保存到类的parentBeanFactory成员对象中,这个对象是在AbstractBeanFactory抽象类中定义的,而这个父工厂也会一直传递到该抽象类进行保存。第二句就是整个类中最重要的地方了,顾名思义,它的目的是通过XmlBeanDefinitionReader这个XML的Reader从资源resource中(也就是你的配置文件)读取bean的定义。接下来我们打开XmlBeanDefinitionReader的loadBeanDefinitions方法,我们可看到在这个方法里代码就一行,调用了一个同名不同参的方法,而参数是EncodedResource的一个实例,这个类实际上是Resource的一个包装类,用来保存资源的Encode的,那接下来我们再看被调用的loadBeanDefinitions方法,这个方法里最主要的部分就是:7 Q T& c9 T, Y: f
- B' D7 ~: O$ a1 X以下内容为程序代码:
" ?/ ~% N% E7 s, Z
5 i4 u+ k9 T3 u) [8 f+ Y. R InputSource inputSource = new InputSource(inputStream);; i* M7 t; ?5 O" D, X3 v+ r
if (encodedResource.getEncoding() != null) {- N$ x Y8 U1 o3 h/ y" O
inputSource.setEncoding(encodedResource.getEncoding());
+ v, s& o: ]$ A+ s0 S, r- X }. c$ @8 ~4 h! x0 Z! ?# `# W
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());0 K* p0 h; K J/ Q/ k0 F5 I( Q
7 s" w# Z* q- K1 `8 x
0 \# u6 g! y, u) z v 这里的目的是将资源包装成一个InputSource,连同Resource作为参数传递到doLoadBeanDefinitions方法+ u- t }5 ^' ^& h2 A2 S1 B# ?0 [1 ]& C
- m7 `% c" F; q8 r* ?. _/ G- - W6 C$ u l4 Q' G+ W
- DocumentBuilderFactory factory = createDocumentBuilderFactory();$ h2 D; ]+ {4 a# C6 m) \
- if (logger.isDebugEnabled()) {
' t1 K% h: D, f( j - logger.debug("Using JAXP implementation [" + factory + "]");
( D# a/ E! ]7 }1 A* q+ Q - }* d8 s8 J/ [# l0 s% \
- DocumentBuilder builder = createDocumentBuilder(factory);
* R* [7 z+ \6 @0 ]+ a4 w; V - Document doc = builder.parse(inputSource);& m/ Q, {/ ~" i, a" W( W
- return registerBeanDefinitions(doc, resource); P; Q9 r' [1 R* O( f$ r
复制代码 1 P, h Z- F" R# ]( B6 B! f3 a V
2 ]9 s1 A8 ]. w8 b9 n1 C 这个方法的目的一目了然,就是为了将资源解释成为Document对象,然后调用registerBeanDefinitions方法,这里不做详细解释,不了解的话请去看看关于JAXP的介绍。接下来我们打开registerBeanDefinitions方法:& G6 H5 g7 [8 j3 s: Z' Z4 c
以下内容为程序代码:
( W5 d, J* m# h B; g- q Q; `% N8 g5 O/ C$ |6 R
public int registerBeanDefinitions(Document doc, Resource resource) throws BeansException {6 a+ u4 @6 [* i2 ~7 ]$ V( @& \( V$ y
XmlBeanDefinitionParser parser =) G) H) W; D" V" j) r" Q" j+ s
(XmlBeanDefinitionParser) BeanUtils.instantiateClass(this.parserClass);
) k0 t8 @2 K5 | return parser.registerBeanDefinitions(this, doc, resource);* h L9 x1 i; O% d/ s3 U
}' Q' O) @; v- C2 N9 T
! o3 `* R7 c9 _& l- W
, Z; S) z5 T0 j- m# i: f5 J' R
这里创建了一个XmlBeanDefinitionParser接口的实现,这个接口的具体类是DefaultXmlBeanDefinitionParser,这个接口很简单,只有registerBeanDefinitions一个方法,这个方法的作用也很明了,就是用来注册Bean的定义的,所以说类和方法的名字一定要起得有意义,这样可以让人一看就大概了解其作用,减少了很多阅读代码的痛苦。废话不多说,我们打开DefaultXmlBeanDefinitionParser的registerBeanDefinitions方法,这个类就是解释XML配置文件的核心类了,打开registerBeanDefinitions方法后我们看到如下代码:
0 x+ D2 J/ z. a, o/ Q) E以下内容为程序代码:
/ {9 w2 w7 P2 M" |/ e/ S5 P
. ~% y8 ~3 i& a" K5 _# Z- B& u public int registerBeanDefinitions(BeanDefinitionReader reader, Document doc, Resource resource)# h) F( y M6 a6 s
throws BeanDefinitionStoreException {
& H% q$ U+ O/ ^) K% ]
) d/ {* S& Q. v: g" z X this.beanDefinitionReader = reader;
1 o( `0 L8 B) Z this.resource = resource;+ {5 w+ e$ ~& M0 `6 a! M) o, \+ F3 R$ F: i
- j9 D4 B# O5 M% P3 W$ Y
logger.debug("Loading bean definitions");
) a3 b1 x7 j( U2 h/ u! T( L Element root = doc.getDocumentElement();/ `: J3 [9 D% l# c: f6 m* c: Q( C
//初始化根元素
& R7 b" `3 I0 U8 J7 i; ^5 {6 A initDefaults(root);! T/ G+ `" ~: S3 N% w) c
if (logger.isDebugEnabled()) {
+ |# E1 x) |& }# G; H) o logger.debug("Default lazy init '" + getDefaultLazyInit() + "'");
* s& Z' D; h; S logger.debug("Default autowire '" + getDefaultAutowire() + "'");
# B6 h9 F3 c/ q) R; J' u9 m5 u logger.debug("Default dependency check '" + getDefaultDependencyCheck() + "'");
$ u) F |& i) t/ s: ] }
1 J; t+ r( k" B# g5 i& s
7 C" A+ C6 V0 V+ N1 K% H2 T preProcessXml(root);//一个空方法用于扩展
4 t! [: _" R, B0 X2 L4 Z' h3 w int beanDefinitionCount = parseBeanDefinitions(root);//解释配置的主要方法
; |* [# n3 F. W if (logger.isDebugEnabled()) {
. p. k# F) m$ H G0 l. \3 T logger.debug("Found " + beanDefinitionCount + " <bean> elements in " + resource);
; G5 g0 P. M. K: o. z) @0 F* I$ s }
8 S: ?! G: u0 B$ R7 F. U postProcessXml(root); //一个空方法用于扩展1 Z! L" Q# o. i$ [2 \: A- r
1 E$ r0 l6 \6 i+ U
return beanDefinitionCount;! n+ C; E2 ]9 A/ e5 S0 ^ N* r
}$ U: w$ R& f |& g$ W; P. j
- |2 U9 ]$ y5 c4 ~+ u
1 C5 V5 g# f3 {5 t" _/ D( A$ f 在这个方法当中,主要用于解释定义的有两个方法,一个是initDefaults,一个是parseBeanDefinitions,第一个方法是用来解释根元素的属性的,例如lazy-init, autowire等,而parseBeanDefinitions就是用来解释具体的bean定义了,方法代码如下:
9 B6 q. @# a" g. E) `8 N5 n& ^以下内容为程序代码:
7 C: Q8 k8 y8 r1 l" `9 V: T* E
! m1 a0 i y( y protected int parseBeanDefinitions(Element root) throws BeanDefinitionStoreException {+ ^! h2 w+ ]* I4 P. N
NodeList nl = root.getChildNodes();
9 @/ w, f, D: p6 {4 u int beanDefinitionCount = 0;
$ O# I4 Y: W8 M+ `+ I" z9 p# R$ p for (int i = 0; i < nl.getLength(); i++) {
; p3 j. u0 Y. M& r) i Node node = nl.item(i);1 [% Z1 K( @& Q) j$ X/ u. q8 M
if (node instanceof Element) {2 J/ i& V6 E8 c7 m; H/ |
Element ele = (Element) node;
% N' [! h8 m1 X, s, u+ n' Y if (IMPORT_ELEMENT.equals(node.getNodeName())) {
4 J# F/ z1 v; r importBeanDefinitionResource(ele);
# T% r% Z! A; ^! O; E2 h( B7 f. l }/ ?4 U$ V/ _: G z
else if (ALIAS_ELEMENT.equals(node.getNodeName())) {
- \- s, E: F3 S2 {( s String name = ele.getAttribute(NAME_ATTRIBUTE);
, B) e/ ^" R& k* Z/ \ String alias = ele.getAttribute(ALIAS_ATTRIBUTE);1 C0 M9 M5 J; K9 Q7 ]
this.beanDefinitionReader.getBeanFactory().registerAlias(name, alias);( [3 R$ r7 L# ~1 f: f4 S M
}$ c5 Y2 Z& m3 S1 D9 J. }
else if (BEAN_ELEMENT.equals(node.getNodeName())) {
% `. H$ k4 I$ ?3 f0 V1 o2 T6 |3 C$ Q y beanDefinitionCount++;
. z9 I. V: @3 b& w& R! V BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele, false);
: h+ I( u/ C! ^, ^. R. A BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.beanDefinitionReader.getBeanFactory());2 _, r0 m2 J6 G5 h) E
}) n U; |3 T: R' I) W, p
}
$ z% M1 F* h) P' P. }; p: c }
) Y) C+ S; i. u) U return beanDefinitionCount;0 {( ?2 r6 h1 Z
}
6 D1 ^8 `9 _7 M3 y$ o- f0 C) c5 y4 y" ]5 A( ?
0 f( B" ~/ _) \7 H5 w 其他标签具体如何被解释这里就不多说,相信大家也能看得懂,这里主要讲一下解释bean的的处理,我们注意以下代码:
( @+ ]( g4 N6 c: H! f% K以下内容为程序代码:
+ g$ A# p$ A ]9 r! M7 k: S9 O) y- h1 L3 f2 G
else if (BEAN_ELEMENT.equals(node.getNodeName())) {
4 c% g3 f8 w5 c beanDefinitionCount++;- X) W* P- j/ m$ P: R {
BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele, false);8 x5 ]& q5 S) A
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.beanDefinitionReader.getBeanFactory());/ N4 k% ~. v) s5 m" Q3 X
}
- \# u) _- H+ [9 Z# h$ L; h# S7 y. m
这里是当碰到一个bean标签的时候所进行的处理,也既是对bean的定义进行解释,可以看到parseBeanDefinitionElement方法的第一个参数就是bean则个元素,第二个参数表示该bean是否为内置的bean,从这里进行解释的bean都不可能是内置的,所以这里直接以false为参数,打开parseBeanDefinitionElement方法,就可以看到这个方法里就是对bean的内部的解释,也很简单,也不多讲了,呵呵(下班时间已经到了,所以就写这么多了,基本的流程也就这样,没什么特别难的地方。),对了,最后还有一点就是解释完后,bean的定义将会被保存到beanFactory中,这个beanFactory的实现就是XmlBeanFactory了,该beanFactory是在new的时候被传递到reader中的,就是该类中以下这行代码:' j& ~3 r, a- d: m& u
以下内容为程序代码:
2 `9 E3 f# [/ i2 g- L( I; R
. X# X6 \& n/ @* u% n1 D* v z private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
8 T+ R& B& @: i7 s6 H, P5 _7 `; n! }" W2 X- b, M0 }
K2 i; V4 e9 t
好了,就这么多了,本文只作为参考,只讲解了如何加载bean定义这块,只作为一个参考,希望对其他朋友能有所帮助吧,因为时间匆忙,有错漏的地方请指正。 |
|