0

Im using Spring 3.0 and JDBC I'm currently experimenting with spring for a desktop application. Each time a class would need to use the datasource declared on my spring_bean_file.xml I would need to declare each of them in the xml file and again initialize each of them in my class.
Below is my xml file

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">       
        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
        <property name="url" value="#{T(java.lang.System).getenv(DB_URL')}"/>
        <property name="username" value="#{T(java.lang.System).getenv('DB_USER')}"/>
        <property name="password" value="#{T(java.lang.System).getenv('DB_PASS')}"/>        
    </bean>


<bean id="classA" class="com.example.ClassA">
    <property name="dataSource" ref="dataSource"/>
</bean>

<bean id="classB" class="com.example.ClassB">
    <property name="dataSource" ref="dataSource"/>
</bean>

This is my java code:

public static void main(String[] args) {        

        ApplicationContext context = new ClassPathXmlApplicationContext("spring_bean_file.xml");
            ClassA classA = (ClassA) context.getBean("classA");
            ClassB classB = (ClassB) context.getBean("classB");
            try {
                rrRpi.generateRrRpi();
                rrSpi.generateRrSpi();
            } catch (SQLException e) {

                e.printStackTrace();
            } catch (IOException e) {

                e.printStackTrace();
            }

         //close the context             
        ((ClassPathXmlApplicationContext) context).close(); 

    }

Id like to know if theres a more efficient way of doing this. Whats the best approach so I wouldnt need to add a bean for each class that would use the DataSoruce. Thanks in advance guys.

royjavelosa
  • 2,048
  • 6
  • 30
  • 46
  • 1
    What exactly is your problem? You can declare bean template using abstract="true" and use parent="myBean" to add common fields declaration to each bean. – Danubian Sailor Mar 02 '12 at 08:17
  • I dont want to initialize each beans into my class for every class that would need the dataSource e.g. ClassA classA = (ClassA) context.getBean("classA"); ClassB classB = (ClassB) context.getBean("classB"); – royjavelosa Mar 02 '12 at 08:20

1 Answers1

1

You can use:

Annotations and CLASSPATH scanning

@Service
public class ClassA {
    @Resource
    private DataSource dataSource;

    //...
}

@Service
public class ClassB {
    @Resource
    private DataSource dataSource;

    //...
}

dataSource definition is still required to be in the XML, you also need to replace classA and classB <bean/> definitions with simple:

<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"
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">

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

    <!-- ... -->
</beans

@Configuration

Or you can take advantage of very new but exciting Java configuration:

@Configuration
public class Cfg {

    @Bean
    public DataSource dataSource() {
        BasicDataSource ds = new BasicDataSource();
        ds.setDriverClassName("oracle.jdbc.driver.OracleDriver);
        //...
        return ds;
    }

    @Bean
    public ClassA classA() {
        ClassA ca = new ClassA()
        ca.setDataSource(dataSource());
        return ca;
    }

    @Bean
    public ClassB classB() {
        ClassB cb = new ClassB()
        cb.setDataSource(dataSource());
        return cb;
    }

}

The benefit of this approach is that you don't need XML, at all:

new AnnotationConfigApplicationContext(Cfg.class);

See also

Community
  • 1
  • 1
Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • can i declare more than one just in case the classes are from different packages? – royjavelosa Mar 02 '12 at 08:26
  • I tried the service / resource approach but it says the prefix "context" for the element "context:component-scan" is not bound. – royjavelosa Mar 05 '12 at 06:13
  • @royjavelosa: you need to define XML schema namespaces, see my updated answer near `context:component-scan`. – Tomasz Nurkiewicz Mar 05 '12 at 07:33
  • @royjavelosa: looks fine, remeber about XML namespace declaration and to provide real package name. – Tomasz Nurkiewicz Mar 05 '12 at 08:08
  • I apologize for the code format but should I do it like this? – royjavelosa Mar 05 '12 at 08:11
  • @royjavelosa: yes you already posted the same code, it is correct, but remember about package name and XML namespace. – Tomasz Nurkiewicz Mar 05 '12 at 08:17
  • Thanks! Just one more thing if its ok. For desktop application how do I reference the .xml file I usually use the code below but since im already using the context:component approach whats the best way to reference the ApplicationContext.xml 'ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");' 'ClassA classA = (ClassA) context.getBean("classA");' I do this on the main method. – royjavelosa Mar 06 '12 at 02:59
  • 1
    @royjavelosa: `ClassPathXmlApplicationContext` is fine in desktop application. Unfortunately you have to reference the very first bean somehow. Your method is OK, but consider strongly typed version: `ClassA classA = context.getBean(ClassA.class)` (no downcasting) – Tomasz Nurkiewicz Mar 06 '12 at 07:35
  • Thanks alot! using classA = context.getBean(ClassA.class) syntax saved me from the redundancy of using context.getBean("classA") context.getBean("classB") etc. as long as I put all the related beans on a single application context. Spring is indeed very powerful and flexible. :) – royjavelosa Mar 07 '12 at 07:02