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

Как вставить beans в реализацию области?

Я пишу свою собственную область (т.е. класс, который реализует org.springframework.beans.factory.config.Scope), и мне нужно ввести beans. Как это сделать?

Фон: Spring сначала должен создать всю область beans, чтобы я мог определить, какой beans перейти в область. Но как насчет beans, что мне нужно создать область в первую очередь?

4b9b3361

Ответ 1

Я придумал это обходное решение, которое кажется довольно безопасным, но я хотел бы услышать комментарии (или, может быть, мой ответ дает вам несколько лучших идей):

  • Определите область действия и дайте ей сеттеры (вместо использования @Autowired)
  • Создайте "конфигуратор областей" bean:

    public CustomScopeConfigurer {
        @Autowired private Foo foo;
        private CustomScope scope;
    
        public CustomScopeConfigurer( CustomScope scope ) {
            this.scope = scope;
        }
    
        @PostConstruct
        public void initScope() {
            scope.setFoo( foo );
        }
    }
    

    Этот конфигуратор bean не должен быть ленивым.

Рассуждение:

  • Сама область не может использовать автосогласование, потому что она создается до первого bean. Хотя он может быть создан позже, вы можете быть уверены, что он будет создан до всех остальных bean. Поэтому автоустановка не может работать надежно.

  • Конфигуратор bean будет создан вместе со всеми другими beans, но после области. Таким образом, аутсорсинг будет работать для него.

  • Так как конфигуратор bean не инициализирован ленивым, он будет создан до того, как остальная часть приложения увидит контекст приложения. Это означает, что no beans для области (т.е. beans с @Scope("custom")) может быть создано в это время - область не может быть "активной", но → Spring не пыталась поместите в него все beans.

  • Сама область обычно создается как статическая константа. Поэтому мы должны передать это как аргумент конструктору.

Ответ 2

Вы можете сделать это очень просто.

Рассмотрим следующий класс пользовательской видимости:

package com.way2learn;

import java.util.Map;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;

public class MyCustomScope implements Scope{

    private Map<String, Object> scope;

    public void setScope(Map<String, Object> scope) {
        this.scope = scope;
    }

    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        checkAndClear();
        Object bean=scope.get(name);
        if(bean==null){
            bean=objectFactory.getObject();
            scope.put(name,bean);
        }
        return bean;
    }
    private void checkAndClear() {
        //Some logic to check condition and clear the scope
    }
    //optional methods
    @Override
    public Object remove(String name) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void registerDestructionCallback(String name, Runnable callback) {

    }

    @Override
    public Object resolveContextualObject(String key) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public String getConversationId() {
        // TODO Auto-generated method stub
        return null;
    }

}

Он имеет зависимость от java.util.Map.

Вы не можете использовать autotire с помощью @Autowired, поскольку как @Autowired аннотация работает только после AutoWiredAnnotationBeanPostProcessor.

Но пользовательские области будут зарегистрированы до AutoWiredAnnotationBeanPostProcessor.

Итак, вы можете вручную ввести Map в класс MyCustomScope, как показано ниже:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd">

        <util:map key-type="java.lang.String" value-type="java.lang.Object" id="custScopeMap"/>

        <bean id="myCustomScope" class="com.way2learn.MyCustomScope">
            <property name="scope" ref="custScopeMap"/>
        </bean>

        <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
            <property name="scopes">
                <map>
                    <entry key="myScope" value-ref="myCustomScope"/>
                </map>
            </property>
        </bean>

</beans>

Я попробовал. Он работает нормально. И я нашел ошибку в ответе Aaron Digulla's i.e.

Рассмотрим приведенный ниже сценарий: сначала будет создан Spring CustomScopeConfigurer bean, сразу будет создан CustomScope bean, и теперь наша пользовательская область готова к использованию. Через некоторое время будет создано Aaron Digulla CustomScopeConfigurer, которое инициализирует foo в CustomScope. Но что произойдет, если после CustomScope registration и Aaron Digulla CustomScopeConfigurer bean создаются некоторые пользовательские области beans? Для этих beans не будет foo в CustomScope bean.