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

В любом случае, @Autowire bean, который требует аргументов конструктора?

Я использую Spring 3.0.5 и использую аннотацию @Autowire для моих членов класса как можно больше. Один из beans, который мне нужен для autwire, требует аргументов для его конструктора. Я просмотрел документы Spring, но, похоже, не нашел ссылки на то, как комментировать аргументы конструктора.

В XML я могу использовать как часть определения bean. Есть ли аналогичный механизм для аннотации @Autowire?

Пример:

@Component
public class MyConstructorClass{

  String var;
  public MyConstructorClass( String constrArg ){
    this.var = var;
  }
...
}


@Service
public class MyBeanService{
  @Autowired
  MyConstructorClass myConstructorClass;

  ....
}

В этом примере, как указать значение "constrArg" в MyBeanService с аннотацией @Autowire? Есть ли способ сделать это?

Спасибо,

Эрик

4b9b3361

Ответ 1

Вам нужна аннотация @Value.

Общим вариантом использования является назначение значений полей по умолчанию, используя "#{systemProperties.myProp}" выражения стиля.

public class SimpleMovieLister {

  private MovieFinder movieFinder;
  private String defaultLocale;

  @Autowired
  public void configure(MovieFinder movieFinder, 
                        @Value("#{ systemProperties['user.region'] }"} String defaultLocale) {
      this.movieFinder = movieFinder;
      this.defaultLocale = defaultLocale;
  }

  // ...
}

Смотрите: Язык выражений > Настройка аннотации


Чтобы быть более ясным: в вашем сценарии вы бы связали два класса: MybeanService и MyConstructorClass, что-то вроде этого:

@Component
public class MyBeanService implements BeanService{
    @Autowired
    public MybeanService(MyConstructorClass foo){
        // do something with foo
    }
}

@Component
public class MyConstructorClass{
    public MyConstructorClass(@Value("#{some expression here}") String value){
         // do something with value
    }
}

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

Ответ 2

В этом примере, как я могу указать значение "constrArg" в MyBeanService с аннотацией @Autowire? Есть ли способ сделать это?

Нет, не так, как вы. bean, представляющий MyConstructorClass, должен быть конфигурируемым, не требуя какого-либо его клиента beans, поэтому MyBeanService не может сказать, как настроено MyConstructorClass.

Это не проблема с автосогласованием, проблема в том, как Spring создает экземпляр MyConstructorClass, учитывая, что MyConstructorClass является @Component (и вы используете компонентное сканирование и, следовательно, не указываете MyConstructorClass явно в вашей конфигурации).

Как сказал @Sean, один из ответов здесь заключается в использовании @Value для параметра конструктора, так что Spring будет извлекать значение конструктора из системного свойства или файла свойств. Альтернативой является MyBeanService для непосредственного создания экземпляра MyConstructorClass, но если вы это сделаете, то MyConstructorClass больше не является Spring bean.

Ответ 3

Ну, время от времени я сталкиваюсь с тем же вопросом. Насколько мне известно, этого нельзя сделать, когда нужно добавить динамические параметры к конструктору. Однако шаблон factory может помочь.

public interface MyBean {
    // here be my fancy stuff
}

public interface MyBeanFactory {
    public MyBean getMyBean(/* bean parameters */);
}

@Component
public class MyBeanFactoryImpl implements MyBeanFactory {
    @Autowired
    WhateverIWantToInject somethingInjected;

    public MyBean getMyBean(/* params */) {
        return new MyBeanImpl(/* params */);
    }

    private class MyBeanImpl implements MyBean {
        public MyBeanImpl(/* params */) {
            // let do whatever one has to
        }
    }
}

@Component
public class MyConsumerClass {
    @Autowired
    private MyBeanFactory beanFactory;

    public void myMethod() {
        // here one has to prepare the parameters
        MyBean bean = beanFactory.getMyBean(/* params */);
    }
}

Теперь MyBean не является spring bean как таковой, но он достаточно близко. Dependency Injection работает, хотя я ввожу factory, а не сам bean - нужно добавить новый factory поверх своей новой реализации MyBean, если захотите ее заменить.

Кроме того, MyBean имеет доступ к другому beans - потому что он может иметь доступ к файлу factory.

