Announcement Announcement Module
Collapse

JavaConfig forum decommissioned in favor of Core Container

As described at

http://static.springsource.org/sprin...fig/README.TXT

key features of the Spring JavaConfig project have been migrated into the core Spring Framework as of version 3.0.

Please see the Spring 3.0 documentation on @Configuration and @Bean support:

http://static.springsource.org/sprin...tml#beans-java

For any questions related to @Configuration classes and @Bean methods in Spring 3.0, please post in the dedicated 'Core Container' forum at

http://forum.springsource.org/forumdisplay.php?f=26
See more
See less
How to use TransactionProxyFactoryBean in JavaConfig? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • How to use TransactionProxyFactoryBean in JavaConfig?

    Thanks!

    I'm new to JavaConfig and have one question. In our development we use spring's transaction management because it's so powerful and convenient, thanks to the AOP! ^_^ Usually we'll define one base bean like this:

    <bean id="baseProxy" lazy-init="true" abstract="true" class="org.springframework.transaction.interceptor .TransactionProxyFactoryBean">
    <property name="transactionAttributes">
    <props>
    <prop key="save*">PROPAGATION_REQUIRED</prop>
    <prop key="update*">PROPAGATION_REQUIRED</prop>
    <prop key="delete*">PROPAGATION_REQUIRED</prop>

    </props>
    </property>
    </bean>

    then we can define our transactional service as :

    <bean id="fooService" parent="baseProxy">
    <property name="target">
    <bean class="example.FooServiceImpo">
    <property name="fooDao"><ref bean="fooDao"/></property>
    </bean>
    </property>
    </bean>

    now our "fooService" can use the above transaction attribute defined in its parent bean, but how to implement this configuration when we are using JavaConfig? I didn't find any hint in JavaConfig's reference document.

    Thanks again!

  • #2
    Here is a comprehensive working example using JavaConfig (uses standalone HSQL server with a simple foo table). This java configuration can be further simplified if you use annotation driven transactions (not included in this sample).

    Code:
    import org.springframework.transaction.interceptor.TransactionProxyFactoryBean;
    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.config.java.annotation.Bean;
    import org.springframework.config.java.annotation.Configuration;
    import org.springframework.config.java.context.JavaConfigApplicationContext;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.springframework.jdbc.datasource.DriverManagerDataSource;
    import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
    import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
    import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
    import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
    import org.springframework.dao.EmptyResultDataAccessException;
    import org.springframework.orm.ObjectRetrievalFailureException;
    import org.junit.Test;
    
    import javax.sql.DataSource;
    import java.util.Properties;
    import java.sql.SQLException;
    import java.sql.ResultSet;
    
    import static junit.framework.Assert.assertEquals;
    
    public class TestTransactionConfig {
    
        @Test
        public void testFooService() throws Exception {
            JavaConfigApplicationContext context = new JavaConfigApplicationContext(TransactionConfig.class);
            DefaultFooService fooService = context.getBean(DefaultFooService.class);
            Foo myFoo = new Foo();
            myFoo.setName("myFoo");
            fooService.insertFoo(myFoo);
            assertEquals("myFoo", fooService.getFoo(0).getName());
        }
    
        @Configuration
        static class TransactionConfig {
    
            @Bean
            public TransactionProxyFactoryBean baseProxy() {
                TransactionProxyFactoryBean transactionProxyFactoryBean = new TransactionProxyFactoryBean();
                Properties transactionAttributes = new Properties();
                transactionAttributes.setProperty("save", "PROPAGATION_REQUIRED");
                transactionAttributes.setProperty("update", "PROPAGATION_REQUIRED");
                transactionAttributes.setProperty("delete", "PROPAGATION_REQUIRED");
                transactionProxyFactoryBean.setTransactionAttributes(transactionAttributes);
                transactionProxyFactoryBean.setTarget(fooService());
                transactionProxyFactoryBean.setTransactionManager(transactionManager());
                return transactionProxyFactoryBean;
            }
    
            @Bean
            public DefaultFooService fooService() {
                DefaultFooService fooService = new DefaultFooService();
                fooService.setFooDao(fooDao());
                return fooService;
            }
    
            @Bean
            public DefaultFooDao fooDao() {
                DefaultFooDao fooDao = new DefaultFooDao();
                fooDao.setDataSource(dataSource());
                return fooDao;
            }
    
            @Bean
            public PlatformTransactionManager transactionManager() {
                DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
                transactionManager.setDataSource(dataSource());
                return transactionManager;
            }
    
            @Bean
            public DataSource dataSource() {
                DriverManagerDataSource dataSource = new DriverManagerDataSource();
                dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
                dataSource.setUrl("jdbc:hsqldb:hsql://localhost:9001");
                dataSource.setUsername("sa");
                dataSource.setPassword("");
                return dataSource;
            }
        }
    
        static class Foo {
            private Integer id;
            private String name;
    
            public Integer getId() {
                return id;
            }
    
            public void setId(Integer id) {
                this.id = id;
            }
    
            public String getName() {
                return name;
            }
    
            public void setName(String name) {
                this.name = name;
            }
        }
    
        public interface FooService {
    
            Foo getFoo(int id);
    
            void insertFoo(Foo foo);
    
            void updateFoo(Foo foo);
    
            void deleteFoo(int id);
        }
    
        public interface FooDao {
            void create(Foo foo);
    
            Foo read(int id);
    
            void update(Foo foo);
    
            void delete(int id);
        }
    
        static class DefaultFooDao implements FooDao {
            public DefaultFooDao() {
            }
    
            private SimpleJdbcTemplate simpleJdbcTemplate;
    
            private SimpleJdbcInsert insertFoo;
    
            private DataSource dataSource;
    
            public void setDataSource(DataSource dataSource) {
                this.dataSource = dataSource;
                this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
                this.insertFoo = new SimpleJdbcInsert(dataSource)
                        .withTableName("foo")
                        .usingGeneratedKeyColumns("id");
            }
    
            public void create(Foo foo) {
                Number newKey = this.insertFoo.executeAndReturnKey(
                        createFooParameterSource(foo));
                foo.setId(newKey.intValue());
            }
    
            public Foo read(int id) {
                Foo foo;
                try {
                    foo = this.simpleJdbcTemplate.queryForObject(
                            "SELECT id, name FROM foo WHERE id=?",
                            new JdbcPetRowMapper(),
                            id);
                }
                catch (EmptyResultDataAccessException ex) {
                    throw new ObjectRetrievalFailureException(Foo.class, id);
                }
                return foo;
            }
    
            public void update(Foo foo) {
                throw new UnsupportedOperationException();
            }
    
            public void delete(int id) {
                throw new UnsupportedOperationException();
            }
    
            private MapSqlParameterSource createFooParameterSource(Foo foo) {
                return new MapSqlParameterSource()
                        .addValue("id", foo.getId())
                        .addValue("name", foo.getName());
            }
    
            private class JdbcPetRowMapper implements ParameterizedRowMapper<Foo> {
    
                public Foo mapRow(ResultSet rs, int rownum) throws SQLException {
                    Foo foo = new Foo();
                    foo.setId(rs.getInt("id"));
                    foo.setName(rs.getString("name"));
                    return foo;
                }
            }
    
        }
    
        static class DefaultFooService implements FooService {
    
            public DefaultFooService() {
            }
    
            private FooDao fooDao;
    
            public void setFooDao(FooDao fooDao) {
                this.fooDao = fooDao;
            }
    
            public Foo getFoo(int id) {
                return fooDao.read(id);
            }
    
            public void insertFoo(Foo foo) {
                fooDao.create(foo);
            }
    
            public void updateFoo(Foo foo) {
                fooDao.update(foo);
            }
    
            public void deleteFoo(int id) {
                fooDao.delete(id);
            }
        }
    }

    Hope this helps.

    -Arul
    Last edited by aruld; Oct 11th, 2008, 08:32 PM. Reason: fixed a typo

    Comment


    • #3
      Thanks very much, I got it.
      But I think this approach confused me a little.When I use an XML configuration, I can understand it clearly that the fooService was returned from the ProxyFactoryBean and also I know it was aspected with one interceptor.

      Further I think if the code was refactored like this it would be easier to understand (based on XML)

      Code:
         @Bean
          public TransactionProxyFactoryBean baseProxy() { }
      
         @Bean
          public FooService fooService() {
                  DefaultFooService fooService = new DefaultFooService();
                  baseProxy().setTarget(fooService);
                  return fooService;
           }
      then if I need another barService, it can be
      Code:
         @Bean
          public BarService barService() {
                  DefaultBarService barService = new DefaultBarService ();
                   baseProxy().setTarget(barService);
                  return barService;
           }
      but it failed! Do I need config another TransactionProxyFactoryBean again? I found that Spring will actually create one bean named "baseProxy", but I want it to be abstract( like "abstract=true" in the XML ), then it can be reused by barService .....

      another problem , I printed the fooService returned by the SpringContext and found it's not been proxied(I removed DAO and datasource, just return one empty fooService ), then I commented the configuration for baseProxy, it printed the same result, seems that the configuration for baseProxy is useless.I know if I do configuration in XML, the fooService will be a reference to one object returned by ProxyFactoryBean.getObject() (though it's done when spring initialize the IOC context), but I can't see that from the above code.

      Anyway I got some idea, thanks again.
      Last edited by javeer; Oct 12th, 2008, 11:14 AM.

      Comment


      • #4
        I am not sure how the bean inheritance is supported in JavaConfig. May be someone in this forum can chime in. I prefer to use Spring 2+ Transaction configuration as they are less verbose and recommended style and easier to configure using JavaConfig.

        -Arul

        Comment

        Working...
        X