Инъекция бобов внутри JPA @Entity

spring spring-mvc jpa

31613 просмотра

3 ответа

Можно ли внедрить bean-компоненты в JPA, @Entityиспользуя инъекцию зависимостей Spring?

Я попытался @Autowire ServletContext, но, хотя сервер действительно запустился, я получил исключение NullPointerException при попытке получить доступ к свойству компонента.

@Autowired
@Transient
ServletContext servletContext;
Автор: theblang Источник Размещён: 12.11.2019 09:22

Ответы (3)


39 плюса

Решение

Вы можете внедрить зависимости в объекты, не управляемые контейнером Spring, используя, @Configurableкак описано здесь: http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/aop.html#aop-atconfigurable ,

Как вы уже поняли, если только не используется @Configurableсоответствующая ткацкая конфигурация AspectJ, Spring не внедряет зависимости в объекты, созданные с помощью newоператора. На самом деле, он не вводит зависимости в объекты, если вы не получили их из ApplicationContext, по той простой причине, что он просто не знает об их существовании. Даже если вы аннотируете свою сущность @Component, создание этой сущности все равно будет выполняться newоперацией, либо вами, либо фреймворком, таким как Hibernate. Помните, аннотации - это просто метаданные: если никто не интерпретирует эти метаданные, это не добавляет поведения и не влияет на работающую программу.

Все это, как говорится, я настоятельно рекомендую не вводить ServletContextв сущность. Объекты являются частью вашей доменной модели и должны быть отделены от любого механизма доставки, такого как уровень веб-доставки на основе сервлетов. Как вы будете использовать эту сущность, когда к ней обращается клиент командной строки или что-то еще, не связанное с ServletContext? Вы должны извлечь необходимые данные из этого ServletContext и передать их через аргументы традиционного метода вашей сущности. Благодаря этому подходу вы достигнете гораздо лучшего дизайна.

Автор: Spiff Размещён: 16.07.2013 10:40

20 плюса

Да, конечно ты можешь. Вам просто нужно убедиться, что сущность также зарегистрирована как управляемый компонент Spring либо декларативно с использованием <bean>тегов (в некотором spring-context.xml), либо с помощью аннотаций, как показано ниже.

Используя аннотации, вы можете пометить свои объекты @Component(или более конкретным стереотипом, @Repositoryкоторый включает автоматический перевод исключений для DAO и может или не может мешать JPA).

@Entity
@Component
public class MyJAPEntity {

  @Autowired
  @Transient
  ServletContext servletContext;
  ...
}

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

<beans ... xmlns:context="..." >
  ...
  <context:component-scan base-package="pkg.of.your.jpa.entities" />
<beans>

РЕДАКТИРОВАТЬ : (что, наконец, сработало и почему)

  • Создание ServletContext статики . (удалить @Autowired )

    @Transient
    private static ServletContext servletContext;
    

Поскольку JPA создает отдельный экземпляр сущности, т. Е. Не использует управляемый bean-компонент Spring, он необходим для совместного использования контекста .

  • Добавление метода @PostConstruct init() .

    @PostConstruct
    public void init() {
        log.info("Initializing ServletContext as [" +
                    MyJPAEntity.servletContext + "]");
    }
    

Это срабатывает init()после создания экземпляра сущности и, ссылаясь ServletContextвнутри, вызывает принудительное внедрение статического свойства, если оно еще не введено.

  • Переход @Autowiredк методу экземпляра, но установка статического поля внутри.

    @Autowired
    public void setServletContext(ServletContext servletContext) {
        MyJPAEntity.servletContext = servletContext;
    }
    

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

Нет хорошего способа сделать то, что вы хотите, поскольку JPA не использует контейнер Spring для создания экземпляров своих сущностей. Думайте о JPA как об отдельном контейнере ORM, который создает экземпляр жизненного цикла сущностей и управляет им (полностью отделенный от Spring) и выполняет DI только на основе взаимосвязей сущностей.

Автор: Ravi Thapliyal Размещён: 10.05.2013 06:58

1 плюс

После долгого времени я наткнулся на этот SO ответ, который заставил меня задуматься об элегантном решении:

  • Добавьте к своим сущностям все необходимые поля @Transient @Autowired
  • Создайте @Repository DAO с этим автоматическим полем: @Autowired private AutowireCapableBeanFactory autowirer;
  • Из вашего DAO, после извлечения сущности из БД, вызовите этот код автоматического подключения: String beanName = fetchedEntity.getClass().getSimpleName(); autowirer.autowireBean(fetchedEntity); fetchedEntity = (FetchedEntity) autowirer.initializeBean(fetchedEntity, beanName);

Затем ваша сущность сможет получить доступ к полям с автопроводкой, как любой @Component.

Автор: xtian Размещён: 13.11.2017 10:17
Вопросы из категории :
32x32