И, по-видимому, возможно, потребуется добавить некоторую логику в функцию getMyBean, что является дополнительным усилием, которое я допускаю, но, к сожалению, у меня нет лучшего решения. Поскольку обычно проблема заключается в том, что динамические параметры поступают из внешнего источника, например базы данных или взаимодействия с пользователем, поэтому я должен создать экземпляр bean только в середине запуска, только когда эта информация будет доступна, поэтому Factory должно быть достаточно адекватным.

Ответ 4

Вы также можете настроить свой компонент следующим образом:

package mypackage;
import org.springframework.context.annotation.Configuration;
   @Configuration
   public class MyConstructorClassConfig {


   @Bean
   public MyConstructorClass myConstructorClass(){
      return new myConstructorClass("foobar");
   }
  }
}

С аннотацией Bean вы говорите Spring зарегистрировать возвращенный бин в BeanFactory.

Таким образом, вы можете подключить его по своему желанию.

Ответ 5

Вам нужно использовать @Autowired и @Value. Для получения дополнительной информации по этой теме обратитесь к post.

Ответ 6

Альтернативой может быть вместо передачи параметров конструктору, который может быть у вас в качестве getter и seters, а затем в @PostConstruct инициализировать значения по вашему желанию. В этом случае Spring создаст bean с помощью конструктора по умолчанию. Пример ниже

@Component
public class MyConstructorClass{

  String var;

  public void setVar(String var){
     this.var = var;
  }

  public void getVar(){
    return var;
  }

  @PostConstruct
  public void init(){
     setVar("var");
  }
...
}


@Service
public class MyBeanService{
  //field autowiring
  @Autowired
  MyConstructorClass myConstructorClass;

  ....
}

Ответ 7

Большинство ответов довольно старые, поэтому в то время это было невозможно, но на самом деле существует решение, удовлетворяющее всем возможным вариантам использования.

Так что правильно знаете ответы:

  • Не предоставление реального компонента Spring (дизайн factory)
  • или не подходит для каждой ситуации (используя @Value, вы должны иметь значение в файле конфигурации где-нибудь)

Решение этих проблем состоит в том, чтобы создать объект вручную с помощью ApplicationContext:

@Component
public class MyConstructorClass
{
    String var;

    public MyConstructorClass() {}
    public MyConstructorClass(String constrArg) {
        this.var = var;
    }
}

@Service
public class MyBeanService implements ApplicationContextAware
{
    private static ApplicationContext applicationContext;

    MyConstructorClass myConstructorClass;

    public MyBeanService()
    {
        // Creating the object manually
        MyConstructorClass myObject = new MyConstructorClass("hello world");
        // Initializing the object as a Spring component
        AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory();
        factory.autowireBean(myObject);
        factory.initializeBean(myObject, myObject.getClass().getSimpleName());
    }

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        applicationContext = context;
    }
}

Это классное решение, потому что:

  • Он дает вам доступ ко всем функциям Spring на вашем объекте (например, @Autowired, но также @Async),
  • Вы можете использовать любой источник для аргументов конструктора (файл конфигурации, вычисленное значение, жестко закодированное значение,...),
  • Требуется только добавить несколько строк кода, не изменяя ничего.
  • Он также может использоваться для динамического создания неизвестного количества экземпляров класса Spring -managed (я использую его для создания нескольких асинхронных исполнителей "на лету", например)

Единственное, о чем следует помнить, это то, что у вас должен быть конструктор, который не принимает никаких аргументов (и может быть пустым) в классе, который вы хотите создать (или конструктор @Autowired, если он вам нужен).

Ответ 8

Другой вариант, если у вас уже есть экземпляр созданного объекта и вы хотите добавить его как зависимость @autowired для инициализации всех внутренних переменных @autowired, может быть следующим:

@Autowired 
private AutowireCapableBeanFactory autowireCapableBeanFactory;

public void doStuff() {
   YourObject obj = new YourObject("Value X", "etc");
   autowireCapableBeanFactory.autowireBean(obj);
}

Ответ 9

В

Вы нашли ответ на этот пост? Я ищу то же самое, дайте мне знать, если какое-либо из решений работает для вас.

Спасибо