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

Необязательные Spring bean ссылки

В моем приложении я использую ContextLoaderListener для загрузки файлов контекста из многих банок, используя:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:META-INF/contextBeans.xml</param-value>
</context-param>

Это означает, что я могу ссылаться на beans на другие банки без импорта.

В приложении есть несколько вариантов развертывания, и в некоторых вариантах развертывания банки могут быть исключены. Чтобы поддержать это, я хотел бы, чтобы некоторые ссылки bean были необязательными. Например:

<bean id="mainAppBean" class="com.someapp.MyApplication">
    <constructor-arg index="0" ref="localBean"/>
     <constructor-arg index="1" ref="optionalBeanReference1"/>
    <constructor-arg index="2" ref="optionalBeanReference2"/>
 </bean>

В приведенном выше примере я хотел бы иметь опциональное значениеBeanReference1 равным null, если ссылка не найдена (пометьте ее необязательным в некотором роде)

Можно ли это сделать в Spring? или какой метод вы рекомендуете для обработки динамических ссылок?

4b9b3361

Ответ 1

какой метод вы рекомендуете для обработки динамических ссылок?

Я думаю, что @cristian @Ответ на вопрос - хороший. Это вызовет методы настройки, если доступно beans этого типа. Однако, если у вас есть несколько beans одного типа, я считаю, что Spring генерирует исключение. Если вы не можете использовать @Autowired для этой или какой-либо другой причины, я вижу пару решений:

  • Вы можете создать свой класс ApplicationContextAware и самостоятельно найти beans в контексте:

    public void setApplicationContext(ApplicationContext applicationContext) {
        if (applicationContext.containsBean("optionalBeanReference1")) {
            setOptionalBeanReference1(
                (OptionalBeanReference1)applicationContext.bean(
                    "optionalBeanReference1");
        }
        ...
    }
    
  • Вы можете инвертировать зависимость. Каждый из необязательных классов мог установить себя на mainAppBean. Я использую это в определенных ситуациях, когда прямая зависимость вызывает циклы или другие проблемы.

    <bean id="optionalBeanReference1" class="com.someapp.SomeClass">
        <constructor-arg index="0" ref="mainAppBean"/>
    </bean>
    

    Затем в SomeClass:

    public SomeClass(com.someapp.MyApplication mainAppBean) {
        mainAppBean.setOptionalBeanReference1(this);
    }
    
  • Вы можете остаться с вашей прямой зависимостью, а затем либо импортировать файл с beans, либо указать другой файл, в котором вы определяете beans как имеющие нулевые значения, используя factory bean. См. Этот factory код.

Удачи.

Ответ 2

Мое лучшее предположение - использовать autowire -инг с требуемым значением false. Не знаете, как вы можете выразить это в XML, но используя конфигурацию аннотаций, это будет выглядеть так:

@Autowired(required=false)

Ответ 3

В последних версиях Spring (протестированных с помощью Spring 4.1) и конфигурации Java и Java 8 вы можете использовать опцию в параметрах и только в том случае, если они доступны.

@Autowired
public MyApplication(Optional<YourOptionalObject> maybeObject) {
    // do something with the optional autowired
}

Ответ 4

Для этого нет встроенного механизма. Однако вы можете написать довольно тривиальную реализацию FactoryBean, чтобы сделать это для вас, примерно так:

public class OptionalFactoryBean extends AbstractFactoryBean<Object> implements BeanNameAware {

    private String beanName;

    @Override
    public void setBeanName(String beanName) {
        this.beanName = BeanFactoryUtils.originalBeanName(beanName);

    }

    @Override
    protected Object createInstance() throws Exception {
        if (getBeanFactory().containsBean(beanName)) {
            return getBeanFactory().getBean(beanName);
        } else {
            return null;
        }
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }
}

Затем вы можете использовать его следующим образом:

<bean id="mainAppBean" class="com.someapp.MyApplication">
    <constructor-arg index="0" ref="localBean"/>    
    <constructor-arg index="1">
       <bean name="optionalBeanReference1" class="com.someapp.OptionalBeanFactory"/>
    </constructor-arg>
    <constructor-arg index="2">
       <bean name="optionalBeanReference2" class="com.someapp.OptionalBeanFactory"/>
    </constructor-arg>
</bean>

Ответ 5

Учитывая, что ссылки bean в вашей конфигурации XML определяются с помощью языка выражений (EL), вы можете сделать следующее:

<property name="cache" value="#{getObject('optionalCache')}" />

который использует метод BeanExpressionContext.getObject(). Подробнее см. здесь.