Spring Scoped Proxy工作用于Scoped Proxy Beans字段的字段,但不是bean本身?

时间:2015-12-26 09:13:34

标签: java spring proxy

这是我的代码:

SpringConfiguration:

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 {
}

富:

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

public interface Foo {
    String getState();
}

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:35 */

public interface Bar {
    Foo getFoo();
}

BarImpl:

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());

    }
}

输出将是:

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

我的问题是,

我知道064bdb74-cad7-4d13-86fe-a4fc0021e5a0不等于c6f2d9be-09b4-456d-9414-8ece2f2acc9e,因为FooImpl实际上是ScopedProxy。

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

这怎么可能:

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

???

2 个答案:

答案 0 :(得分:3)

首先要解释输出,你需要了解Spring框架的工作方式和内容。让我们开始的想法,当你注射&#34;短暂的&#34;范围豆成为一个长寿的&#34; scope bean(在你的情况下是原型bean到singleton bean)Spring注入一个AOP代理来代替scoped bean。

  

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

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

让我们回到示例代码并尝试了解发生了什么...... 当您的应用程序启动时,Spring Framework会创建两个bean FooBar,但这两个bean不仅仅是一个简单的实现(FooImpl和BarImpl),而是代理(CglibAopProxy&#39; s)。 所以在你的TestClass课程中,你有2个引用同一个{0}的AopProxy barOne和barTwo。由于BarImpl的范围是单例,因此AopProxy的底层目标类是预先加入的同一对象(BarImpl)。此Bar AopProxy注入的AopPorxy类型为Bar,因此当您执行以下代码Foo时,其评估为true,因为barOne.getFoo() == barTwo.getFoo()barOne具有相同的AopProxy实例(不是目标类),但是当您调用barTwo时,AopProxy正在创建目标类的新实例(FooImpl)并在其上执行barTwo().getFoo().getState()方法。因此,每次调用getState()都会创建bar.getFoo().getState()的新实例,然后执行其FooImpl方法。

答案 1 :(得分:0)

代码突出显示:

  • 代码在Singleton中使用原型范围的bean。
  • 然后使用bean代理模式ScopedProxyMode.TARGET_CLASS。

结果是预期的。为什么呢?