Внедрение зависимостей с помощью @Autowired в объекты, созданные с помощью «new ...» - PullRequest
4 голосов
/ 24 марта 2011

У меня проблема с внедрением бина в вспомогательный класс.Это работает в основном так: я создаю объект в конструкторе страницы, который выполняет некоторую работу, возвращает некоторые данные и показываю их на странице.В этом вспомогательном объекте сервис должен вводиться с помощью аннотации @Autowired.Тем не менее, я всегда получаю исключение нулевого указателя, когда я его использую.Я также попробовал @SpringBean, но это не помогло.С другой стороны, когда я внедряю этот сервис прямо на страницу с @SpringBean, он доступен и работает нормально.Знаете ли вы, где проблема?

Это страница:

public class Page extends BasePage {
    public Page() {
        HelperObject object = new HelperObject(new Application("APP_NAME"));
        String result = object.getData();

        add(new Label("label", result));
    }
}

Вспомогательный объект:

public class HelperObject {
    private Application app;

    @Autowired
    private Service service;

    public HelperObject(Application app) {
        this.app = app;
    }

    public String getData() {
        // use service, manipulate data, return a string
    }
}

Ответы [ 3 ]

5 голосов
/ 24 марта 2011

Вы можете внедрить зависимости в объекты, созданные не Spring-non-Wicket-new, используя @SpringBean, вызвав InjectorHolder.getInjector().inject(this); в его конструкторе.

Например:

class MyPojo {
    @SpringBean
    MyDumbDAO dao;
    MyPojo() {
        InjectorHolder.getInjector().inject(this);
    }
    void justDoIt() {
        dao.duh(); // dao is there!
    }
}

Обратите внимание, что он будет работать только в том случае, если он вызывается в рамках запроса, управляемого Wicket.Если нет (т. Е. Если это задание Quartz или фильтр, выполненный до Wicket), экземпляр Application будет недоступен, и инжектор не будет знать, как получить зависимости.

Другое решениеэто использовать Spring's @Configurable.Он использует AspectJ для перехвата создания аннотированных объектов и внедрения его зависимостей, даже если вы создаете их экземпляры напрямую с помощью new (или какой-либо другой инфраструктуры, например Hibernate, создает их внутри).Но для этого требуется манипулирование байт-кодом во время выполнения или во время сборки (лучше для меня), что может быть чересчур волшебным для некоторых людей.

3 голосов
/ 22 июля 2013

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

Вы действительно должны избегать использования SpringContext повсеместно (или любого другого подобного решения в этом отношении). Вот неполный список причин:

  1. Ваш код слишком сильно связан с Spring (низкая когезия).
  2. Вы смешиваете сантехнический код с бизнес-логикой.
  3. Ваш код менее читабелен.
  4. Это менее обслуживаемо (например, изменение имени служебного компонента приведет к модификации кода - это нарушает SRP и OCP).
  5. Он менее тестируемый (например, для его тестирования требуется среда Spring).
3 голосов
/ 24 марта 2011

@SpringBean только внедряет зависимости в классы, которые наследуются от Wicket Component.@Autowired только внедряет зависимости в классы, созданные самой Spring.Это означает, что вы не можете автоматически внедрить зависимость в объект, который вы создаете с помощью new.

(Изменить: вы также можете добавить @SpringBean инъекцию в ваш класс, вставив в конструктор: InjectorHolder.getInjector().inject(this);)

Мой обычный обходной путь для этого - использовать мой класс приложения для помощи.(Я немного озадачен тем, что вы используете new Application(...). Я предполагаю, что на самом деле это не org.apache.wicket.Application.) Например:

public class MyApplication extends AuthenticatedWebApplication implements
    ApplicationContextAware {

    private ApplicationContext ctx;

    public void setApplicationContext(ApplicationContext applicationContext)
        throws BeansException {
        this.ctx = applicationContext;
    }

    public static MyApplication get() {
        return (MyApplication) WebApplication.get();
    }

    public static Object getSpringBean(String bean) {
        return get().ctx.getBean(bean);
    }

    public static <T> T getSpringBean(Class<T> bean) {
        return get().ctx.getBean(bean);
    }

    ....
}

В моем контексте приложения Spring:

<!-- Set up wicket application -->
<bean id="wicketApplication" class="uk.co.humboldt.Project.MyApplication"/>

Мой вспомогательный объект затем ищет сервис по запросу:

public class HelperObject {

    private Service getService() {
        return MyApplication.getSpringBean(Service.class);
    }
...