论坛首页 Java企业应用论坛

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

浏览 17081 次
精华帖 (18) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间: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。不知道我对老外话的理解对不对。
0 请登录后投票
   发表时间:2008-12-04   最后修改:2008-12-04
引用
“which requires class to expose default constructor”,这句似乎专指的是需要暴露默认的构造方法。倒不是不允许使用构造器注入来建立Spring bean AOP。不知道我对老外话的理解对不对。

which requires class to expose default constructor - 默认的构造器是不是就是指不带arg的那个啊?如果要构造器注入的话应该就有arg.
我不知道spring是怎么考虑的,但我觉得要解决不难啊 ,直接用你的那个解决方案 
但不知道是不是cglib有限制,这个我没有研究过。
0 请登录后投票
   发表时间:2008-12-04   最后修改: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中才行。


0 请登录后投票
   发表时间: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的出发点了。
引用
如果这一切都不明确,就需要动态判断注入的类,这样可能需要反复动态生成对象,甚至可能最终因为其中有关的一个类没有默认构造函数而失败。

这句话我没想明白,让我好好想想.....
0 请登录后投票
   发表时间:2008-12-04   最后修改:2008-12-04
jiwenke 写道

引用

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


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

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

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


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

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

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

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


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



~~~~
由于我对自己的java水平也没多少信心,所以不知道我所理解的不可行的地方到底对不对。
楼主看着帮忙分析一下吧。

目的:实例化子类,也就是生成子类的对象。
拥有资源:只有目标对象,当然这个目标对象是一个没有默认构造方法的类的对象。
具体的步骤:
1、利用目标对象,借助于CGLIB生成其子类。
  目前来讲,CGLIB应该只是照葫芦画瓢,并没有再给这个子类添加一个默认构造方法,仅仅是覆盖了一下目标对象类的构造函数。其实,我个人认为,CGLIB增加一个可以自动强制为子类添加默认构造方法应该不算难事,但是目前来讲,我想CGLIB肯定没有提供这种生成子类的方法,否则Spring的这个aop失败的情况就不会有了。
2、实例化生成的子类。
  由于子类的构造方法也是带参数的,如果想用实例化他的话,必须要提供参数对象,但是,此时参数对象并不能拿到啊。因为唯一的资源“目标对象”的构造方法的参数是包在其对象里的,并没有提供get方法,我们拿不到的(这点,其实也是构造函数注入的初衷,就是被注入的东西不可变),于是,我想我们还必须想法搞到子类构造方法的参数的对象,这样,就有了我上面的关于反复反射直到能找到能生产对象的那一刻,才能回过头来,把所有的对象给实例化出来。
  没有默认构造方法的类,要想实现实例化,我个人的知识范围是需要提供构造函数参数对象的。如果有其他技巧可以在没有参数对象的情况实例化出没有默认构造函数的类的对象,我想,确实就没必须反复反射,去找那个根对象了。

  跟楼主讨论问题,引发了我很多的思考,真的很爽,也加深了认识。谢谢!
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics