Универсальный Java-сервис с программным созданием бина не внедряет EntityManager - PullRequest
0 голосов
/ 31 марта 2011

У меня (надеюсь) стандартная установка с кучей @Controller, @Service, @Entity и @Repository аннотированных классов, например:

@Service
public class ChannelManager {
    @Autowired
    private ChannelDao channelDao;

    public List<Channel> allChannels() {
        return channelDao.findAll();
    }
}

где ChannelDao is:

public interface ChannelDao extends PersistentDao<Channel> {}

ChannelImpl is:

@Repository
public class ChannelImpl extends PersistentImpl<Channel> implements ChannelDao {}

Channel is:

@Entity
@Table(name = "channel")
public class Channel extends Persistent {
    @Id
    @Column(name = "id", nullable = false)
    private Long id;
    // set/get
}

PersistentDao is:

public interface PersistentDao<T extends Persistent> {
    public List<T> findAll();
}

и, наконец, PersistentImpl - это:

public class PersistentImpl<T extends Persistent> implements PersistentDao<T> {
    @PersistenceContext
    protected EntityManager entityManager;

    private Class<T> clazz; // gets assigned correctly

    public List<T> findAll() {
        return entityManager.createQuery("from " + clazz.getSimpleName()).getResultList();
    }
}

Все это работает, как и ожидалось.Я использую <context:annotation-config/> и <context:component-scan/>, а также <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" ...> с persistence.xml.В основном все это работает.

Но теперь я хочу обобщить ChannelManager, так как у меня есть много других сущностей и я хочу избежать дублирования.Например, мне также нужен JobManager с методом List<Job> allJobs() { return jobDao.findall(); }.

Итак, я создал это:

@Service
public class GeneralManager<T extends PersistentDao, E extends Persistent>  {
    @Autowired
    private AutowireCapableBeanFactory factory;
    public void setFactory(AutowireCapableBeanFactory factory) {
        this.factory = factory;
    }

    private Class<? extends T> impl;
    private T dao;

    public GeneralManager(Class<? extends T> impl) throws Exception {
        this.impl = impl;
    }

    @PostConstruct
    public void postCtor() {
        dao = factory.createBean(impl); // seems to be created and is not null
    }

    public List<E> all() {
        return dao.findAll();
    }
}

И я обновил context.xml

<bean id="jobImpl" class="a.b.c.GeneralManager">
    <property name="factory" ref="autowireFactory"/>
    <constructor-arg value="a.b.c.JobImpl"/>
</bean>

<bean id="autowireFactory" class="org.springframework.beans.factory.support.DefaultListableBeanFactory"/>

<context:annotation-config/>
  <context:component-scan base-package="a.b.c">
    <context:exclude-filter type="regex" expression=".*GeneralManager"/>
</context:component-scan>

И наконец добавил объявление в контроллер:

@Autowired
@Qualifier(value="jobImpl")
private GeneralManager<JobDao, Job> jobManager;

Просто представьте, что классы Jobxxx похожи на классы Channelxxx.

Однако, когда дело доходит до выполнения метода findAll() вДля специализации JobImpl entityManager равен null , поэтому что-то настроено неправильно.

Итак, мой вопрос действительно заключается в том, "можно ли это сделать"?Хотя, если есть альтернативный и более хороший способ сделать это, пожалуйста, просветите меня!

Редактировать: Следует отметить, что я использую Spring 3.0.5, Java 1.6.0_21-b07и Hibernate 3.6.2.Final

Ответы [ 2 ]

1 голос
/ 01 апреля 2011

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

Мой код теперь выглядит так:

public class GeneralManager<T extends PersistentDao, E extends Persistent>  {
    private T dao;
    public void setDao(T dao) {
        this.dao = dao;
    }
    ...
}

с использованием контроллера:

@Autowired
private GeneralManager<ChannelDao, Channel> channelManager;

@Autowired
private GeneralManager<JobDao, Job> jobManager;

и context.xml теперь имеет:

<bean id="jobManager" class="com.a.b.service.EntityManager" p:dao-ref="jobImpl"/>
<bean id="jobImpl" class="com.a.b.dao.JobImpl"/>
<bean id="channelManager" class="com.a.b.service.EntityManager" p:dao-ref="channelImpl"/>
<bean id="channelImpl" class="com.a.b.dao.ChannelImpl"/>

Надеюсь, это кому-нибудь поможет!

0 голосов
/ 28 марта 2013

почему бы просто не использовать проект spring-data? он делает именно то, что вам нужно, и даже больше.

...