Spring @Autowired на новый экземпляр класса - PullRequest
0 голосов
/ 16 сентября 2018

Я не очень знаком с Spring и имею следующую ситуацию:

Класс репозитория:

@Repository
public class MyRepository {
    // ...
}

Класс, использующий класс репозитория:

public class MyClass extends AbstractClass {

    @Autowired
    private MyRepository myRepository;

    //...
}

Я знаю, что если я аннотирую свой MyClass с помощью @Component и использую его с @Autowired, то @Autowired MyRepository разрешается очень хорошо.Проблема в том, что мне нужно создать новые экземпляры MyClass с отражением.Так что MyRepository никогда не разрешается и все время является нулевым.

Есть ли способ использовать @Autowired в этой ситуации?

Объясняя лучше мою ситуацию:У меня есть несколько реализаций AbstractClass.На этапе настройки моего приложения я создаю HashMap этих реализаций.В основном:

{"MyClass", MyClass.class}
//...

Затем у меня есть универсальный Controller, который сопоставляется с URL /{class}?options=.... Используя {class} @PathVariable, HashMap выше и отражение, я могу создать экземпляркласса, основанного на данном options (эта часть важна).Ребята, вы думаете, есть лучший способ сделать это?

Заранее спасибо

Ответы [ 6 ]

0 голосов
/ 16 сентября 2018

Spring сам по себе предлагает некоторую функциональность для автоматического подключения ваших объектов который вы создали new или newInstance() или что-то еще.

Чтобы использовать его, вам нужно AutowireCapableBeanFactory который вы получаете с помощью обычной инъекции зависимостей Spring с @Autowired.

@Autowired
private  AutowireCapableBeanFactory autowireCapableBeanFactory;

Затем вы используете его autowireBean(Object) метод внедрить свойства @Autowired в ваш бин.

Object myBean = map.get(className).newInstance();
autowireCapableBeanFactory.autowireBean(myBean);

Примечание по проекту:

Подумайте хорошо, если вам действительно нужен подход выше. Javadoc AutowireCapableBeanFactory не рекомендуется использовать этот интерфейс в большинстве случаев:

Этот подинтерфейс BeanFactory не предназначен для использования в обычном коде приложения: придерживайтесь BeanFactory или ListableBeanFactory для типичных случаев использования.

Код интеграции для других платформ может использовать этот интерфейс для связи и заполнения существующих экземпляров компонентов, которые Spring не контролирует жизненный цикл. Это особенно полезно, например, для действий WebWork Actions и объектов Tapestry Page.

0 голосов
/ 16 сентября 2018

Попробуйте это

@Component    
public class SomeClass extends AbstractClass {

  private static ApplicationContext applicationContext;

  public MyClass getMyClass(){
      // Now @Autowired MyRepository will work
      return applicationContext.getBean(MyClass.class);
  }

}
0 голосов
/ 16 сентября 2018

Вы можете использовать Factory Design Pattern здесь.

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

Шаги:

  1. Добавить @Component во все реализации AbstractClass.
  2. Создать фабричный класс как:

    @Component
    public class MyFactory {
    
        private final Map<String, AbstractClass> impletationMap = new HashMap<>();
    
        @Autowired
        ApplicationContext context;
    
        @PostConstruct
        public void initialize() {
            populateDataMapperMap(context.getBeansOfType(AbstractClass.class).values().iterator());
        }
    
        private void populateDataMapperMap(final Iterator<AbstractClass> classIterator) {
            while (classIterator.hasNext()) {
                AbstractClass abstractClassImpl = (AbstractClass) classIterator.next();
                impletationMap.put(abstractClassImpl.getClass().getName(), abstractClassImpl);
    
            }
        }
    }
    

Когда Бин этого класса MyFactory инициализируется, он будет искать все бины типа AbstractClass и помещать их в HashMap (creationMap).

Теперь с этой фабрики вы можете получить HashMap, а затем получить реализации по мере необходимости.Это будет очень легко, когда вы добавите новую реализацию AbstractClass, поскольку фабрика позаботится об этом.

0 голосов
/ 16 сентября 2018

Обходной путь - вместо привязки MyClass к Hashmap для привязки класса Factory.MyClassFactory.Таким образом, вы делегируете конструкцию конкретной фабрике, которая выполнит работу по созданию экземпляра правильного класса и инициализации правильного хранилища.

Вот пример:

{"MyClass", MyClassFactory.class}

Фабрика можетБудь также компонентным, тогда вам нужно привязать хэш-карту к экземпляру фабрики, а не к классу фабрики.Но допустим, что это не компонент:

//@Component   this is optional
    public MyClassFactory {
        //@Autowired optional
        ApplicationContext ctx;


       public MyClass createInstance() {
            MyRepository repo = ctx.getBean("")
            MyClass myclass = new MyClass(repo)
            return myclass;
       }
    }

Если вы пометите его как компонент, вы также можете использовать интерфейс ApplicationContextAware, если вы собираетесь автоматически связывать ApplicationContext.

0 голосов
/ 16 сентября 2018

Один из подходов - объявить @Component поверх MyClass.

Затем, на этапе установки, вы можете передать экземпляр из MyClass вместо самого MyClass.class в HashMap. Не нужно создавать экземпляры с помощью отражения.

Примечание: Вы можете получить экземпляр MyClass из вашего ApplicationContext на этапе настройки.

0 голосов
/ 16 сентября 2018

Да, вы можете аннотировать все ваши компоненты реализации AbstractClass с помощью @Component и использовать следующее объявление

@Autowired
private List<AbstractClass> beans;

Затем вы можете преобразовать это в Map в методе @PostConstruct.

Spring не будет жаловаться на дубликаты определений, если вы автоматически связываете списки.

...