5

I want to make sure that since I am using @PersistenceContext I do not need to close any connections so as to avoid leakages and any left open connections and poor performance. So my applicationContext.xml looks as follows (where i define the entitymanager factory etc..)

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd">

<context:component-scan base-package="com.companyname.*" />

<tx:annotation-driven/>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceXmlLocation" value="classpath:com/urbanbuz/controller/persistence.xml" />
    <property name="persistenceUnitName" value="userPersistenceUnit" />
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
    <property name="jpaDialect" ref="jpaDialect" />
</bean>

<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    <property name="database" value="MYSQL" />
    <property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect" />
    <property name="showSql" value="true"/>
</bean>

<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
    <property name="dataSource" ref="dataSource" />
    <property name="jpaDialect" ref="jpaDialect" />
</bean>

<tx:annotation-driven transaction-manager="transactionManager" />

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost:3306/ub" />
    <property name="username" value="root" />
    <property name="password" value="" />
</bean>

My persistence xml is as follows accordingly:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
version="1.0">
<persistence-unit name="userPersistenceUnit" transaction-type="RESOURCE_LOCAL" >
    <provider>org.hibernate.ejb.HibernatePersistence</provider> 
    <class>com.urbanbuz.model.User</class>
    <class>com.urbanbuz.model.Account</class>
    <class>com.urbanbuz.model.AccountDetails</class>
    <class>com.urbanbuz.model.Posting</class>
    <class>com.urbanbuz.model.Journal</class>
</persistence-unit>

Now for each of those models I have a DAO and Service class, as an example I am providing one:

@Repository("accountDao")
@Transactional(propagation = Propagation.REQUIRED)
public class AccountDAO {
@PersistenceContext
private EntityManager entityManager;

public EntityManager getEntityManager() {
    return entityManager;
}

public void setEntityManager(EntityManager entityManager) {
    this.entityManager = entityManager;
}

// method inserts account into database
public void insert(Account account) {
    entityManager.persist(account);
}
}

@Service
public class AccountService {

private AccountDAO accountDAO;

public AccountDAO getAccountDao() {
    return accountDAO;
}

@Autowired
public void setAccountDao(AccountDAO accountDAO) {
    this.accountDAO = accountDAO;
}

public void addAccount(Account account) {
    getAccountDao().insert(account);
}
}

So whenever I need to access the database and perform any actions I define the following: ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml") and then define the context EntityService entityService = (EntityService) context.getBean("entityService") and accordingly call the needed methods. Do I need any further special management?

Edit: App.Java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/applicationContext.xml" })
public class App {
    public static void main(String[] args) {
     // here i just initialize an instance of the a component I have
     SignupComponent sc = new SignupComponent();
     // some code
     sc.signUp();
    } 
}

In the component I am trying to autowire the entities as such:

public class SignupComponent {
    @Autowired
    EntityService entityService;

    //using it as follows for example: entityService.getEntity(entity_id);
}
Farah Makki
  • 109
  • 1
  • 9
  • "So whenever I need to access the database and perform any actions I define the following: ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml") " Why everytime? Bean creation would be costly everytime? IMHO You should use singleton for the same. – SMA Dec 28 '14 at 13:27
  • Well... There's a few problems here. First off. You don't need to specify the classes in the persistence unit. And I **`strongly`** suggest you try using [Spring-Data-JPA](http://projects.spring.io/spring-data-jpa/) till you get your Spring Fu chops up. – Edward J Beckett Dec 28 '14 at 13:31
  • 1
    Never create a new context because you need a bean instance, use dependency injection. Your solution will eventually lead to database starvation, each time you do `new ApplicationContext(...)` all your beans, including the datasource etc. are recreated. Meaning each time you do that 10 new connections (I believe that is the commons-dbcp default) to the database are made. – M. Deinum Dec 28 '14 at 14:36

2 Answers2

2

You defined the annotation:driven twice:

<tx:annotation-driven/>

and

<tx:annotation-driven transaction-manager="transactionManager" />

Both are doing the same thing, since the default transaction manager is called transactionManager anyway.

Your settings are fine and Spring transaction manager and Hibernate connection providers are taking care of opening and closing connections.

The only things you need to fix are:

  1. To properly initialize the Spring Application Context.

    • If you have a web app you can simply set the WebApplicationinitializer.
    • If this is a stand along app you need to initialize the context in your bootstrap loading class.
    • If it's a test then use Spring JUnit Runner, which initializes the context on your behalf (and it can reuse it across tests)
  2. Inject your dependencies using @Autowired

    Instead of:

    EntityService entityService = (EntityService) context.getBean("entityService");
    

    you should have:

    @Autowired
    private EntityService entityService;
    
    public void callService() {
         entityService.call();
    }
    

Update

Now that I saw your App class this is what you need to do:

  1. Remove the test runner configs which are meant for testing:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = { "/applicationContext.xml" })
    
  2. Boostrap your context:

    public static void main(String args[]) {
        AbstractApplicationContext context = new ClassPathXmlApplicationContext("/applicationContext.xml");
        context.registerShutdownHook();
        EntityService entityService = (EntityService) context.getBean("entityService");
    }
    
