为什么自调用不适用于Spring代理(例如使用AOP)?

为什么自调用不适用于Spring代理(例如使用AOP)?,spring,proxy,spring-aop,Spring,Proxy,Spring Aop,请解释一下,为什么代理上的自调用在目标上执行,而不是在代理上执行?如果这是故意的,那为什么呢?如果代理是通过子类化创建的,则可以在每次方法调用之前执行一些代码,甚至在自调用时也是如此。我试过了,我有自我调用的代理 公共类DummyPrinter{ 公共空白打印1(){ 系统输出打印项次(“打印1”); } 公共空白打印2(){ 系统输出打印项次(“打印2”); } 公共空间{ print1(); print2(); } } 公共类PrinterProxy扩展DummyPrinter{ @凌驾

请解释一下,为什么代理上的自调用在目标上执行,而不是在代理上执行?如果这是故意的,那为什么呢?如果代理是通过子类化创建的,则可以在每次方法调用之前执行一些代码,甚至在自调用时也是如此。我试过了,我有自我调用的代理

公共类DummyPrinter{
公共空白打印1(){
系统输出打印项次(“打印1”);
}
公共空白打印2(){
系统输出打印项次(“打印2”);
}
公共空间{
print1();
print2();
}
}
公共类PrinterProxy扩展DummyPrinter{
@凌驾
公共空白打印1(){
System.out.println(“打印前1”);
super.print1();
}
@凌驾
公共空白打印2(){
System.out.println(“打印前2”);
super.print2();
}
@凌驾
公共空间{
System.out.println(“打印两者之前”);
super.printweath();
}
}
公共类主{
公共静态void main(字符串[]args){
DummyPrinter p=新的PrinterProxy();
p、 打印两个();
}
}
输出:

在打印之前
打印前1
打印1
打印前2
打印2
这里,每个方法都在代理上调用。为什么在文档中提到在自调用的情况下应该使用AspectJ?

请阅读Spring手册,然后您就会理解。这里甚至使用了“自我调用”一词。如果您仍然不理解,请随时提出后续问题,只要这些问题与上下文相关


更新:好的,在我们确定您真正阅读了那一章之后,在重新阅读您的问题并分析了您的代码之后,我发现这个问题实际上非常深刻(我甚至投了更高的票),值得更详细地回答

你关于它如何工作的(错误)假设 您的误解是关于动态代理如何工作,因为它们不像示例代码中那样工作。让我将对象ID(哈希代码)添加到日志输出中,以便在您自己的代码中进行说明:

package de.scrum\u master.app;
公共类Dummy打印机{
公共空白打印1(){
System.out.println(此+打印1);
}
公共空白打印2(){
System.out.println(此+打印2);
}
公共空间{
print1();
print2();
}
}
package de.scrum\u master.app;
公共类PseudoPrinterProxy扩展DummyPrinter{
@凌驾
公共空白打印1(){
System.out.println(在print1之前的这个+);
super.print1();
}
@凌驾
公共空白打印2(){
System.out.println(此+“在print2之前”);
super.print2();
}
@凌驾
公共空间{
System.out.println(此+“在打印两者之前”);
super.printweath();
}
公共静态void main(字符串[]args){
新的伪PrinterProxy().printBoth();
}
}
控制台日志:

de.scrum\u master.app。PseudoPrinterProxy@59f95c5d在打印之前
de.scrum_master.app。PseudoPrinterProxy@59f95c5d打印前1
de.scrum_master.app。PseudoPrinterProxy@59f95c5d打印1
de.scrum_master.app。PseudoPrinterProxy@59f95c5d打印前2
de.scrum_master.app。PseudoPrinterProxy@59f95c5d打印2
看到了吗?总是有相同的对象ID,这并不奇怪。“代理”(它不是真正的代理,而是静态编译的子类)的自调用由于多态性而起作用。这由Java编译器负责

它是如何工作的 现在请记住,我们在这里讨论的是动态代理,即在运行时创建的子类和对象:

  • JDK代理用于实现接口的类,这意味着实现这些接口的类是在运行时创建的。在这种情况下,无论如何都没有超类,这也解释了为什么它只适用于公共方法:接口只有公共方法
  • CGLIB代理也适用于未实现任何接口的类,因此也适用于受保护和包作用域的方法(但不是私有方法,因为您无法覆盖这些方法,因此称为私有方法)
  • 然而,关键的一点是,在上述两种情况下,当代理被创建时,原始对象已经(并且仍然)存在,,因此不存在多态性。这种情况是,我们有一个动态创建的代理对象委托给原始对象,即我们有两个对象:一个代理和一个委托
我想这样来说明:

package de.scrum\u master.app;
公共类DelegatingPrinterProxy扩展DummyPrinter{
达米打印机代表;
公共授权PrinterProxy(DummyPrinter授权){
this.delegate=委托;
}
@凌驾
公共空白打印1(){
System.out.println(在print1之前的这个+);
delegate.print1();
}
@凌驾
公共空白打印2(){
System.out.println(此+“在print2之前”);
delegate.print2();
}
@凌驾
公共空间{
System.out.println(此+“在打印两者之前”);
delegate.printweath();
}
公共静态void main(字符串[]args){
新的DelegatingPrinterProxy(新的DummyPrinter()).PrintAll();
}
}
看到区别了吗?因此,控制台日志更改为:

de.scrum\u master.app。DelegatingPrinterProxy@59f95c5d在打印之前
de.scrum_master.app。DummyPrinter@5c8da962打印1
de.scrum_master.app。DummyPrinter@5c8da962打印2
这是SpringAOP或Spring的其他部分使用动态代理的行为,甚至是使用JDK或CGLIB代理的非Spring应用程序

这是一个特性还是一个限制?作为AspectJ(不是SpringAOP)用户,我认为这是一个限制。也许其他人会认为这是一个特性,因为根据Spring中代理使用的实现方式,您可以在