proxyMode ScopedProxyMode.TARGET_CLASS vs ScopedProxyMode.INTERFACE

时间:2016-10-09 15:18:34

标签: java spring

正如其他SO答案建议的那样,根据您的需要使用代理模式类型,我仍然感到困惑;

@Configuration
@ComponentScan
public class Application 
{
    public static void main( String[] args )
    {
        ApplicationContext context = new AnnotationConfigApplicationContext(Application.class);

        PrototypeBeanFactory factoryBean = context.getBean(PrototypeBeanFactory.class);
        System.out.println("Let's start");
        SomeInterface b1 = factoryBean.getPrototypeBeanInstance();
        SomeInterface b2 = factoryBean.getPrototypeBeanInstance();

        System.out.println(b1.hashCode());
        System.out.println(b2.hashCode());

        b1.sayHello();
        b2.sayHello();

        b1.sayHello();
        b2.sayHello();
    }
}

@Component
public class PrototypeBeanFactory {
    @Lookup
    public PrototypeBean getPrototypeBeanInstance(){
        System.out.println("It'll be ignored");
        return null;
    }
}

@Component
@Scope(value="prototype", proxyMode = ScopedProxyMode.INTERFACES)
public class PrototypeBean {
    public PrototypeBean() {
        System.out.println("I am created");
    }

    public void sayHello() {
        System.out.println("Hello from " + this.hashCode());
    }

}

输出

Let's start
I am created
I am created
1849201180
1691875296
Hello from 1849201180
Hello from 1691875296
Hello from 1849201180
Hello from 1691875296

现在,如果我将代理模式更改为TARGET_CLASS

输出

Let's start
-721204056
-721204056
I am created
Hello from 172032696
I am created
Hello from 299644693
I am created
Hello from 1771243284
I am created
Hello from 2052256418

为什么,在基于类的代理的情况下,它会在每个方法调用上创建不同的对象?

2 个答案:

答案 0 :(得分:7)

@Component
@Scope(value="prototype", proxyMode = ScopedProxyMode.INTERFACES)
public class PrototypeBean { ... }

在您的情况下,这将导致每次调用getBean bean时都会导致bean,因为PrototypeBean没有实现接口,因此无法创建范围内的代理。在您的情况下,您调用查找方法两次,因此您将获得2个实例。这实际上是prototype范围内的bean的正常行为。

Component
@Scope(value="prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class PrototypeBean { ... }

这将导致创建代理。该代理创建一次,并将在每次调用getBean时返回。只要在代理上调用方法,它就会根据范围创建新方法或重用现有方法。由于您已将范围指定为prototype,因此每个方法调用都将导致一个新对象。

注意:如果您的类会实现一个公开适当方法的接口,那么proxyMode = ScopedProxyMode.INTERFACESproxyMode = ScopedProxyMode.TARGET_CLASS的行为就没有区别,因为在这两种情况下将创建范围代理。

答案 1 :(得分:0)

我用sayHello创建了一个PrototypeBeanI接口,并使用了main()中的接口,结果仍然不同。似乎使用PrototypeBeanI或PrototypeBean作为变量类型不会产生任何差异。