Подтвердить что ты не робот

Spring Прототип scoped bean в одноэлементном

Я пытаюсь внедрить bean-компонент prototype в bean-компонент singleton так, чтобы каждый новый вызов метода синглтон-компонента имел новый экземпляр прототипа bean-компонента.

Рассмотрим синглтон-бин, как показано ниже:

    @Component
    public class SingletonBean {
       @Autowired 
       private PrototypeBean prototypeBean;

       public void doSomething() {
         prototypeBean.setX(1);
         prototypeBean.display();
       }
    }

Я ожидаю, что каждый раз, когда вызывается метод doSomething(), используется новый экземпляр PrototypeBean.

Ниже приведен пример прототипа:

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

        void setX(Integer x) {
         this.x = x;
        }

        void display() {
          System.out.println(x);
        }
    }

То, что, похоже, происходит, заключается в том, что spring слишком тяготеет к передаче нового экземпляра PrototypeBean в методе doSomething(). Таким образом, две строки кода в методе doSomething() создают новый экземпляр prototypeBean в каждой строке.

И так во 2-й строке - prototypeBean.display() печатает NULL.

Чего не хватает в конфигурации для этой инъекции?

4b9b3361

Ответ 1

Из Spring документации:

Вам не нужно использовать <aop:scoped-proxy/> в сочетании с beans, которые определены как одиночные или прототипы. Если вы попытаетесь создать ограниченный прокси-сервер для singleton bean, BeanCreationException.

Кажется, документация немного изменилась для версии 3.2 документации, где вы можете найти это предложение:

Вам не нужно использовать <aop:scoped-proxy/> в сочетании с beans, которые определены как одиночные или прототипы.

Кажется, что не предполагается, что вы используете прокси-прототип bean, так как каждый раз, когда он запрашивается BeanFactory, он создаст новый экземпляр.


Чтобы ваш прототип bean имел вид factory, вы можете использовать ObjectFactory следующим образом:

@Component
public class SingletonBean {

    @Autowired
    private ObjectFactory<PrototypeBean> prototypeFactory;

    public void doSomething() {
        PrototypeBean prototypeBean = prototypeFactory.getObject();
        prototypeBean.setX(1);
        prototypeBean.display();
    }
}

и ваш прототип bean будет объявлен следующим образом:

@Component 
@Scope(value="prototype")
public class PrototypeBean {
    // ...
}

Ответ 2

Синглтон-бин создается только один раз, поэтому внедренный bean-объект-прототип также создается один раз при создании экземпляра синглтон-компонента. Один и тот же экземпляр bean-компонента-прототипа будет использоваться для каждого запроса.

Если новый экземпляр компонента-прототипа будет создан для каждого запроса во время выполнения, можно использовать приведенный ниже метод Injection

Пример

public class Singleton {
    private Prototype prototype;

    public Singleton(Prototype prototype) {
        this.prototype = prototype;
    }

    public void doSomething() {
         prototype.foo();
    }

    public void doSomethingElse() {
        prototype.bar();
    }
}

public abstract class Singleton {
    protected abstract Prototype createPrototype();

    public void doSomething() {
        createPrototype().foo();
    }

    public void doSomethingElse() {
        createPrototype().bar();
    }
}


<bean id="prototype" class="ch.frankel.blog.Prototype" scope="prototype" />
<bean id="singleton" class="sample.MySingleton">
   <lookup-method name="createPrototype" bean="prototype" />
</bean>

Ответ 3

Правильный способ его достижения - использовать метод поиска методом поиска и везде, где вы использовали beans использовать метод вызова метода поиска (подробный ответ)

Ответ 4

Spring прокладывает ваш beans довольно простым способом. Я работаю в большом коммерческом приложении, и я вставлял следующие фрагменты кода для проверки порядка загрузки.

1) Все ваши структуры oneton bean изначально загружаются Spring (пока Spring знает об этом через аннотации и/или xml). Это случается только однажды. Вы можете проверить это путем записи или печати в статическом блоке:

    static {
        log.info("#### classNameHere loaded"); //or println if no log setup
    }

2) Spring создает все экземпляры singleton, о которых он знает (но не прототипы! экземпляры Prototype будут созданы, если они ссылаются внутри singleton bean - там, естественно, загружаются структуры классов). Вы можете проверить это, добавив этот метод в каждый класс:

    @PostConstruct
    public void methodHitAfterClassInstantiation() {
        LOGGER.info("#### instance of classNameHere");
    }

Итак, в вашем примере структуры классов SingletonBean загружаются при запуске Spring. Создается новый экземпляр SingletonBean. И поскольку PrototypeBean Autowired внутри SingletonBean, его структура классов загружается и создается экземпляр. Теперь, если был еще один bean, скажем AnotherSingletonBean, с Autwired PrototypeBean внутри из него будет создан РАЗЛИЧНЫЙ экземпляр PrototypeBean (нет необходимости снова загружать структуру класса). Таким образом, существует только 1 SingletonBean, а внутри него PrototypeBean, который всегда будет указывать на тот же bean. Из-за этого синглтоны всегда должны быть безгражданными, так как все ваши другие beans, которые используют синглтон, будут указывать на  тот же объект. Но вы можете сохранить состояние в прототипе bean, потому что везде, где вы создаете новую ссылку, вы укажете на другой объект bean.  http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-factory-scopes-prototype