⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 java开源笔记:spring源代码解析.htm

📁 springioc部分最新的分析
💻 HTM
📖 第 1 页 / 共 5 页
字号:
AOP的例子,在Spring声明式事务处理的源代码中我们可以看到:<BR>1.怎样封装各种不同平台下的事务处理代码<BR>2.怎样读取属性值和结合事务处理代码来完成既定的事务处理策略<BR>3.怎样灵活的使用SpringAOP框架。<BR>如果能够结合前面的Spring 
AOP的源代码来学习,理解可能会更深刻些。<BR>
<P></P>
<DIV style="CLEAR: both"></DIV></DIV>
<DIV class=post-footer>
<P class="post-footer-line post-footer-line-1"><SPAN 
class="post-author vcard">发表者 <SPAN class=fn>jiwenke</SPAN> </SPAN><SPAN 
class=post-timestamp>位置在: <A class=timestamp-link title="permanent link" 
href="http://jiwenke-spring.blogspot.com/" rel=bookmark><ABBR class=published 
title=2007-06-09T21:44:00-07:00>下午9:44</ABBR></A> </SPAN><SPAN 
class=post-comment-link><A class=comment-link onclick="" 
href="http://www.blogger.com/comment.g?blogID=4147982534777444487&amp;postID=5535501562609619884">0 
评论</A> </SPAN><SPAN class="post-backlinks post-comment-link"><A 
class=comment-link href="http://jiwenke-spring.blogspot.com/#links">指向此文章的链接</A> 
</SPAN><SPAN class=post-icons><SPAN 
class="item-control blog-admin pid-357757119"><A title=修改文章 
href="http://www.blogger.com/post-edit.g?blogID=4147982534777444487&amp;postID=5535501562609619884"><SPAN 
class=quick-edit-icon>&nbsp;</SPAN> </A></SPAN></SPAN></P>
<P class="post-footer-line post-footer-line-2"><SPAN 
class=post-labels></SPAN></P>
<P class="post-footer-line post-footer-line-3"></P></DIV></DIV>
<H2 class=date-header>2007年6月8日 星期五</H2>
<DIV class="post hentry uncustomized-post-template"><A 
name=5820869262907769498></A>
<DIV class=post-header-line-1></DIV>
<DIV class="post-body entry-content">
<P>下面我们来看看Spring的AOP的一些相关代码是怎么得到Proxy的,让我们我们先看看AOP和Spring AOP的一些基本概念:<BR><SPAN 
style="FONT-WEIGHT: bold; FONT-STYLE: italic; TEXT-DECORATION: underline">Advice:</SPAN><BR>通知,制定在连接点<SPAN 
style="BACKGROUND-COLOR: rgb(255,255,102)">做什么</SPAN>,在Sping中,他主要描述Spring围绕方法调用注入的额外的行为,Spring提供的通知类型有:<BR>before 
advice,AfterReturningAdvice,ThrowAdvice,MethodBeforeAdvice,这些都是Spring 
AOP定义的接口类,具体的动作实现需要用户程序来完成。<BR><SPAN 
style="FONT-WEIGHT: bold; FONT-STYLE: italic; TEXT-DECORATION: underline">Pointcut:</SPAN><BR>切点,其决定一个advice应该应用于哪个连接点,也就是需要插入额外处理的地方的集合,例如,被某个advice作为目标的一组方法。Spring 
pointcut通常意味着标示方法,可以选择一组方法调用作为pointcut,Spring提供了具体的切点来给用户使用,比如正则表达式切点 
JdkRegexpMethodPointcut通过正则表达式对方法名进行匹配,其通过使用 
AbstractJdkRegexpMethodPointcut中的对MethodMatcher接口的实现来完成pointcut功能:<BR>public 
final boolean matches(Method method, Class targetClass) {<BR>// TODO use target 
class here?<BR>String patt = method.getDeclaringClass().getName() + "." + 
method.getName();<BR><SPAN style="BACKGROUND-COLOR: rgb(255,255,102)">for (int i 
= 0; i &lt; this.patterns.length; i++) {<BR>// 
这里是判断是否和方法名匹配的代码,当然知道true或者false<BR 
style="BACKGROUND-COLOR: rgb(255,255,102)"></SPAN><SPAN 
style="BACKGROUND-COLOR: rgb(255,255,102)">boolean matched = matches(patt, 
i);</SPAN><BR style="BACKGROUND-COLOR: rgb(255,255,102)">if (matched) {<BR>for 
(int j = 0; j &lt; this.excludedPatterns.length; j++) {<BR>boolean excluded = 
matchesExclusion(patt, j);<BR>if(excluded) {<BR>return 
false;<BR>}<BR>}<BR>return true;<BR>}<BR>}<BR>return 
false;<BR>}<BR>在JDKRegexpMethodPointcut中通过JDK中的正则表达式匹配来完成pointcut的最终锁定<BR>protected 
boolean matches(String pattern, int patternIndex) {<BR>Matcher matcher = 
this.compiledPatterns[patternIndex].matcher(pattern);<BR><SPAN 
style="BACKGROUND-COLOR: rgb(255,255,102)">return 
matcher.matches();</SPAN><BR>}<BR><SPAN 
style="FONT-WEIGHT: bold; FONT-STYLE: italic; TEXT-DECORATION: underline">Advisor:</SPAN><BR>当 
我们完成额外完成的动作设计(advice)和动作插入点的设计(pointcut)以后,我们需要一个对象把他们结合起来,这就是通知器 - 
advisor,定义应该在哪里应用哪个通知。Advisor的实现有:DefaultPointcutAdvisor他有两个属性advice和 
pointcut来让我们配置advice和pointcut。<BR>接着我们就可以通过ProxyFactoryBean来配置我们的代理对象和方面 
行为,在ProxyFactoryBean中有interceptorNames来配置已经定义好的通知器-advisor,具体的代理实现通过JDK 
的Proxy或者CGLIB的技术来完成。我们可以看看具体的代码实现,在ProxyFactoryBean中我们看看怎样得到Proxy:<BR>public 
Object getObject() throws BeansException {<BR>initializeAdvisorChain();<BR>if 
(isSingleton()) {<BR>//根据定义需要生成单件的Proxy<BR><SPAN 
style="BACKGROUND-COLOR: rgb(255,255,102)">return 
getSingletonInstance();</SPAN><BR 
style="BACKGROUND-COLOR: rgb(255,255,102)">}<BR>else {<BR>if (this.targetName == 
null) {<BR>logger.warn("Using non-singleton proxies with singleton targets is 
often undesirable." +<BR>"Enable prototype proxies by setting the 'targetName' 
property.");<BR>}<BR>//根据定义需要生成Prototype的Proxy<BR><SPAN 
style="BACKGROUND-COLOR: rgb(255,255,102)">return 
newPrototypeInstance();</SPAN><BR 
style="BACKGROUND-COLOR: rgb(255,255,102)">}<BR>}<BR>我们看看怎样生成单件的Proxy:<BR>private 
synchronized Object getSingletonInstance() {<BR>if (this.singletonInstance == 
null) {<BR>this.targetSource = freshTargetSource();<BR>if 
(this.autodetectInterfaces &amp;&amp; getProxiedInterfaces().length == 0 
&amp;&amp; !isProxyTargetClass()) {<BR>// 
这里设置Proxy的接口<BR>setInterfaces(ClassUtils.getAllInterfacesForClass(this.targetSource.getTargetClass()));<BR>}<BR>// 
Eagerly initialize the shared singleton 
instance.<BR>super.setFrozen(this.freezeProxy);<BR>// 
注意这里的方法会使用ProxyFactory来生成我们需要的Proxy<BR><SPAN 
style="BACKGROUND-COLOR: rgb(255,255,102)">this.singletonInstance = 
getProxy(createAopProxy());</SPAN><BR 
style="BACKGROUND-COLOR: rgb(255,255,102)">// We must listen to superclass 
advice change events to recache the singleton<BR>// instance if 
necessary.<BR>addListener(this);<BR>}<BR>return 
this.singletonInstance;<BR>}<BR><BR>ProxyFactoryBean的父类是AdvisedSupport,Spring使用AopProxyFactory接口把AOP代理的实现与框架的其他部分分离开来;在AdvisedSupport中通过这样的方式来得到AopProxy,这里还需要AopProxyFactory的帮助 
- 下面我们看到Spring为我们提供了默认的实现可以帮助我们方便的从JDK或者cglib中得到我们想要的:<BR>protected synchronized 
AopProxy createAopProxy() {<BR>if (!this.isActive) 
{<BR>activate();<BR>}<BR><SPAN style="BACKGROUND-COLOR: rgb(255,255,102)">return 
getAopProxyFactory().createAopProxy(this);</SPAN><BR>}<BR>而在ProxyConfig中对使用的AopProxyFactory做了定义:<BR>//这个DefaultAopProxyFactory是Spring用来生成AopProxy的地方,<BR>//当然了它包含JDK和Cglib两种实现方式。<BR>private 
transient AopProxyFactory aopProxyFactory = new 
DefaultAopProxyFactory();<BR>其中在DefaultAopProxyFactory中是这样生成AopProxy的:<BR>public 
AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException 
{<BR>if (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass() 
||<BR>advisedSupport.getProxiedInterfaces().length == 0) {<BR>if 
(!cglibAvailable) {<BR>throw new AopConfigException(<BR>"Cannot proxy target 
class because CGLIB2 is not available. " +<BR>"Add CGLIB to the class path or 
specify proxy interfaces.");<BR>}<BR>// 
这里使用Cglib来生成Proxy,如果target不是接口的实现的话<BR><SPAN 
style="BACKGROUND-COLOR: rgb(255,255,102)">return 
CglibProxyFactory.createCglibProxy(advisedSupport);</SPAN><BR 
style="BACKGROUND-COLOR: rgb(255,255,102)">}<BR>else {<BR>// 
这里使用JDK来生成Proxy<BR><SPAN style="BACKGROUND-COLOR: rgb(255,255,102)">return new 
JdkDynamicAopProxy(advisedSupport);</SPAN><BR 
style="BACKGROUND-COLOR: rgb(255,255,102)">}<BR>}<BR>于是我们就可以看到其中的Proxy可以有JDK或者Cglib来生成,我们看到JdkDynamicAopProxy类和Cglib2AopProxy都实现的是AopProxy的接口,在JDK实现中我们可以看到Proxy是怎样生成的:<BR>public 
Object getProxy(ClassLoader classLoader) {<BR>if (logger.isDebugEnabled()) 
{<BR>Class targetClass = 
this.advised.getTargetSource().getTargetClass();<BR>logger.debug("Creating JDK 
dynamic proxy" +<BR>(targetClass != null ? " for [" + targetClass.getName() + 
"]" : ""));<BR>}<BR>Class[] proxiedInterfaces = 
AopProxyUtils.completeProxiedInterfaces(this.advised);<BR>findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);<BR>//这里我们调用JDK 
Proxy来生成需要的Proxy实例<BR><SPAN style="BACKGROUND-COLOR: rgb(255,255,102)">return 
Proxy.newProxyInstance(classLoader, proxiedInterfaces, 
this);</SPAN><BR>}<BR>这样用Proxy包装target之后,对其的调用就被Proxy拦截了,ProxyFactoryBean的getObject()方法得到的实际上已经是Proxy了。<SPAN 
style="BACKGROUND-COLOR: rgb(255,255,102)"></SPAN> </P>
<DIV style="CLEAR: both"></DIV></DIV>
<DIV class=post-footer>
<P class="post-footer-line post-footer-line-1"><SPAN 
class="post-author vcard">发表者 <SPAN class=fn>jiwenke</SPAN> </SPAN><SPAN 
class=post-timestamp>位置在: <A class=timestamp-link title="permanent link" 
href="http://jiwenke-spring.blogspot.com/2007/06/springaopproxyaopspring-aop-advice.html" 
rel=bookmark><ABBR class=published 
title=2007-06-08T02:51:00-07:00>上午2:51</ABBR></A> </SPAN><SPAN 
class=post-comment-link><A class=comment-link onclick="" 
href="http://www.blogger.com/comment.g?blogID=4147982534777444487&amp;postID=5820869262907769498">0 
评论</A> </SPAN><SPAN class="post-backlinks post-comment-link"><A 
class=comment-link 
href="http://jiwenke-spring.blogspot.com/2007/06/springaopproxyaopspring-aop-advice.html#links">指向此文章的链接</A> 
</SPAN><SPAN class=post-icons><SPAN 
class="item-control blog-admin pid-357757119"><A title=修改文章 
href="http://www.blogger.com/post-edit.g?blogID=4147982534777444487&amp;postID=5820869262907769498"><SPAN 
class=quick-edit-icon>&nbsp;</SPAN> </A></SPAN></SPAN></P>
<P class="post-footer-line post-footer-line-2"><SPAN 
class=post-labels></SPAN></P>
<P class="post-footer-line post-footer-line-3"></P></DIV></DIV>
<H2 class=date-header>2007年6月7日 星期四</H2>
<DIV class="post hentry uncustomized-post-template"><A 
name=7659085064913675164></A>
<DIV class=post-header-line-1></DIV>
<DIV class="post-body entry-content">
<P>下面我们对Spring MVC框架代码进行分析,对于webApplicationContext的相关分析可以参见以前的文档,我们这里着重分析Spring 
Web 
MVC框架的实现.我们从分析DispatcherServlet入手:<BR>//这里是对DispatcherServlet的初始化方法,根据名字我们很方面的看到对各个Spring 
MVC主要元素的初始化<BR>protected void initFrameworkServlet() throws ServletException, 
BeansException 
{<BR>initMultipartResolver();<BR>initLocaleResolver();<BR>initThemeResolver();<BR>initHandlerMappings();<BR>initHandlerAdapters();<BR>initHandlerExceptionResolvers();<BR>initRequestToViewNameTranslator();<BR>initViewResolvers();<BR>}<BR>看 
到注解我们知道,这是DispatcherSerlvet的初始化过程,它是在WebApplicationContext已经存在的情况下进行的,也就 
意味着在初始化它的时候,IOC容器应该已经工作了,这也是我们在web.xml中配置Spring的时候,需要把DispatcherServlet的 
load-on-startup的属性配置为2的原因。<BR>对于具体的初始化过程,很容易理解,我们拿initHandlerMappings()来看看:<BR>private 
void initHandlerMappings() throws BeansException {<BR>if 
(this.detectAllHandlerMappings) {<BR>// 
这里找到所有在上下文中定义的HandlerMapping,同时把他们排序<BR>// 
因为在同一个上下文中可以有不止一个handlerMapping,所以我们把他们都载入到一个链里进行维护和管理<BR><SPAN 
style="BACKGROUND-COLOR: rgb(255,255,102)">Map matchingBeans = 
BeanFactoryUtils.beansOfTypeIncludingAncestors(</SPAN><BR 
style="BACKGROUND-COLOR: rgb(255,255,102)"><SPAN 
style="BACKGROUND-COLOR: rgb(255,255,102)">getWebApplicationContext(), 
HandlerMapping.class, true, false);</SPAN><BR 
style="BACKGROUND-COLOR: rgb(255,255,102)">if (!matchingBeans.isEmpty()) 
{<BR><SPAN style="BACKGROUND-COLOR: rgb(255,255,102)">this.handlerMappings = new 
ArrayList(matchingBeans.values());</SPAN><BR 
style="BACKGROUND-COLOR: rgb(255,255,102)"><SPAN 
style="BACKGROUND-COLOR: rgb(255,255,102)">// 
这里通过order属性来对handlerMapping来在list中排序</SPAN><BR 
style="BACKGROUND-COLOR: rgb(255,255,102)"><SPAN 
style="BACKGROUND-COLOR: rgb(255,255,102)">Collections.sort(this.handlerMappings, 
new OrderComparator());</SPAN><BR 
style="BACKGROUND-COLOR: rgb(255,255,102)">}<BR>}<BR>else { <BR>try {<BR>Object 
hm = getWebApplicationContext().getBean(HANDLER_MAPPING_BEAN_NAME, 
HandlerMapping.class);<BR>this.handlerMappings = 
Collections.singletonList(hm);<BR>}<BR>catch (NoSuchBeanDefinitionException ex) 
{<BR>// Ignore, we'll add a default HandlerMapping 
later.<BR>}<BR>}<BR><BR>//如果在上下文中没有定义的话,那么我们使用默认的BeanNameUrlHandlerMapping<BR>if 
(this.handlerMappings == null) {<BR><SPAN 
style="BACKGROUND-COLOR: rgb(255,255,102)">this.handlerMappings = 
getDefaultStrategies(HandlerMapping.class);</SPAN><BR 
style="BACKGROUND-COLOR: rgb(255,255,102)"><SPAN 
style="BACKGROUND-COLOR: rgb(255,255,255)"></SPAN>........<BR>}<BR>}<BR>怎样获得上下文环境,可以参见我们前面的对IOC容器在web环境中加载的分析。 
DispatcherServlet把定义了的所有HandlerMapping都加载了放在一个List里待以后进行使用,这个链的每一个元素都是一个handlerMapping的配置,而一般每一个handlerMapping可以持有一系列从URL请求到 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -