`
zzc1684
  • 浏览: 1191148 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

Spring4新特性——Groovy Bean定义DSL

阅读更多

Spring4支持使用Groovy DSL来进行Bean定义配置,其类似于XML,不过因为是Groovy DSL,可以实现任何复杂的语法配置,但是对于配置,我们需要那么复杂吗?本着学习的态度试用了下其Groovy DSL定义Bean,其主要缺点:

1、DSL语法规则不足,需要其后续维护;

2、编辑器的代码补全需要跟进,否则没有代码补全,写这个很痛苦;

3、出错提示不友好,排错难;

4、当前对于一些配置还是需要XML的支持,所以还不是100%的纯Groovy DSL;

5、目前对整个Spring生态支持还是不够的,比如Web,需要观望。

 

其优点就是其本质是Groovy脚本,所以可以做非常复杂的配置,如果以上问题能够解决,其也是一个不错的选择。在Groovy中的话使用这种配置 感觉不会有什么问题,但是在纯Java开发环境下也是有它,给我的感觉是这个功能其目的是去推广它的groovy。比较怀疑它的动机。

 

接下来我们来看看Spring配置的发展:

Spring 2时代是XML风格配置  可以参考《跟我学Spring3》的前几章

Spring 3时代引入注解风格配置  可以参考《跟我学Spring3》的第12章 

Spring 4时代引入Groovy DSL风格来配置 后续讲解

 

一、对比

对于我来说,没有哪个好/坏,只有适用不适用;开发方便不方便。接下来我们来看一下各种类型的配置吧:

XML风格配置

Java代码  收藏代码
  1. <context:component-scan base-package="com.sishuok.spring4"/>  
  2. <bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor">  
  3.     <property name="validator" ref="validator"/>  
  4. </bean>  
  5. <mvc:annotation-driven validator="validator"/>  
  6.   
  7. <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">  
  8.     <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>  
  9.     <property name="validationMessageSource" ref="messageSource"/>  
  10. </bean>  

 

注解风格配置 

Java代码  收藏代码
  1. @Configuration  
  2. @EnableWebMvc  
  3. @ComponentScan(basePackages = "com.sishuok.spring4")  
  4. public class MvcConfiguration extends WebMvcConfigurationSupport {  
  5.     @Override  
  6.     protected Validator getValidator() {  
  7.         LocalValidatorFactoryBean localValidatorFactoryBean =  
  8.                 new LocalValidatorFactoryBean();  
  9.         localValidatorFactoryBean.setProviderClass(HibernateValidator.class);  
  10.         localValidatorFactoryBean.setValidationMessageSource(messageSource());  
  11.         return localValidatorFactoryBean;  
  12.     }  
  13. }  

 

Groovy DSL风格配置

Java代码  收藏代码
  1. import org.hibernate.validator.HibernateValidator  
  2. import org.springframework.context.support.ReloadableResourceBundleMessageSource  
  3. import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean  
  4.   
  5. beans {  
  6.     xmlns context: "http://www.springframework.org/schema/context"  
  7.     xmlns mvc: "http://www.springframework.org/schema/mvc"  
  8.   
  9.     context.'component-scan'('base-package'"com,sishuok.spring4")  
  10.     mvc.'annotation-driven'('validator'"validator")  
  11.   
  12.     validator(LocalValidatorFactoryBean) {  
  13.         providerClass = HibernateValidator.class  
  14.         validationMessageSource = ref("messageSource")  
  15.     }  
  16. }  

因为Spring4 webmvc没有提供用于Web环境的Groovy DSL实现的WebApplicationContext,所以为了在web环境使用,单独写了一个WebGenricGroovyApplicationContext,可以到源码中查找。

 

 

可以看到,它们之前差别不是特别大;以上只提取了部分配置,完整的配置可以参考我的github:spring4-showcase

 

对于注解风格的配置,如果在Servlet3容器中使用的话,可以借助WebApplicationInitializer实现无配置:

Java代码  收藏代码
  1. public class AppInitializer implements WebApplicationInitializer {  
  2.   
  3.     @Override  
  4.     public void onStartup(javax.servlet.ServletContext sc) throws ServletException {  
  5.   
  6. //        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();  
  7. //        rootContext.register(AppConfig.class);  
  8. //        sc.addListener(new ContextLoaderListener(rootContext));  
  9.   
  10.         //2、springmvc上下文  
  11.         AnnotationConfigWebApplicationContext springMvcContext = new AnnotationConfigWebApplicationContext();  
  12.         springMvcContext.register(MvcConfiguration.class);  
  13.   
  14.         //3、DispatcherServlet  
  15.         DispatcherServlet dispatcherServlet = new DispatcherServlet(springMvcContext);  
  16.         ServletRegistration.Dynamic dynamic = sc.addServlet("dispatcherServlet", dispatcherServlet);  
  17.         dynamic.setLoadOnStartup(1);  
  18.         dynamic.addMapping("/");  
  19.   
  20.         //4、CharacterEncodingFilter  
  21.         FilterRegistration filterRegistration =  
  22.                 sc.addFilter("characterEncodingFilter", CharacterEncodingFilter.class);  
  23.         filterRegistration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false"/*");  
  24.   
  25.   
  26.     }  
  27. }  

 

到底好还是不好,需要根据自己项目大小等一些因素来衡量。对于Servlet3可以参考我github的示例:servlet3-showcase  

 

对于Groovy风格配置,如果语法足够丰富、Spring内部支持完善,且编辑器支持也非常好的话,也是不错的选择。

 

 

二、Groovy Bean定义

接下来我们来看下groovy DSL的具体使用吧:

1、安装环境

Java代码  收藏代码
  1. <dependency>  
  2.     <groupId>org.codehaus.groovy</groupId>  
  3.     <artifactId>groovy-all</artifactId>  
  4.     <version>${groovy.version}</version>  
  5. </dependency>  

我使用的groovy版本是2.2.1

 

2、相关组件类

此处使用Spring Framework官网的hello world,可以前往http://projects.spring.io/spring-framework/ 主页查看 

 

3、Groovy Bean定义配置文件

Java代码  收藏代码
  1. import com.sishuok.spring4.xml.MessageServiceImpl  
  2. import com.sishuok.spring4.xml.MessagePrinter  
  3.   
  4. beans {  
  5.     messageService(MessageServiceImpl) {//名字(类型)   
  6.         message = "hello"  //注入的属性  
  7.     }  
  8.   
  9.     messagePrinter(MessagePrinter, messageService) //名字(类型,构造器参数列表)  
  10.   
  11. }  

从此处可以看到 如果仅仅是简单的Bean定义,确实比XML简洁。

 

 

4、测试

如果不测试环境可以这样测试:

Java代码  收藏代码
  1. public class XmlGroovyBeanDefinitionTest1 {  
  2.     @Test  
  3.     public void test() {  
  4.         ApplicationContext ctx = new GenericGroovyApplicationContext("classpath:spring-config-xml.groovy");  
  5.         MessagePrinter messagePrinter = (MessagePrinter) ctx.getBean("messagePrinter");  
  6.         messagePrinter.printMessage();  
  7.     }  
  8. }  

使用GenericGroovyApplicationContext加载groovy配置文件。 

 

 

如果想集成到Spring Test中,可以这样:

Java代码  收藏代码
  1. @RunWith(SpringJUnit4ClassRunner.class)  
  2. @ContextConfiguration(locations = "classpath:spring-config-xml.groovy", loader = GenericGroovyContextLoader.class)  
  3. public class XmlGroovyBeanDefinitionTest2 {  
  4.   
  5.     @Autowired  
  6.     private MessagePrinter messagePrinter;  
  7.   
  8.     @Test  
  9.     public void test() {  
  10.         messagePrinter.printMessage();  
  11.     }  
  12. }  

此处需要定义我们自己的bean loader,即从groovy配置文件加载:

Java代码  收藏代码
  1. public class GenericGroovyContextLoader extends AbstractGenericContextLoader {  
  2.   
  3.     @Override  
  4.     protected String getResourceSuffix() {  
  5.         throw new UnsupportedOperationException(  
  6.                 "GenericGroovyContextLoader does not support the getResourceSuffix() method");  
  7.     }  
  8.     @Override  
  9.     protected BeanDefinitionReader createBeanDefinitionReader(GenericApplicationContext context) {  
  10.         return new GroovyBeanDefinitionReader(context);  
  11.     }  
  12. }  

使用GroovyBeanDefinitionReader来加载groovy配置文件。  

 

到此基本的使用就结束了,还算是比较简洁,但是我们已经注意到了,在纯Java环境做测试还是比较麻烦的。 比如没有给我们写好相关的测试支撑类。另外大家可以前往Spring的github看看在groovy中的单元测试:GroovyBeanDefinitionReaderTests.groovy

 

再看一下我们使用注解方式呢:

Java代码  收藏代码
  1. @Component  
  2. public class MessageServiceImpl implements MessageService {  
  3.     @Autowired  
  4.     @Qualifier("message")  
  5.     private String message;  
  6.     ……  
  7. }  

 

Java代码  收藏代码
  1. @Component  
  2. public class MessagePrinter {  
  3.     private MessageService messageService;  
  4.     @Autowired  
  5.     public MessagePrinter(MessageService messageService) {  
  6.         this.messageService = messageService;  
  7.     }  
  8. ……  
  9. }  

 

此处省略无关代码,需要的话直接去github查看 。点击前往 

 

Groovy配置文件:

 

Java代码  收藏代码
  1. beans {  
  2.     xmlns context: "http://www.springframework.org/schema/context"    //导入命名空间  
  3.   
  4.     context.'component-scan'('base-package'"com.sishuok.spring4") {  
  5.         'exclude-filter'('type'"aspectj"'expression'"com.sishuok.spring4.xml.*")  
  6.     }  
  7.   
  8.     message(String, "hello") {}  
  9.   
  10. }  

在该配置文件中支持导入xml命名空间, 其中context.'component-scan'部分等价于XML中的:

Java代码  收藏代码
  1. <context:component-scan base-package="com.sishuok.spring4">  
  2.     <context:exclude-filter type="aspectj" expression="com.sishuok.spring4.xml.*"/>  
  3. </context:component-scan>              
 从这里可以看出,其还没能完全从XML风格配置中走出来,不是纯Groovy DSL。

 

 

测试方式和之前的一样就不重复了,可以查看XmlGroovyBeanDefinitionTest2.java

 

三、Groovy Bean定义 DSL语法

到目前为止,基本的helloworld就搞定了;接下来看看Groovy DSL都支持哪些配置吧:

创建Bean

 

构造器

Java代码  收藏代码
  1. validator(LocalValidatorFactoryBean) { //名字(类型)  
  2.     providerClass = HibernateValidator.class  //属性=值  
  3.     validationMessageSource = ref("messageSource"//属性 = 引用,当然也支持如 validationMessageSource=messageSource 但是这种方式缺点是messageSource必须在validator之前声明  
  4. }   

静态工厂方法

Java代码  收藏代码
  1. def bean = factory(StaticFactory) {  
  2.     prop = 1  
  3. }  
  4. bean.factoryMethod = "getInstance"  
或者
Java代码  收藏代码
  1. bean(StaticFactory) { bean ->  
  2.     bean.factoryMethod = "getInstance"  
  3.     prop = 1  
  4. }  
 
实例工厂方法
Java代码  收藏代码
  1. beanFactory(Factory)  
  2. bean(beanFactory : "newInstance""args") {  
  3.     prop = 1  
  4. }  
或者
Java代码  收藏代码
  1. beanFactory(Factory)  
  2. bean("bean"){bean ->  
  3.     bean.factoryBean="beanFactory"  
  4.     bean.factoryMethod="newInstance"  
  5.     prop = 1  
  6. }  

 

依赖注入

 

属性注入

Java代码  收藏代码
  1. beanName(BeanClass) { //名字(类型)  
  2.     str = "123" // 常量直接注入  
  3.     bean = ref("bean"//属性 = 引用 ref("bean", true) 这样的话是引用父容器的  
  4.     beans = [bean1, bean2] //数组/集合  
  5.     props = [key1:"value1", key2:"value2"// Properties / Map  
  6. }  

 

构造器注入 

Java代码  收藏代码
  1. bean(Bean, "args1""args2")   

 

静态工厂注入/实例工厂注入,请参考创建bean部分

 

 

匿名内部Bean

Java代码  收藏代码
  1. outer(OuterBean) {  
  2.    prop = 1  
  3.    inner =  { InnerBean bean ->  //匿名内部Bean  
  4.                           prop =2  
  5.             }  
  6. }  
Java代码  收藏代码
  1. outer(OuterBean) {  
  2.    prop = 1  
  3.    inner =  { bean ->  //匿名内部Bean 通过实例工厂方法创建  
  4.                           bean.factoryBean = "innerBean"  
  5.                           bean.factoryMethod = "create"  
  6.                           prop = 2  
  7.             }  
  8. }  

单例/非单例/作用域

Java代码  收藏代码
  1. singletonBean(Bean1) { bean ->  
  2.     bean.singleton = true  
  3. }  
  4. nonSingletonBean(Bean1) { bean ->  
  5.     bean.singleton = false  
  6. }  
  7. prototypeBean(Bean1) { bean ->  
  8.     bean.scope = "prototype"  
  9. }  

 

其中bean可以理解为xml中的<bean> 标签,即bean定义。

 

 

父子Bean

Java代码  收藏代码
  1. parent(Bean1){ bean ->   
  2.     bean.'abstract' = true //抽象的  
  3.     prop = 123  
  4. }  
  5. child { bean ->  
  6.     bean.parent = parent //指定父bean  
  7. }  
 

 

命名空间

Java代码  收藏代码
  1. xmlns aop:"http://www.springframework.org/schema/aop"  
  2. myAspect(MyAspect)  
  3. aop {  
  4.     config("proxy-target-class":true) {  
  5.         aspect( id:"test",ref:"myAspect" ) {  
  6.             before method:"before", pointcut: "execution(void com.sishuok.spring4..*.*(..))"  
  7.         }  
  8.     }  
  9. }  
以上是AOP的,可以自己推到其他相关的配置; 

 

Java代码  收藏代码
  1. xmlns context: "http://www.springframework.org/schema/context"     
  2. context.'component-scan'('base-package'"com.sishuok.spring4") {  
  3.     'exclude-filter'('type'"aspectj"'expression'"com.sishuok.spring4.xml.*")  
  4. }  
以上是component-scan,之前介绍过了。

  

Java代码  收藏代码
  1. xmlns aop:"http://www.springframework.org/schema/aop"  
  2. scopedList(ArrayList) { bean ->  
  3.     bean.scope = "haha"  
  4.     aop.'scoped-proxy'()    
  5. }  
 等价于
Java代码  收藏代码
  1. <bean id="scopedList" class="java.util.ArrayList" scope="haha">  
  2.     <aop:scoped-proxy/>  
  3. </bean>  

 

Java代码  收藏代码
  1. xmlns util:"http://www.springframework.org/schema/util"  
  2. util.list(id : 'list') {  
  3.     value 1  
  4.     value 2  
  5. }  
等价于XML:
Java代码  收藏代码
  1. <util:list id="list">  
  2.     <value>1</value>  
  3.     <value>2</value>  
  4. </util:list>  

 

Java代码  收藏代码
  1. xmlns util:"http://www.springframework.org/schema/util"  
  2. util.map(id : 'map') {  
  3.     entry(key : 1, value :1)  
  4.     entry('key-ref' : "messageService"'value-ref' : "messageService")  
  5. }  
 等价于
Java代码  收藏代码
  1. <util:map id="map">  
  2.     <entry key="1" value="1"/>  
  3.     <entry key-ref="messageService" value-ref="messageService"/>  
  4. </util:map>  

引入其他配置文件

Java代码  收藏代码
  1. importBeans "classpath:org/springframework/context/groovy/test.xml"  

当然也能引入XML的。 

 

对于DSL新的更新大家可以关注:GroovyBeanDefinitionReaderTests.groovy,本文也是根据其编写的。

 

再来看看groovy bean定义的另一个好处:

我们可以直接在groovy bean定义文件中声明类,然后使用

Java代码  收藏代码
  1. @Controller  
  2. def class GroovyController {  
  3.     @RequestMapping("/groovy")  
  4.     @ResponseBody  
  5.     public String hello() {  
  6.         return "hello";  
  7.     }  
  8. }  
  9.   
  10. beans {  
  11.   
  12.     groovyController(GroovyController)  
  13.   
  14. }  

 

 另一种Spring很早就支持的方式是引入外部groovy文件,如:

Java代码  收藏代码
  1. xmlns lang: "http://www.springframework.org/schema/lang"  
  2. lang.'groovy'(id: 'groovyController2''script-source''classpath:com/sishuok/spring4/controller/GroovyController2.groovy')  

使用其lang命名空间引入外部脚本文件。

 

 

到此,Groovy Bean定义DSL就介绍完了,其没有什么特别之处,只是换了种写法而已,我认为目前试试即可,还不能用到真实环境。

 

 

示例代码:

https://github.com/zhangkaitao/spring4-showcase

https://github.com/zhangkaitao/servlet3-showcase

 

 

分享到:
评论

相关推荐

    workshop-spring-4.0-to-4.2:Spring 4新功能研讨会

    从Spring Framework 4.0开始,可以使用Groovy DSL定义外部bean配置。 这在概念上与使用XML bean定义相似,但是允许使用更简洁的语法。 使用Groovy还使您可以轻松地将bean定义直接嵌入到引导代码中。 类固醇上的XML...

    spring4.0 Generic Qualifier(泛型限定).docx

    Spring 4.0已经发布RELEASE版本,不仅支持Java8,而且向下兼容到JavaSE6/JavaEE6,并移出了相关废弃类,新添加如Java8的支持、Groovy式Bean定义DSL、对核心容器进行增强、对Web框架的增强、Websocket模块的实现、...

    spring-boot-reference.pdf

    4. Working with Spring Boot 5. Learning about Spring Boot Features 6. Moving to Production 7. Advanced Topics II. Getting Started 8. Introducing Spring Boot 9. System Requirements 9.1. Servlet ...

    springboot参考指南

    使用Groovy beans DSL开发应用 iv. 57. 接下来阅读什么 9. VIII. 构建工具插件 i. 58. Spring Boot Maven插件 i. 58.1. 包含该插件 ii. 58.2. 打包可执行jar和war文件 ii. 59. Spring Boot Gradle插件 i. 59.1. ...

    spring-framework-reference-4.1.2

    3.5. Groovy Bean Definition DSL .............................................................................. 18 3.6. Core Container Improvements ........................................................

    jersey-spring-spock-test

    在Java中我们不支持多重继承,但是这个问题可以很容易地通过委派来解决,对于我们的救世主来说,就是Groovy的委派机制,(好吧,我是一个groovy粉丝和提醒者,是基于Groovy的DSL进行测试)。 添加Spock Mocks来构建...

    spring-framework-reference4.1.4

    3.5. Groovy Bean Definition DSL .............................................................................. 18 3.6. Core Container Improvements ........................................................

    Grails 中文参考手册

    1. 简介 2. 起步 2.1 下载并安装Grails 2.2 创建一个Grails...14.3 通过Beans DSL运行Spring 14.4 配置属性占位 14.5 配置属性重载 15. Grails和Hibernate 15.1 通过Hibernate注释进行映射 15.2 深入了解 16. 脚手架

    JAVA上百实例源码以及开源项目源代码

    两个例子,无状态SessionBean可会话Bean必须实现SessionBean,获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,计算利息等;在有状态SessionBean中,用累加器,以对话状态存储起来,创建EJB对象,并将...

    JAVA上百实例源码以及开源项目

    两个例子,无状态SessionBean可会话Bean必须实现SessionBean,获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,计算利息等;在有状态SessionBean中,用累加器,以对话状态存储起来,创建EJB对象,并将...

Global site tag (gtag.js) - Google Analytics