Community
  • 1
  • 1
Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
  • Thank you @VladMihalcea for your amazing answer! I removed the , as for the ApplicationContext in my App.java (application entry point) I initialized it and passed it as an argument to the constructor of the called class would that be ok? Also for your last suggestion what are the benefits of doing so? I am getting a null pointer exception. Also do I need to call ((ClassPathXmlApplicationContext) context).close(); when my method returns? Thank you again so much! – Farah Makki Dec 29 '14 at 06:11
  • You need to post the code for App.java as well. You are right that @Autowired would not work in App since the context is not initialized. Post the code so I can figure it out better. – Vlad Mihalcea Dec 29 '14 at 08:26
  • I updated my code with the most important parts of App and a component I have @VladMihalcea – Farah Makki Dec 29 '14 at 09:40
  • Can't I initialize in App my AppliactionContext and just pass it as an argument while initializing a component? Also does it affect performance if whenever I need the service I call is as such: EntityService entityService = (EntityService) context.getBean("entityService"); ? – Farah Makki Dec 29 '14 at 09:42
  • So I will pass context to my component. Now entity i need in several components, I can safely declare this many times EntityService entityService = (EntityService) context.getBean("entityService"); ? Context is created once in the App but the service call I can create as much as needed across components (performance wise)? Btw I sincerely appreciate your continuous help :) – Farah Makki Dec 29 '14 at 11:53
  • Nope. You need the context.getBean only in App. Everywhere else you can use @Autowired as long as the beans are declared in your context xml config or they are scanned (component scan). – Vlad Mihalcea Dec 29 '14 at 11:57
  • Oh ok! I still get a null pointer exception though although I declare the bean scan . Ill debug further. Thank you for the help! – Farah Makki Dec 29 '14 at 12:27
  • Wouldnt work even after I added the following: – Farah Makki Dec 29 '14 at 12:34
  • Then it may be because it cannot find the xml context config file in the classpath. – Vlad Mihalcea Dec 29 '14 at 12:42
  • But if it cannot find it then when I previously declare EntityService entityService = (EntityService) context.getBean("entityService"); it should have given an error but it didnt right? – Farah Makki Dec 29 '14 at 12:58
  • Yes indeed. But Autowired doesn't allow unresolved dependencies either. It has requited=true. – Vlad Mihalcea Dec 29 '14 at 13:52
0

Let me see if I can offer you some assistance in the form of a common spring setup.. I'm using a few different libraries but I think you'll get a better picture of how to setup the configuration for Spring and Hibernate...

Personally, I like to keep all the separate configurations in different files. ApplicationContext being the main configuration, then data, logging, etc, etc. This is just a preference but it helps to keep things clear as Spring XML config can become verbose quickly.

Application Context

applicationContext.xml


    <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd
                http://www.springframework.org/schema/mvc
                http://www.springframework.org/schema/mvc/spring-mvc.xsd">

 
    <!-- Configures the annotation-driven Spring MVC Controller programming model.
    Note that, with Spring 3.0, this tag works in Servlet MVC only!  -->
    <mvc:annotation-driven/>

    <!-- Activates various annotations to be detected in bean classes -->
    <context:annotation-config/>

    <!-- Scans the classpath for annotated components that will be auto-registered as Spring beans.
     For example @Controller and @Service. Make sure to set the correct base-package -->
    <context:component-scan base-package="com.farah"/>

    <mvc:resources mapping="/resources/**" location="/resources/"/>

    <!-- Imports datasource configuration -->
    <import resource="spring-data.xml"/>  

</beans>

Note here I'm using Spring-Data-JPA, a great library from Spring that gives you a lot of features and functionality without having to write all the imperative boiler plate code again.

Data Configuration

spring-data.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <tx:annotation-driven transaction-manager="transactionManager"/>

    <context:component-scan base-package="com.farah.repository.impl"/>

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>

        </property>

        <property name="jpaProperties">
            <map>
                <entry key="hibernate.hbm2ddl.auto" value="create-drop"/>
                <entry key="hibernate.show_sql" value="true"/>
            </map>
        </property>

        <property name="packagesToScan" value="com.farah.domain"/>
    </bean> 

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/ub" />
        <property name="username" value="root" />
        <property name="password" value="" />
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>
</beans>

Here's where Spring Data JPA comes in to do some heavy lifting for you. If you extend the JpaRepository Interface you can automatically inherit a lot of CRUD functionality. To define it you simply create a repository for your domain object like the following.

Repositories

AccountRepository


/**
 * Spring Data JPA repository for the Account entity.
 */
public interface AccountRepository extends JpaRepository<Account, Long> {

}

And that will give you all the methods from the JpaRepository Interface

Next you can just build your domain object for your entity.

Domain

Account


/**
* An Account.
*/
@Entity
@Table( name = "T_ACCOUNT" )
public class Account implements Serializable {

    @Id
    @GeneratedValue( strategy = GenerationType.AUTO ) private Long id;
    @Column( name = "name" ) private String name;
    /**
     * Getters, Setters... 
     */
     ...
}

Then you can simply @Inject your repository into your service layer.

ServiceFacade

AccountService


@Transactional
@Service
public class AccountService {

    @Autowired
    private AccountRepository repository;

    public Boolean create( Account Account ) {
        ...
    }

    public Boolean update( Account Account ) {
       ...
    }

    public Boolean delete( Account Account ) {
        ...
    }
}
Community
  • 1
  • 1
Edward J Beckett
  • 5,061
  • 1
  • 41
  • 41