Java Spring作用域代理为作用域代理bean字段的字段而不是bean本身工作?

Java Spring作用域代理为作用域代理bean字段的字段而不是bean本身工作?,java,spring,proxy,Java,Spring,Proxy,这是我的代码: Spring配置: package biz.tugay; /* User: koray@tugay.biz Date: 25/12/15 Time: 19:30 */ import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan(base

这是我的代码:

Spring配置:

package biz.tugay;
/* User: koray@tugay.biz Date: 25/12/15 Time: 19:30 */

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = "biz.tugay")
public class SpringConfiguration {
}
傅:

FooImpl:

package biz.tugay;
/* User: koray@tugay.biz Date: 25/12/15 Time: 19:31 */

import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;

import java.util.UUID;

@Component
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class FooImpl implements Foo {
    private final String state = UUID.randomUUID().toString();
    public String getState() {
        return state;
    }
}
酒吧:

巴林普:

package biz.tugay;
/* User: koray@tugay.biz Date: 25/12/15 Time: 19:33 */

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope(value = "singleton")
public class BarImpl implements Bar {

    private Foo foo;

    @Autowired
    public void setFoo(Foo foo) {
        this.foo = foo;
    }

    public Foo getFoo() {
        return foo;
    }
}
和测试类:

package biz.tugay;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import static java.lang.System.out;

public class TestClass {

    final static Class<SpringConfiguration> SPRING_CONFIGURATION_CLASS = SpringConfiguration.class;

    public static void main(String[] args) {

        final ApplicationContext applicationContext;
        applicationContext = new AnnotationConfigApplicationContext(SPRING_CONFIGURATION_CLASS);

        final Bar barOne = applicationContext.getBean(BarImpl.class);
        final Bar barTwo = applicationContext.getBean(BarImpl.class);

        out.println("barOne == barTwo: " + (barOne == barTwo));
        out.println("barOne.getFoo == barTwo.getFoo: " + (barOne.getFoo() == barTwo.getFoo()));

        out.println(barOne.getFoo().getState());
        out.println(barTwo.getFoo().getState());

    }
}
我的问题是,

据我所知,064bdb74-cad7-4d13-86fe-a4fc0021e5a0不等于c6f2d9be-09b4-456d-9414-8ECE2F2F2AC9E,因为FooImpl实际上是作用域氧

我不明白的是,为什么barOne.getFoo可以等于barTwo.getFoo

这怎么可能:

barOne.getFoo() == barTwo.getFoo()
barOne.getFoo().getState() != barTwo().getFoo().getState()
??

突出显示代码:

  • 代码在Singleton中使用原型范围的bean
  • 然后使用bean代理模式ScopedProxyMode.TARGET_类
结果是意料之中的。为什么?

  • 由于UUID是最终类,请参见 . 因此,尝试获取代理是不可能的,每次都会获得一个新对象

要首先解除对输出的理解,您需要了解Spring框架的工作方式和内容。让我们从这样一个想法开始:当您将“短期”范围bean注入“长期”范围bean(在您的例子中,将原型bean注入singleton bean)时,Spring将注入一个AOP代理来代替范围bean

也就是说,您需要注入一个代理对象,该代理对象公开与作用域对象相同的公共接口,但也可以从相关作用域(如HTTP请求)检索真实目标对象,并将方法调用委托给真实对象

基本上有两种主要类型的代理:JDK代理和CGLIB代理(默认)

因此,让我们回到示例代码,并尝试了解发生了什么。。。 当应用程序启动时,Spring框架会创建两个bean,即
Foo
Bar
,但这两个bean不仅仅是一个简单的实现(FooImpl和BarImpl),而是代理(CglibAopProxy)。
因此,在您的
TestClass
类中,您有两个对
BarImpl
barOne和barTwo的相同AopProxy的引用。由于
条形图
的作用域为单例,因此AopProxy的底层目标类与预先优化的对象(BarImpl)相同。这个
Bar
AopProxy有一个类型为
Foo
的注入AopPorxy,因此当您执行以下代码
barOne.getFoo()==barTwo.getFoo()
时,它的计算结果为true,因为
barOne
barTwo
都有相同的AopProxy实例(不是目标类),但是当您调用
barTwo时().getFoo().getState()
AopProxy正在创建目标类(FooImpl)的新实例,并对其执行
getState()
方法。因此,每次调用
bar.getFoo().getState()
都将创建
FooImpl
的新实例,然后执行其
getState()
method.

奇怪的是,它怎么知道什么时候需要用新实例替换代理!如果只是在目标类上执行公共方法,它基本上不会用新实例更改代理。这就是代理的概念。如果你想知道目标是什么,代理只会从IOC获取目标,IOC只会返回新的insta你应该看到上面@Babl的答案。
package biz.tugay;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import static java.lang.System.out;

public class TestClass {

    final static Class<SpringConfiguration> SPRING_CONFIGURATION_CLASS = SpringConfiguration.class;

    public static void main(String[] args) {

        final ApplicationContext applicationContext;
        applicationContext = new AnnotationConfigApplicationContext(SPRING_CONFIGURATION_CLASS);

        final Bar barOne = applicationContext.getBean(BarImpl.class);
        final Bar barTwo = applicationContext.getBean(BarImpl.class);

        out.println("barOne == barTwo: " + (barOne == barTwo));
        out.println("barOne.getFoo == barTwo.getFoo: " + (barOne.getFoo() == barTwo.getFoo()));

        out.println(barOne.getFoo().getState());
        out.println(barTwo.getFoo().getState());

    }
}
barOne == barTwo: true
barOne.getFoo == barTwo.getFoo: true
064bdb74-cad7-4d13-86fe-a4fc0021e5a0
c6f2d9be-09b4-456d-9414-8ece2f2acc9e
barOne.getFoo() == barTwo.getFoo()
barOne.getFoo().getState() != barTwo().getFoo().getState()