该用户从未签到
|
源代码分析,是一件既痛苦又快乐的事情,看别人写的代码是通过的,但当你能够看明白的时候,相信快乐也会随之而来,为了减少痛苦,更快的带来快乐,在这里希望通过这篇文章对觉得困难的朋友有一个帮助。
* o$ h* E8 e0 H$ p* P/ D
6 ~& ~4 R8 z1 I/ @4 [ 本文以spring框架的XmlBeanFactory为入手点进行分析,希望能够以尽量简洁明了的方式给予有需要的朋友一定的帮助。
9 o( L: [ p' W
+ y7 d: ] E9 ] 首先来打开该类的代码,我们将看到如下代码:
0 F3 L8 R/ f& o以下内容为程序代码:# G0 t6 b B7 d1 s( \2 Z6 y9 b
# O* O! P U# R% `* _
public class XmlBeanFactory extends DefaultListableBeanFactory {
7 }" {& S6 Q/ @- n! R
9 ~$ W; a5 m8 r/ {: ]5 I# v+ b private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
+ w6 n) t1 A0 c Z% \, \4 V& Z1 h" I
public XmlBeanFactory(Resource resource) throws BeansException {
' g1 X, y/ Y% u this(resource, null);$ q9 j' _! H$ q( C- L8 z
}/ W% {3 [+ O. R
( A9 P. Y. h) u2 N3 Z$ C: I" P
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
6 D. E6 t1 P" e h/ @+ i super(parentBeanFactory);; }# V2 u7 W8 z6 z: c
this.reader.loadBeanDefinitions(resource); S/ z+ t4 c6 }- k: d$ i
} p6 b! i. z8 r/ T2 E
% Q$ D) m& y U1 f( x& |/ ~}
# ?2 ^, T( o: G! b/ Y/ r: J1 |
8 A# Q) M! q: H3 M7 `. y
$ f! T7 z7 d) j8 E8 n3 T$ p: I 这个类的代码很简单,一个成员对象加两个构造函数,从这里我们可以看出,最重要的地方在于最后一个构造函数:4 |$ N7 a: I7 m* ]% J5 D* _
! K" j/ ?1 c- T' w& G3 ]3 {以下内容为程序代码:8 h5 n, R* u; I/ U
% V2 |& v- j7 c
super(parentBeanFactory);
' o5 y; A* Q4 F# i this.reader.loadBeanDefinitions(resource);/ w( \/ j* \' g8 g6 R2 c/ O
2 S& o$ i' k$ C1 |- s0 Y3 f
0 ]+ ]2 o# b% ~3 }
第一句就是将父亲工厂交给父类的构造函数,实际上最后也就是把父工厂保存到类的parentBeanFactory成员对象中,这个对象是在AbstractBeanFactory抽象类中定义的,而这个父工厂也会一直传递到该抽象类进行保存。第二句就是整个类中最重要的地方了,顾名思义,它的目的是通过XmlBeanDefinitionReader这个XML的Reader从资源resource中(也就是你的配置文件)读取bean的定义。接下来我们打开XmlBeanDefinitionReader的loadBeanDefinitions方法,我们可看到在这个方法里代码就一行,调用了一个同名不同参的方法,而参数是EncodedResource的一个实例,这个类实际上是Resource的一个包装类,用来保存资源的Encode的,那接下来我们再看被调用的loadBeanDefinitions方法,这个方法里最主要的部分就是:
- l p- o' ^/ D0 ]3 l+ F/ g& t2 [8 y: w8 P8 K
以下内容为程序代码:$ Y4 m4 n1 Q3 \0 K3 s. f4 p* m
! h% [+ Z4 K+ R, d6 ~) Y3 |3 u InputSource inputSource = new InputSource(inputStream);
: S; d0 S5 h! `3 a8 a if (encodedResource.getEncoding() != null) {
/ J( e. r- w9 x; L) n inputSource.setEncoding(encodedResource.getEncoding());, L' L4 B. ~. u7 M3 l D3 a( V
}+ }% a3 X% \: u
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
; R- m3 [1 X+ d$ d& E7 s1 ^6 U, E0 n; n1 C
! L2 f$ l8 j/ P4 z% C0 \& e
这里的目的是将资源包装成一个InputSource,连同Resource作为参数传递到doLoadBeanDefinitions方法
( c- z* d+ I2 J/ L: ~; y7 o) S' m
7 c2 H8 f0 b; F
+ Z& n( F8 q7 C- DocumentBuilderFactory factory = createDocumentBuilderFactory();5 g$ k- y; n" T
- if (logger.isDebugEnabled()) {8 e9 C! J# c0 e! h/ N" c
- logger.debug("Using JAXP implementation [" + factory + "]");+ R* ] t4 s7 a) S: @3 \
- }- s% W* c! d! o, b. p4 g" p
- DocumentBuilder builder = createDocumentBuilder(factory);$ ?6 v9 W7 a4 F+ u$ s
- Document doc = builder.parse(inputSource);5 N- @# b/ \2 ^
- return registerBeanDefinitions(doc, resource);
; j, |+ N/ r, V. k' a
复制代码
+ a3 b" C9 N5 J" M& t
5 [/ h5 p- p6 f4 u2 V 这个方法的目的一目了然,就是为了将资源解释成为Document对象,然后调用registerBeanDefinitions方法,这里不做详细解释,不了解的话请去看看关于JAXP的介绍。接下来我们打开registerBeanDefinitions方法:/ N1 {% G6 |* X) e- X
以下内容为程序代码:) B8 ^; v. L$ i1 \
& w% }$ S8 h# o+ @& r6 b5 o A: |
public int registerBeanDefinitions(Document doc, Resource resource) throws BeansException {" G0 a* I9 F* i ^% j* X
XmlBeanDefinitionParser parser =; _% Z3 P' w6 {+ A4 t
(XmlBeanDefinitionParser) BeanUtils.instantiateClass(this.parserClass);3 |' m$ g/ W, ?; K
return parser.registerBeanDefinitions(this, doc, resource);
$ l9 g& S6 t& e+ m+ E }/ [" x8 ]# M9 {0 K
; C' t& u2 C5 f/ u$ H" t- j- X- ]2 w+ c% i. w+ s" S: Y* a# M
这里创建了一个XmlBeanDefinitionParser接口的实现,这个接口的具体类是DefaultXmlBeanDefinitionParser,这个接口很简单,只有registerBeanDefinitions一个方法,这个方法的作用也很明了,就是用来注册Bean的定义的,所以说类和方法的名字一定要起得有意义,这样可以让人一看就大概了解其作用,减少了很多阅读代码的痛苦。废话不多说,我们打开DefaultXmlBeanDefinitionParser的registerBeanDefinitions方法,这个类就是解释XML配置文件的核心类了,打开registerBeanDefinitions方法后我们看到如下代码:) m9 q3 M( f" V5 R$ A M0 K( [
以下内容为程序代码:
/ B4 V9 k* y2 `. F
! d# }+ u u1 T% x" Y public int registerBeanDefinitions(BeanDefinitionReader reader, Document doc, Resource resource)
# E- x" c. `* [3 U% u% W throws BeanDefinitionStoreException {2 y5 L k, @2 N0 _
5 a' v; c8 M4 o+ ?
this.beanDefinitionReader = reader;
( |5 u) X* X2 A( B7 Z& D# ` this.resource = resource;: h) ^* `9 |7 r- S2 n
* F0 j+ U d( D6 O
logger.debug("Loading bean definitions");
- c* [/ u3 t# q# C Element root = doc.getDocumentElement();
, T+ w: b, v! B6 n. k$ M //初始化根元素
- C- L! e6 ^& ^! c initDefaults(root);7 _$ I1 n! E( d! n
if (logger.isDebugEnabled()) {* L1 L5 T; {. F8 s! Q6 F# Z
logger.debug("Default lazy init '" + getDefaultLazyInit() + "'");
N2 d' ]1 n/ I+ J2 ~2 u Z4 g logger.debug("Default autowire '" + getDefaultAutowire() + "'");
4 \2 w8 `) c, O, ~6 r% D logger.debug("Default dependency check '" + getDefaultDependencyCheck() + "'");; R$ n: ~2 d6 g0 K5 Q8 g d
}
! P: C1 M5 t# I6 C' E* X* x% K2 R t6 \( E
preProcessXml(root);//一个空方法用于扩展
* _' s5 E' a0 t5 I int beanDefinitionCount = parseBeanDefinitions(root);//解释配置的主要方法* V6 Y4 S( d& T0 u0 f9 k$ @
if (logger.isDebugEnabled()) {
/ O5 J; |5 B- d1 T logger.debug("Found " + beanDefinitionCount + " <bean> elements in " + resource); @7 ?2 x% j2 P" I: y6 P- J
}7 q8 A7 c9 K" Z8 |9 C
postProcessXml(root); //一个空方法用于扩展; o2 M6 b& O1 f
+ E! y* E4 c) s( F- m& w
return beanDefinitionCount;5 J4 w) {" w9 w+ T
}
, m5 |/ X8 x) B5 [5 E2 W' L7 ?$ F/ u3 S
/ O: n. z; @ _1 b/ _
在这个方法当中,主要用于解释定义的有两个方法,一个是initDefaults,一个是parseBeanDefinitions,第一个方法是用来解释根元素的属性的,例如lazy-init, autowire等,而parseBeanDefinitions就是用来解释具体的bean定义了,方法代码如下:
6 X( I8 k3 l1 S) S' O [5 z1 f以下内容为程序代码:
. |7 p# [" s! y# }5 D1 @! N" ^8 F/ k% z& a% Z6 O' M
protected int parseBeanDefinitions(Element root) throws BeanDefinitionStoreException {
" O1 f% n1 x, f4 Z" K, Q5 v NodeList nl = root.getChildNodes();" Z! B m% Q% E
int beanDefinitionCount = 0;
0 j: w, S+ K4 v! j- m! i) H for (int i = 0; i < nl.getLength(); i++) {2 r [/ s. C9 m) C* }, P8 d \( X
Node node = nl.item(i);! n, z+ K: e0 X$ ~" |
if (node instanceof Element) {' t2 c2 [$ f5 g
Element ele = (Element) node;' g1 d8 P" H4 `# |
if (IMPORT_ELEMENT.equals(node.getNodeName())) {/ n& q. ^0 A3 x. E) j2 V
importBeanDefinitionResource(ele);0 Z! A* L* M4 X# s
}, I$ g7 [9 P* H7 @4 v9 r3 D( N
else if (ALIAS_ELEMENT.equals(node.getNodeName())) {
7 S% ?% w& x% _ Q" ~ String name = ele.getAttribute(NAME_ATTRIBUTE);- N$ b5 g; ~, W1 u9 W1 T* w; M
String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
$ Y9 v' _9 r+ h. [3 H* X! d" o this.beanDefinitionReader.getBeanFactory().registerAlias(name, alias);
( J" {4 B3 v; o) N+ x }
4 P2 i6 [# ?3 s else if (BEAN_ELEMENT.equals(node.getNodeName())) {
8 e7 L! k3 k% ]# S beanDefinitionCount++;
* w ~, `6 C k; [% o, m9 B BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele, false);2 b3 C! j: g) f& M6 m
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.beanDefinitionReader.getBeanFactory());
4 j* i: m4 O6 j/ p) t }
+ ]( P0 b: w; {: m }- [0 {0 R4 y5 f
}3 j: c6 d2 j$ \8 f' `
return beanDefinitionCount;
2 Y; z: m( U* \" S; I& V6 X }* l$ G3 S4 I( u( u3 ]+ t J$ \0 |
6 r; f* N( _- C* M; Y
. ~5 L0 ^4 {2 o7 g: Q" n2 t 其他标签具体如何被解释这里就不多说,相信大家也能看得懂,这里主要讲一下解释bean的的处理,我们注意以下代码:
# I% S3 T. N. [* M- k3 `以下内容为程序代码:- s/ ~' K" g9 p D# d/ c
, W# h. F! f# w else if (BEAN_ELEMENT.equals(node.getNodeName())) {
# O0 a1 H1 ?7 ?6 N& B3 l) a beanDefinitionCount++;8 B9 R; B+ J5 N; B) p
BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele, false);$ `: v. H/ j8 c* `/ V9 [; Y
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.beanDefinitionReader.getBeanFactory());
% r" A% y* h6 N z* R }- I9 x# |: D# y" m$ _$ \
9 w. C1 ~) t. v% ]4 q: M" D8 V 这里是当碰到一个bean标签的时候所进行的处理,也既是对bean的定义进行解释,可以看到parseBeanDefinitionElement方法的第一个参数就是bean则个元素,第二个参数表示该bean是否为内置的bean,从这里进行解释的bean都不可能是内置的,所以这里直接以false为参数,打开parseBeanDefinitionElement方法,就可以看到这个方法里就是对bean的内部的解释,也很简单,也不多讲了,呵呵(下班时间已经到了,所以就写这么多了,基本的流程也就这样,没什么特别难的地方。),对了,最后还有一点就是解释完后,bean的定义将会被保存到beanFactory中,这个beanFactory的实现就是XmlBeanFactory了,该beanFactory是在new的时候被传递到reader中的,就是该类中以下这行代码:
6 O# |! w3 \9 T0 T! d以下内容为程序代码:
, v1 v( K1 ?" n# G
" l5 M5 |( {# S+ ] private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);, w5 z# \) S/ n: S4 q$ W0 ]; [
& A" S( W) k- H8 ?) N
. L% T: E( `; g8 A& g% {" X x 好了,就这么多了,本文只作为参考,只讲解了如何加载bean定义这块,只作为一个参考,希望对其他朋友能有所帮助吧,因为时间匆忙,有错漏的地方请指正。 |
|