Spring 4: Groovy DSL bean definition
In Spring 2.x, script language is supported in Spring via the Java scripting engine.
In Spring 4.0, Groovy is a first class citizen in Spring. Groovy can be used as an alternative for configuring bean definition.
Groovy DSL bean definition
As a Spring developer, you could be very familiar with XML based or/and Java annotation based bean definition.
The following is an example of XML bean definition.
<jdbc:embedded-database id="dataSource" type="H2"> </jdbc:embedded-database> <bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory"> <property name="persistenceUnitName" value="persistenceUnit" /> <property name="dataSource" ref="dataSource" /> <property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"></property> <property name="packagesToScan"> <array> <value>com.hantsylabs.example.spring.model</value> </array> </property> <property name="jpaProperties"> <value> hibernate.format_sql=true hibernate.show_sql=true hibernate.hbm2ddl.auto=create </value> </property> </bean> <bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean>
The following is the equivalent bean definition using Java annotation.
@Configuration
@ComponentScan(basePackages = { "com.hantsylabs.example.spring.dao",
"com.hantsylabs.example.spring.jpa" })
@EnableTransactionManagement(mode=AdviceMode.ASPECTJ)
public class JpaConfig {
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(dataSource());
emf.setPackagesToScan("com.hantsylabs.example.spring.model");
emf.setPersistenceProvider(new HibernatePersistence());
emf.setJpaProperties(jpaProperties());
return emf;
}
private Properties jpaProperties() {
Properties extraProperties = new Properties();
extraProperties.put("hibernate.format_sql", "true");
extraProperties.put("hibernate.show_sql", "true");
extraProperties.put("hibernate.hbm2ddl.auto", "create");
return extraProperties;
}
@Bean
public PlatformTransactionManager transactionManager() {
return new JpaTransactionManager(entityManagerFactory().getObject());
}
}
The following content defines these beans in Groovy DSL way.
import org.apache.commons.dbcp.BasicDataSource
import org.springframework.orm.jpa.JpaTransactionManager
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
import com.hantsylabs.example.spring.jpa.JpaConferenceDaoImpl
beans {
dataSource(BasicDataSource) {
driverClassName = "org.h2.Driver"
url = "jdbc:h2:mem:spring4-sandbox"
username = "sa"
password = ""
}
entityManagerFactory(LocalContainerEntityManagerFactoryBean){
persistenceProviderClass="org.hibernate.ejb.HibernatePersistence"
dataSource=dataSource
persistenceUnitName="persistenceUnit"
packagesToScan=["com.hantsylabs.example.spring.model"]
jpaProperties=[
"hibernate.format_sql":"true",
"hibernate.show_sql":"true",
"hibernate.hbm2ddl.auto":"create"
]
}
transactionManager(JpaTransactionManager){
entityManagerFactory=entityManagerFactory
}
conferenceDao(JpaConferenceDaoImpl){
}
}
If you have some experience of Grails, you could have recognized this feature is similar with the Grails resources.groovy.
Add groovy as a dependency in your Maven pom.xml.
<dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> <version>2.1.8</version> </dependency>
Now you can write some test codes.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = "classpath:/com/hantsylabs/example/spring/config/JpaConfigGroovy.groovy", loader = GenericGroovyContextLoader.class)
@TransactionConfiguration
public class GroovyJpaConferenceDaoImplTest {
public static class GenericGroovyContextLoader extends
AbstractGenericContextLoader {
@Override
protected BeanDefinitionReader createBeanDefinitionReader(
GenericApplicationContext context) {
return new GroovyBeanDefinitionReader(context);
}
@Override
protected String getResourceSuffix() {
return ".groovy";
}
}
// test codes
}
I've tried to load the Groovy bean definition resource through
@ContextConfigurationannotation, but it does not work. By default, the locations and value are ready for loading XML bean definition. Spring 4.0 includes a GroovyBeanDefinitionReader for reading and parsing Groovy bean definition. It is easy to write a custom context loader for loading the Groovy bean definition.
The
Conference, ConferenceDao, JpaConferneceDaoImpl, and the CRUD test cases are no difference from my before posts.
In a web application, you can load the Groovy bean configuration in your bootstrap class(
WebApplicationIntializer) via a Groovy specific GenericGroovyApplicationContext.ApplicationContext ctx=new GenericGroovyApplicationContext("classpath:/com/hantsylabs/example/spring/config/JpaConfigGroovy.groovy");
Create Spring Bean in Groovy way
Create a simple
ConferenceService bean, but use Groovy, put it under src/main/groovyfolder.package com.hantsylabs.example.spring.service
import com.hantsylabs.example.spring.dao.ConferenceDao
class ConferenceService {
def conferenceDao
def findConferenceBySlug(String slug) {
conferenceDao.findBySlug(slug)
}
}
Declare it as a Spring bean in JpaConfigGroovy.groovy file.
conferenceService(ConferenceService){
conferenceDao=conferenceDao
}
Test it.
package com.hantsylabs.example.spring.dao;
//other imports are omitted
import com.hantsylabs.example.spring.service.ConferenceService;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = "classpath:/com/hantsylabs/example/spring/config/JpaConfigGroovy.groovy", loader = GenericGroovyContextLoader.class)
@TransactionConfiguration
public class GroovyConferenceServiceTest {
//all duplicated codes are omitted
@Autowired
ConferenceService conferenceService;
@Test
@Transactional
public void retrieveConference() {
//all duplicated codes are omitted
// query by slug
conference = (Conference) conferenceService.findConferenceBySlug("jud-2013");
assertTrue(conference != null);
}
}
Groovy files are put in src/main/groovy, you need to configure the java compiler to compile groovy files.
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<!-- 2.8.0-01 and later require maven-compiler-plugin 3.1 or higher -->
<version>3.1</version>
<configuration>
<compilerId>groovy-eclipse-compiler</compilerId>
<!-- set verbose to be true if you want lots of uninteresting messages -->
<!-- <verbose>true</verbose> -->
</configuration>
<dependencies>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-eclipse-compiler</artifactId>
<version>2.8.0-01</version>
</dependency>
<!-- for 2.8.0-01 and later you must have an explicit dependency on
groovy-eclipse-batch -->
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-eclipse-batch</artifactId>
<version>2.1.8-01</version>
<!-- or choose a different compiler version -->
<!-- <version>1.8.6-01</version> -->
<!-- <version>1.7.10-06</version> -->
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>src/main/groovy</source>
</sources>
</configuration>
</execution>
<execution>
<id>add-test-source</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>src/test/groovy</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
build-helper-maven-plugin plugin will add src/main/groovy as a compilation source folder, and compiler plugin with groovy-eclipse-compiler configuration will compile groovy into java classes.
If you are using Eclispe IDE or Spring ToolSuite, do not forget install Grails/Groovy plugin from Spring IO, or download a copy of Grails/Groovy Suite for groovy development.
Sample codes
The samples codes is hosted on my github.com account.
评论