`
jiwenke
  • 浏览: 400689 次
  • 性别: Icon_minigender_1
  • 来自: 南京
博客专栏
4ee69929-b8e1-3eb5-bbca-157d075d6192
Spring技术内幕——深...
浏览量:182738
D1c226f7-74e9-3ec4-a15b-18a45ccd88c5
随笔:Spring与云计算...
浏览量:26300
社区版块
存档分类
最新评论

Spring源代码分析的PDF版本发布

阅读更多
方便大家阅读,请多留言,多指正!
分享到:
评论
30 楼 jiwenke 2008-12-05  
引用
比如,目标对象的构造函数的参数也是一个没有默认构造函数的类时,我们为了将这个类实例化,还需要进一步对这个参数类进行反射,取出其构造方法的参数类型(是什么类),如果不幸,这个类也没有默认构造函数,我们可能还需要进一步反射它的构造函方法的参数类型,...直到我们找到一个存在默认构造函数的类或只是一个接口时,实例化它(接口的话,我们需要借助于CGLIB实例化,非接口应该无所谓),然后一步一步再往前逐一实例化之前没法实例化的类,最终才能够完成对目标对象参数的实例化。
但是,如果在实例化各个参数的参数的过程中,最终一个参数既没有实现接口,也没有默认构造函数时,就完蛋了,因为最后的这个参数,我们没法实例化他,这样,之前的一系统参数,我们也无法实例化,最终,对于目标对象的参数,我们没法给他构造出实实在在的对象,于时,目标对象类的子类对象,我们是无法生成的。整个代理过程失败。

我想如果只有一层代理的话,没有这个逐层的过程啊。你说的参数对象实例话是应该由依赖注入来完成的,他不见得是用CGLIB来实现,如果是正常的依赖注入的话,可以使用类装载器直接实例话就可以了。当然如果参数也是CGLIB的代理类的话,另当别论。

29 楼 netfork 2008-12-04  
jiwenke 写道

引用

还是你老兄研究得透,不过我个人觉得如果硬性规定一个构造方法的话,那么和就给框架带来了侵入性,不符合SPRING POJO的出发点了。


您说的对,这确实又带入了侵入性,这样办违背了初衷。
我就这一小点问题,硬着头皮调试了好几天,关键是我就用的是没有带接口的Service,当时用的是Set注入,结果看了本书Spring in Action的第二章时说到构造函数注入,于是乎我就想改改试试,不小心出差子了,本来想放弃了,后来还是不舍气,最后可算大体弄清楚了。
LZ的Spring源代码分析,那才是够深刻够透彻,我要继续理解你的源码分析,争取全面了解一下Spring的实现方法。
jiwenke 写道

引用
如果这一切都不明确,就需要动态判断注入的类,这样可能需要反复动态生成对象,甚至可能最终因为其中有关的一个类没有默认构造函数而失败。

这句话我没想明白,让我好好想想.....


这句是我的猜想,或许是错误的,以下是我假想的情况,不知道理解的有没有错误。
比如,目标对象的构造函数的参数也是一个没有默认构造函数的类时,我们为了将这个类实例化,还需要进一步对这个参数类进行反射,取出其构造方法的参数类型(是什么类),如果不幸,这个类也没有默认构造函数,我们可能还需要进一步反射它的构造函方法的参数类型,...直到我们找到一个存在默认构造函数的类或只是一个接口时,实例化它(接口的话,我们需要借助于CGLIB实例化,非接口应该无所谓),然后一步一步再往前逐一实例化之前没法实例化的类,最终才能够完成对目标对象参数的实例化。
但是,如果在实例化各个参数的参数的过程中,最终一个参数既没有实现接口,也没有默认构造函数时,就完蛋了,因为最后的这个参数,我们没法实例化他,这样,之前的一系统参数,我们也无法实例化,最终,对于目标对象的参数,我们没法给他构造出实实在在的对象,于时,目标对象类的子类对象,我们是无法生成的。整个代理过程失败。

28 楼 jiwenke 2008-12-04  
引用

我的理解,default constructor应该就是指不带arg的那个。好象java书上有讲吧。

我看了一下Spring中通过cglib实现代理的过程,其实对于动态生成的子类对象除了代理和帮忙切入之外,对于具体调用,都是在Cglib2AopProxy中回调的“真身”即目标对象的方法。
因此,对于动态子类来讲,无所谓什么构造函数,随便弄个构造函数,只要能帮忙把这个子类对象生成出来就行了。
其实,我们完全可以硬性规定,每个需要代理的类,里面加一个如下面这样的构造方法:
public Xxx(Object obj) {
}
然后,在DefaultAopProxyFactory中,new一个Object作为参数数组的一个元素,这样也可以造出这个动态子类的对象,也应该完成可以满足Cglib动态代理的实现的。当然这个是我从理论上分析的,没有试验,不出意外,完全没问题。如果Object不行,可以搞个String也可以。

另外,我的解决方案,只适合于具体的场景,我给出的案例中,我是明确注入Service的类是什么样子的,而且这个类还实现了接口,不会因为没有默认构造函数而无法生成子类对象;如果这一切都不明确,就需要动态判断注入的类,这样可能需要反复动态生成对象,甚至可能最终因为其中有关的一个类没有默认构造函数而失败。
所以,这样来讲,Spring要想完美的解决这个问题,必须动大手术,将构造函数的参数进一步向aop处理部分传递,直到传到DefaultAopProxyFactory中才行。



还是你老兄研究得透,不过我个人觉得如果硬性规定一个构造方法的话,那么和就给框架带来了侵入性,不符合SPRING POJO的出发点了。
引用
如果这一切都不明确,就需要动态判断注入的类,这样可能需要反复动态生成对象,甚至可能最终因为其中有关的一个类没有默认构造函数而失败。

这句话我没想明白,让我好好想想.....
27 楼 zds625 2008-12-04  
感谢,对于spring的源码学习是一个很好的启示~!
26 楼 kivensun 2008-12-04  
谢谢LZ。
25 楼 wojiaojiangnan 2008-12-04  
现在公司使用sping正好拿来看看
谢谢lz
24 楼 M4A3E8 2008-12-04  
非常感谢~~~
23 楼 netfork 2008-12-04  
jiwenke 写道
引用
“which requires class to expose default constructor”,这句似乎专指的是需要暴露默认的构造方法。倒不是不允许使用构造器注入来建立Spring bean AOP。不知道我对老外话的理解对不对。

which requires class to expose default constructor - 默认的构造器是不是就是指不带arg的那个啊?如果要构造器注入的话应该就有arg.
我不知道spring是怎么考虑的,但我觉得要解决不难啊 ,直接用你的那个解决方案 
但不知道是不是cglib有限制,这个我没有研究过。

我的理解,default constructor应该就是指不带arg的那个。好象java书上有讲吧。

我看了一下Spring中通过cglib实现代理的过程,其实对于动态生成的子类对象除了代理和帮忙切入之外,对于具体调用,都是在Cglib2AopProxy中回调的“真身”即目标对象的方法。
因此,对于动态子类来讲,无所谓什么构造函数,随便弄个构造函数,只要能帮忙把这个子类对象生成出来就行了。
其实,我们完全可以硬性规定,每个需要代理的类,里面加一个如下面这样的构造方法:
public Xxx(Object obj) {
}
然后,在DefaultAopProxyFactory中,new一个Object作为参数数组的一个元素,这样也可以造出这个动态子类的对象,也应该完成可以满足Cglib动态代理的实现的。当然这个是我从理论上分析的,没有试验,不出意外,完全没问题。如果Object不行,可以搞个String也可以。

另外,我的解决方案,只适合于具体的场景,我给出的案例中,我是明确注入Service的类是什么样子的,而且这个类还实现了接口,不会因为没有默认构造函数而无法生成子类对象;如果这一切都不明确,就需要动态判断注入的类,这样可能需要反复动态生成对象,甚至可能最终因为其中有关的一个类没有默认构造函数而失败。
所以,这样来讲,Spring要想完美的解决这个问题,必须动大手术,将构造函数的参数进一步向aop处理部分传递,直到传到DefaultAopProxyFactory中才行。


22 楼 jiwenke 2008-12-04  
引用
“which requires class to expose default constructor”,这句似乎专指的是需要暴露默认的构造方法。倒不是不允许使用构造器注入来建立Spring bean AOP。不知道我对老外话的理解对不对。

which requires class to expose default constructor - 默认的构造器是不是就是指不带arg的那个啊?如果要构造器注入的话应该就有arg.
我不知道spring是怎么考虑的,但我觉得要解决不难啊 ,直接用你的那个解决方案 
但不知道是不是cglib有限制,这个我没有研究过。
21 楼 netfork 2008-12-04  
引用
Oleg的意思是说if you have a Spring bean that defines constructor injection it will not work and I think this is the problem you are having - 不允许使用构造器注入来建立Spring bean AOP.


老外的原文
引用
No it does not:
    The proxies are created by dynamically sub-classing the actual class, which requires class to expose default constructor. If you don't you'll get IllegalArgumentException "Superclass has no null constructors but no arguments were given.", which means if you have a Spring bean that defines constructor injection it will not work and I think this is the problem you are having.


“which requires class to expose default constructor”,这句似乎专指的是需要暴露默认的构造方法。倒不是不允许使用构造器注入来建立Spring bean AOP。不知道我对老外话的理解对不对。
20 楼 netfork 2008-12-04  
感谢楼主不遗余力的调查这个问题。
虽然我不知道Oleg是谁,但是似乎老外也有这样的结论。

考虑应该是Spring自己功能上的限制吧。
Debug源码后,感觉目前Spring框架本身想解决这个限制,难度还是比较大。
19 楼 jiwenke 2008-12-04  
发了邮件问了一下, 下面是Spring Source oleg zhurakousky的回复:
No it does not:
    The proxies are created by dynamically sub-classing the actual class, which requires class to expose default constructor. If you don't you'll get IllegalArgumentException "Superclass has no null constructors but no arguments were given.", which means if you have a Spring bean that defines constructor injection it will not work and I think this is the problem you are having.

我的邮件原文是:
Hi,
In the usage of the AOP , we found that with the proxy class usign CGLIB with contructor arg - a exception throw with "org.springframework.aop.framework.AopConfigException". Checking the source code and the testcases(Version 2.5.6) and found that Spring actually doesn't support it. Is that means Spring not encourage this use cases or it is a missing functionality? - it sounds tricky, can any one help to clarify it ? Thanks your time so much!

Tracing code in the Cglib2AopProxy line197:
            if (this.constructorArgs != null) {
                proxy = enhancer.create(this.constructorArgTypes, this.constructorArgs);
            }
            else {
                proxy = enhancer.create();
            }

it is the exception occurred.
And by trace the use of the Cglib2AopProxy.setConstructorArguments - It is only called in the testcases instead of production code. Does it means when use don't permit to AOP those class with arg constructor directly?

public void testWithNoArgConstructor() { 

NoArgCtorTestBean target = new NoArgCtorTestBean("b", 1);  
target.reset();  
   
mockTargetSource.setTarget(target);  
AdvisedSupport pc = new AdvisedSupport(new Class[]{});  
pc.setTargetSource(mockTargetSource);  
Cglib2AopProxy aop = new Cglib2AopProxy(pc);  
aop.setConstructorArguments(new Object[] {"Rob Harrop", new Integer(22)}, new Class[] {String.class, int.class});  
NoArgCtorTestBean proxy = (NoArgCtorTestBean) aop.getProxy();  
proxy = (NoArgCtorTestBean) aop.getProxy();  
assertNotNull("Proxy should be null", proxy);  
}  

Oleg的意思是说if you have a Spring bean that defines constructor injection it will not work and I think this is the problem you are having - 不允许使用构造器注入来建立Spring bean AOP.但我觉得奇怪,不知道这是cglib的限制还是spring自己功能上的限制 - 看到了楼上的解决方案啊,为什么spring不提供?
18 楼 hanjs 2008-12-04  
不错,学习了,下来看看
17 楼 jbeduhai 2008-12-04  
好东西啊,谢了
16 楼 ftj20003 2008-12-03  
多谢了,lz真是好心人啊!
15 楼 netfork 2008-12-03  
jiwenke 写道
我看了一下代码,在Spring2.5.6,似乎如果要支持带参数的构造函数生成proxy,要手动的去调用setConstructorArguments();可以参考测试用例:
	public void testWithNoArgConstructor() {
		NoArgCtorTestBean target = new NoArgCtorTestBean("b", 1);
		target.reset();

		mockTargetSource.setTarget(target);
		AdvisedSupport pc = new AdvisedSupport(new Class[]{});
		pc.setTargetSource(mockTargetSource);
		Cglib2AopProxy aop = new Cglib2AopProxy(pc);
	        aop.setConstructorArguments(new Object[] {"Rob Harrop", new Integer(22)},
				new Class[] {String.class, int.class});
		NoArgCtorTestBean proxy = (NoArgCtorTestBean) aop.getProxy();
		proxy = (NoArgCtorTestBean) aop.getProxy();

		assertNotNull("Proxy should be null", proxy);
	}

如果是不带参数的构造函数的proxy,spring提供的用例是这样的:
	public void testProxyAProxy() {
		ITestBean target = new TestBean();

		mockTargetSource.setTarget(target);
		AdvisedSupport as = new AdvisedSupport(new Class[]{});
		as.setTargetSource(mockTargetSource);
		as.addAdvice(new NopInterceptor());
		Cglib2AopProxy cglib = new Cglib2AopProxy(as);

		ITestBean proxy1 = (ITestBean) cglib.getProxy();

		mockTargetSource.setTarget(proxy1);
		as = new AdvisedSupport(new Class[]{});
		as.setTargetSource(mockTargetSource);
		as.addAdvice(new NopInterceptor());
		cglib = new Cglib2AopProxy(as);

		ITestBean proxy2 = (ITestBean) cglib.getProxy();
	}

不知道我的理解对不对?或者不需要重新build spring,只是要手动的调用一下。从代码上看,Spring的实现方式默认是为不带参数的构造函数生成Proxy,也许是Spring觉得这种使用方式不好,因而支持不够?可能大多数使用方式是不带参数的构造函数,如果要注入的话通过set函数来完成吧。

感谢回答,感谢您帮忙做的调查。

这个结论跟我之前Debug的结论是一致的,也就是对于没有实现接口的类,又没有默认构造函数时,目前的Spring是无法实现AOP拦截的!

不过,我已经找到了解决方案,并且也基本上清楚了CGLIB的AOP的是如何实现的。
稍后,我打算写一篇总结性的文章阐述一下。
写完了,在这:
http://www.iteye.com/topic/286215
14 楼 jiwenke 2008-12-03  
我看了一下代码,在Spring2.5.6,似乎如果要支持带参数的构造函数生成proxy,要手动的去调用setConstructorArguments();可以参考测试用例:
	public void testWithNoArgConstructor() {
		NoArgCtorTestBean target = new NoArgCtorTestBean("b", 1);
		target.reset();

		mockTargetSource.setTarget(target);
		AdvisedSupport pc = new AdvisedSupport(new Class[]{});
		pc.setTargetSource(mockTargetSource);
		Cglib2AopProxy aop = new Cglib2AopProxy(pc);
	        aop.setConstructorArguments(new Object[] {"Rob Harrop", new Integer(22)},
				new Class[] {String.class, int.class});
		NoArgCtorTestBean proxy = (NoArgCtorTestBean) aop.getProxy();
		proxy = (NoArgCtorTestBean) aop.getProxy();

		assertNotNull("Proxy should be null", proxy);
	}

如果是不带参数的构造函数的proxy,spring提供的用例是这样的:
	public void testProxyAProxy() {
		ITestBean target = new TestBean();

		mockTargetSource.setTarget(target);
		AdvisedSupport as = new AdvisedSupport(new Class[]{});
		as.setTargetSource(mockTargetSource);
		as.addAdvice(new NopInterceptor());
		Cglib2AopProxy cglib = new Cglib2AopProxy(as);

		ITestBean proxy1 = (ITestBean) cglib.getProxy();

		mockTargetSource.setTarget(proxy1);
		as = new AdvisedSupport(new Class[]{});
		as.setTargetSource(mockTargetSource);
		as.addAdvice(new NopInterceptor());
		cglib = new Cglib2AopProxy(as);

		ITestBean proxy2 = (ITestBean) cglib.getProxy();
	}

不知道我的理解对不对?或者不需要重新build spring,只是要手动的调用一下。从代码上看,Spring的实现方式默认是为不带参数的构造函数生成Proxy,也许是Spring觉得这种使用方式不好,因而支持不够?可能大多数使用方式是不带参数的构造函数,如果要注入的话通过set函数来完成吧。
13 楼 netfork 2008-12-02  
感谢LZ的及时回复!

为了研究这个问题,我刚换了最新的spring:spring-framework-2.5.6-with-dependencies.zip
之前用的是2.5.5好象,因为用eclipse进行debug时,对不上源代码,所以干脆把环境中的spring.jar全换作了2.5.6。
另:cglib-2.2.jar

我倒是没有整个checkout,build。只是下了最新的包和源码。
就是改,肯定也是在开发环境中建立spring的包,然后把想改的类拷进行改。
我这水平也不想全部搞明白,只想就所我自己碰到的具体问题搞清楚。弄不清楚这事,我老是很不爽。
12 楼 jiwenke 2008-12-02  
你太谦虚了
请问你用的spring是多少版本的。我以前看的版本比较低,想整个checkout出来看看你这个问题 - 不一定能搞定啊
另外,如果你要改spring代码,可以把版本checkout出来后,自己build一个。看看改动是不是有效。
11 楼 netfork 2008-12-02  
jiwenke 写道
方便大家阅读,请多留言,多指正!


jiwenke楼主大侠,请帮我分析一下下面的问题吧。
我想以我目前这点功力,确实难以搞明白这个事,请帮帮忙吧。

请点击下面的链接:
http://www.iteye.com/topic/285113

相关推荐

    Spring源码分析.pdf

    Spring 源码分析 Spring 框架是 Java 语言中最流行的开源框架之一,它提供了一个强大且灵活的基础设施来构建企业级应用程序。在 Spring 框架中,IOC 容器扮演着核心角色,本文将深入分析 Spring 源码,了解 IOC ...

    Spring核心源码解析.pdf

    本篇文档将对Spring框架的核心源码进行解析,以帮助开发者更深入地理解Spring的工作原理和核心概念。 首先,Spring框架通过使用IoC容器来管理应用对象的创建和依赖关系。这种做法可以让程序员从创建对象的复杂性中...

    Spring源码解析.pdf

    ### Spring源码解析知识点 #### 一、Spring IoC 容器详解 ##### 1. BeanFactory —— 最基础的IoC容器 - **概念**:`BeanFactory` 是Spring框架中最基本的IoC容器,它负责管理Bean的生命周期,包括创建、配置和...

    Spring源码深度解析第二版

    Spring源码深度解析第二版 Spring是一款广泛应用于Java企业级应用程序的开源框架,旨在简化Java应用程序的开发和部署。Spring框架的核心主要包括了IoC容器、AOP、MVC框架等模块。 第1章 Spring整体架构和环境搭建 ...

    Spring5 源码分析(第 2 版)-某Tom老师

    《Spring5 源码分析(第 2 版)》是某Tom老师精心编写的深度解析文档,旨在帮助读者全面理解Spring5的核心机制和设计理念。Spring作为Java领域最为广泛应用的框架之一,其源码的深入理解对于开发者来说至关重要。这篇...

    Spring源码解析.zip

    本压缩包“Spring源码解析”提供了对Spring框架核心组件——IOC(Inversion of Control,控制反转)、AOP(Aspect Oriented Programming,面向切面编程)以及Transaction(事务管理)的源码分析,帮助开发者更全面地...

    Spring5 源码分析(第 2 版) .zip

    《Spring5 源码分析(第 2 版)》是针对Spring框架第五个主要版本的深度解析著作,由知名讲师倾心打造,旨在帮助读者深入理解Spring框架的内部工作机制,提升对Java企业级应用开发的专业技能。本书涵盖了Spring框架的...

    spring源代码解析十.pdf

    这篇源代码解析主要关注Spring Acegi中AuthenticationProcessingFilter的实现,它是Web页面验证的核心部分。AuthenticationProcessingFilter是Servlet Filter接口的实现,主要用于在请求到达目标资源之前进行身份...

    Spring MVC源码深度剖析开源架构源码2021.pdf

    本知识点将围绕Spring MVC的源码深度剖析展开,详细介绍Spring MVC的源码结构、工作原理以及如何进行源码分析。 首先,要理解Spring MVC是如何启动和配置的。在web.xml文件中配置了DispatcherServlet,这是Spring ...

    深入剖析Spring Web源码 pdf高清版(第二版)

    《深入剖析Spring Web源码》(第二版) 是一本针对Java开发者深度解析Spring Web框架核心原理的权威指南。这本书详细解读了Spring MVC和Spring WebFlux两大核心模块的源码,帮助读者理解Spring如何实现高效的Web应用...

    springmvc深入解析.pdf

    Spring MVC深入解析 Spring MVC是一个基于模型-视图-控制器(MVC)模式的Web应用程序框架,是Spring Framework的一部分。它提供了一个灵活的方式来构建Web应用程序,使得开发者可以轻松地创建复杂的Web应用程序。 ...

    springbatch 详解PDF附加 全书源码 压缩包

    通过阅读《Spring.Batch批处理框架.pdf》和源码,你将能够掌握 Spring Batch 的核心概念和实践技巧,为你的企业级应用开发带来高效、可靠的批量处理能力。同时,源码可以直接运行,提供了动手实践的机会,加深理解和...

    Spring源码总结.pdf

    在Spring源码中,容器的加载方式、XML属性配置的解析过程以及自定义标签的处理是核心知识点。 1. **Spring容器加载方式**: - **ClassPathXmlApplicationContext**: 通过类路径加载XML配置文件,适用于传统的Java...

    spring security 3.1 PDF 英文版,源代码.7z

    标题中的“spring security 3.1 PDF 英文版,源代码.7z”指的是一个关于Spring Security 3.1的PDF文档,包含了该框架的详细文档,并且附带了源代码。这为开发者提供了一个深入学习和理解Spring Security 3.1的机会,...

    spring揭秘 附带spring源码获取方式

    最近在看spring源码 搜集了这一本大家都推荐的《spring揭秘》PDF 非常不错,同时附带spring源码下载地址 以及编译方式,照着做就可以,本人已经测试; ps spring 涉及动态代理、反射、设计模式之类的先弄懂再看,...

    Spring5.pdf

    Spring 是一个开源的轻量级Java应用框架,其最初由Rod Johnson创建,并在2003年首次发布。...官方的下载地址和GitHub地址也提供了从源代码到二进制构建的入口,便于开发者获取最新版本的Spring框架。

    Spring IoC源码深度剖析开源架构源码2021.pdf

    标题《Spring IoC源码深度剖析开源架构源码2021.pdf》和描述《Spring IoC源码深度剖析开源架构源码2021.pdf》表明该文档主要面向于分析Spring框架中控制反转(IoC)容器的核心源码,解析和理解其内部的工作机制及...

    spring源码

    Spring框架是Java开发中的核心组件,它为应用程序提供了一个全面的基础设施,支持...通过分析源码,开发者还可以了解到如何设计和实现一个可扩展、可维护的框架,这对于提升自身的技术水平和解决问题的能力大有裨益。

Global site tag (gtag.js) - Google Analytics