开发者

Using Spring as a JPA Container

I found this article which talks about using Spring as a JPA container:

http://java.sys-con.com/node/366275

I have never used Spring before this and am trying to make this work and hope someone can help me.

In the article it states that you need to annotate a Spring bean with @Transactional and methods/fields with @PersistenceContext in order to provide transaction support and to inject an entity manager.

Is there something the defines a bean as a "Spring Bean"? I have a bean class which implements CRUD operations on entities using generics:

@Transactional
public class GenericCrudServiceBean implements GenericCrudService
{
    @PersistenceContext(unitName="MyData")
    private EntityManager em;

    @Override
    @PersistenceContext
    public <T> T create(T t)
    {
        em.persist(t);
        return t;
    }

    @Override
    @PersistenceContext
    public <T> void delete(T t)
    {
        t = em.merge(t);
        em.remove(t);
    }
...
...
...
    @Override
    @PersistenceContext
    public List<?> findWithNamedQuery(String queryName)
    {
        return em.createNamedQuery(queryName).getResultList();
    }
}

Originally I only had this peristence context annotation:

@PersistenceContext(unitName="MyData")
private EntityManager em;

but had a null em when findWithNamedQuery was invoked. Then I annotated the methods as well, but em is still null (no injection?).

I was wondering if this had something to do with my bean not being recognized as "Spring".

I have done configuration as best I could following the directions in the article including setting the following in my context.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:tx="http://www.springframework.org/schema/tx"
    tx:schemaLocation="http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="MyData" />
        <property name="dataSource" ref="dataSource" />
        <property name="loadTimeWeaver"
            class="org.springframework.classloading.ReflectiveLoadTimeWeaver" />
        <property name="jpaVendorAdapter" ref="jpaAdapter" />
    </bean>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
        <property name="url" value="jdbc:oracle:thin:@localhost:1521:MySID" />
        <property name="username" value="user" />
        <property name="password" value="password" />
        <property name="initialSize" value="3" />
        <property name="maxActive" value="10" />
    </bean>

    <bean id="开发者_如何学GojpaAdapter"
        class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
        <property name="databasePlatform"
            value="org.eclipse.persistence.platform.database.OraclePlatform" />
        <property name="showSql" value="true" />
    </bean>

    <bean
        class="org.springframework.ormmjpa.support.PersistenceAnnotationBeanPostProcessor" />
    <tx:annotation-driven />
</beans>

I guessed that these belonged in the context.xml file because the article never specifically said which file is the "application context" file. If this is wrong, please let me know.


In the article it states that you need to annotate a Spring bean with @Transactional and methods/fields with @PersistenceContext in order to provide transaction support and to inject an entity manager.

That's correct and you shouldn't add @PersistenceContext on your methods, only on the private EntityManager em attribute.

Is there something the defines a bean as a "Spring Bean"?

That's a bean managed by the Spring container (i.e. Spring manages its lifecycle, wires it with other Spring beans, etc). This implies of course that you are creating a Spring container at some point.

I guessed that these belonged in the context.xml file because the article never specifically said which file is the "application context" file. If this is wrong, please let me know.

This belongs in an application context file which is just an XML file and the name doesn't really matter as long as you tell the Spring container to load it. And actually, that's the big question: how do you run your code?

The article runs the sample from a test case which extends a Spring class providing Spring support (by this I mean that it will create the Spring container for you) and allowing to tell Spring which application context file(s) to load (in this case, my-spring-config.xml) by providing a getConfigLocations method:

package org.bookguru;

import org.springframework.test.jpa.AbstractJpaTests;

public class BookInventorySystemTest extends AbstractJpaTests {

    private BookInventorySystem bookInventorySystem;

    public void setBookInventorySystem(
       BookInventorySystem bookInventorySystem) {
       this.bookInventorySystem = bookInventorySystem;
    }

    protected String[] getConfigLocations() {
       return new String[] {"/my/path/my-spring-config.xml"};
    }
} 

So, how do you run your code?


In order for a class to be a spring bean it has to be:

  • either mapped as <bean id=".." class=".."> or annotated with @Component, @Service, or similar stereotype annotations
  • not instantiated by you. If you want spring to wire your dependencies, you must let it instantiate your classes. So no new GenericCrudServiceBean() (there are "tricks" to enable dependency injection even when using the new operator, but they are for special cases)

In order not to need to instantiate your classes, you must put something "in front" of your controllers and services. For web-frameworks this would be a Servlet, or addition to the servlet, that handles your classes via the ApplicationContext of spring - in Spring MVC DispatcherServlet is used - in JSF a custom spring ELResolver is used

Depending on your framework, look for "X spring integration".

For your case - Portlets - spring have the Portlet MVC


It's worth noting the following from the Spring documentation

@EnableTransactionManagement and only looks for @Transactional on beans in the same application context they are defined in. This means that, if you put annotation driven configuration in a WebApplicationContext for a DispatcherServlet, it only checks for @Transactional beans in your controllers, and not your services. See Section 17.2, “The DispatcherServlet” for more information.

What this means when you are using portlets is that you must enable annotation-driven transactions with in your portlet context. This may possibly be your problem.

This hit me today - I had a multi-portlet app and wanted to set up all the database beans in the applicationcontext. That was fine and worked in all my tests.

However when deployed to the portlet container, none of my portlet-specific beans were aware of the transaction - the reason was because I lacked the in my portletcontext. Clear as day once I read the manual....

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