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

Spring прототип beans в сочетании с singleton beans и инъекцией зависимостей. Есть ли подход, который является только конфигурацией?

У меня есть singleton bean, который необходим для каждого вызова функции, чтобы вернуть ссылку на другой (новый) прототип bean. Единственный способ, который я могу придумать, - это программно получить новый экземпляр bean из BeanFactory/ApplicatioContext, вызвав его метод getBean(). Образец кода будет следовать за...

Есть ли лучший способ сделать это? Надеюсь, только через конфигурацию? (Лично я сомневаюсь, что есть...)

<bean id="protoBean" scope="prototype"
        class="com.blahblah.ProtoBean" />

<bean id="singletonBean"
        class="com.blahblah.SingletonBean" />

public class ProtoBean {

    ....
}

public class SingletonBean {

    private BeanFactory factory;

    public ProtoBean dispense() {
        return (ProtoBean) factory.getBean("protoBean");
    }

    ....
}
4b9b3361

Ответ 2

Из Spring 3.0 мы можем использовать <aop:scoped-proxy> для инъекции зависимости правильного объема. За сценой Spring вводит прокси-объекты и отвечает за поиск правильного контекста области видимости, может быть прототип, сеанс или запрос и т.д. См. Официальную документацию здесь.

И чтобы облегчить жизнь, Spring также ввел атрибут proxyMode для @Scope, поэтому мы не ограничиваемся только объявлениями XML. Например:

@Scope(value = "prototype", proxyMode = ScopedProxyMode.INTERFACES)

Удостоверьтесь, что документ явно введен, bean является прокси-сервером, предупреждающим других о том, что getClass() и литье могут не дать ожидаемого результата. Кроме того, убедитесь, что equals() и hashCode() в прокси-классе используют методы доступа вместо прямого доступа к переменным класса.

Ответ 3

Использование метода инъекции делает singleton- bean класс сложным для модульного тестирования (вам нужно создать подкласс для реализации метода, который выдает зависимость). Плюс это менее многоразово, потому что вы не можете напрямую его создавать, поэтому, если вы не используете Spring и хотите использовать этот класс, вам нужно подклассы и предоставить метод bean -returning.

Лучший подход IMHO заключается в использовании прокси-сервера, прототипа целевого источника и прототипа target bean, как показано ниже. Такой класс singleton-bean легко тестируется и может быть использован многократно.

<bean id="targetPooledObject" class="pool.PooledObject" scope="prototype">
    <constructor-arg value="42" />
</bean>

<bean id="prototypeTargetSource" class="org.springframework.aop.target.PrototypeTargetSource">
    <property name="targetBeanName" value="targetPooledObject" />
</bean>

<bean id="pooledObject" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="targetSource" ref="prototypeTargetSource" />           
</bean>

<bean id="poolConsumer" class="pool.PoolConsumer">
    <property name="pooledObject" ref="pooledObject" />
</bean>

Теперь мы можем вставить pooledObject в одноэлементный bean (poolConsumer, как показано выше), и для каждого вызова метода, который мы делаем на этом одноэлементном bean (например, каждый раз, когда мы вызываем poolConsumer.callPooledObjectMethod(), который в свою очередь, вызывает pooledObject.foo()), мы получаем новый файл PooledObject bean.

Ниже приведен соответствующий код:

public class PooledObject 
{
    private int x;

    public PooledObject(int x)
    {
        this.x = x;
    }

    public void foo()
    {
        System.out.println("foo called");
    }
}

public class PoolConsumer
{
    private PooledObject pooledObject;

    public PooledObject getPooledObject() 
    {
        return pooledObject;
    }

    public void setPooledObject(PooledObject pooledObject) 
    {
        this.pooledObject = pooledObject;
    }

    public void callPooledObjectMethod()
    {
        pooledObject.foo();
    }
}