Spring 3.1 M2: 配置增强

工程 | Chris Beams | 2011 年 6 月 10 日 | ...

正如 Juergen 在他昨天的文章中提到的,以及我在关于 3.1 M1 的我的之前文章中提到的,Spring 3.1 的主要主题之一是完成我们在 Spring 中基于代码配置的愿景。我们认为现代企业级 Java 应用应该可以选择将 Java 和 XML 作为其配置的第一类选项。在本文中,我们将看到 Spring 3.1 M2 如何帮助实现这一目标。

请注意,尽管基于 Java 的配置自 Spring 3.0 起就已可用,但在此版本中,它已与多年来开发的许多基于 XML 的功能相媲美。我们认为结果非常有吸引力,并且在某些情况下甚至比基于 XML 的配置具有明显的优势。简而言之:如果您在 3.0 中没有考虑过它,那么这次您真的应该仔细研究一下。

Spring XML 命名空间的等效代码实现

如果您一直在密切关注,您会记得我们在 3.1 M1 中引入了 FeatureSpecification 类和 @Feature 方法的概念。事实证明,在 3.1 M2 中,我们决定用另一种机制取代它。为什么?因为虽然 FeatureSpecification 类为配置 Spring 容器的功能(如注解驱动的事务管理和组件扫描)提供了一种便捷机制,但这种便捷性也带来了两个缺点:缺乏可扩展性和缺乏实现透明性。我们越深入思考,就越意识到我们可以做得更好。虽然 FeatureSpecification 类通过流式 API 紧密地反映了 XML 命名空间,但新的解决方案采用了不同的形式——一种专门设计用于利用 Java 自身优势的形式。

简单来说,我们将新机制称为 "@Enable" 注解。这些注解应用于 @Configuration 类上的类型级别。我们以 @EnableTransactionManagement 为例。大多数用户会熟悉以下 Spring XML 片段:


<beans>
  <tx:annotation-driven/>
</beans>

这当然是使用 @Transactional 注解启用 Spring 对事务管理的支持。现在让我们看看等效的代码配置:


@Configuration
@EnableTransactionManagement
public class AppConfig {
     // ...
}

很简单,是吧?当然还有很多要说的,我鼓励大家看看我们在此版本中提供的 @Enable 注解的 Javadoc。您会发现它们包含大量背景信息、示例以及对重要相关类型的引用。这应该足以让您入门。当然,我们也会在 3.1 GA 发布前更新参考文档,但出于 M2 版本,我们跳过了这一步,仅仅是因为 Javadoc 已经投入了大量精力。

也请看看 @Configuration 的 Javadoc,它在 M2 版本中进行了大量修订,以展示与新 Environment 抽象等其他注解和机制的主要集成。

关于 @EnableWebMvc 注解,这是一个很好的例子,说明基于 Java 的配置相比 XML 命名空间替代方案具有真正的优势。Rossen 将在本系列的后续文章中详细介绍这个主题,敬请期待。


Hibernate SessionFactory 构建器 API

Spring 对 Hibernate 的支持一直是框架中更受欢迎的功能之一,并且一直是通过 XML 进行配置的。在 M2 版本中,我们引入了 SessionFactoryBuilderAnnotationSessionFactoryBuilder API,使得基于代码配置 Hibernate SessionFactory 变得轻而易举。请看示例:


@Configuration
public class DataConfig {
     @Bean
     public SessionFactory sessionFactory() {
         return new AnnotationSessionFactoryBuilder()
             .setDataSource(dataSource())
             .setPackagesToScan("com.myco")
             .buildSessionFactory();
     }
}

更多示例和具体细节请参阅 Javadoc


无需 XML 的 JPA 配置

使用 JPA 的 Spring 用户会熟悉我们的 LocalContainerEntityManagerFactoryBean。我们添加了一个名为 'packagesToScan' 的属性,您可以使用它完全放弃 persistence.xml 文件!顺便说一下,这与 Spring Hibernate AnnotationSessionFactoryBean 上同名属性非常相似。这里有一个示例:


@Configuration
public class DataConfig {
     @Bean
     public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
         LocalContainerEntityManagerFactoryBean emf =
             new LocalContainerEntityManagerFactoryBean();
         emf.setDataSource(dataSource())
         emf.setPackagesToScan("com.myco")
         return emf;   
     }
}

抛弃 web.xml

Servlet 3.0 引入了一些非常有趣的新特性,用于基于代码配置 Servlet 容器。本质上,ServletContext API 已得到增强,允许用户以基于类或基于实例的方式注册 Servlet、Filter 和 Listener。请看:

这意味着现在可以通过编程方式注册面向 Servlet 的组件,如 Spring 的 DispatcherServletContextLoaderListener,而不是通过 web.xml 以声明方式进行。

唯一缺少的是一个引导机制——一个在 Servlet 容器生命周期的良好定义点执行这些注册的地方。幸运的是,Servlet 3.0 通过 ServletContainerInitializer 也解决了这个问题。

ServletContainerInitializer 是一个低级 SPI,主要面向 Spring 等框架使用。详细信息我会在 Javadoc 中说明(链接如下),但简而言之,Spring 3.1 M2 现在提供了一个非常方便的 WebApplicationInitializer 接口,它可以与 ServletContainerInitializer SPI 协同工作,允许您以编程方式引导 Servlet 容器。这里有一个快速示例:


public class MyWebAppInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext container) {
      XmlWebApplicationContext appContext = new XmlWebApplicationContext()
      appContext.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");

      ServletRegistration.Dynamic dispatcher =
        container.addServlet("dispatcher", new DispatcherServlet(appContext));
      dispatcher.setLoadOnStartup(1);
      dispatcher.addMapping("/");
    }

}

如您所见,DispatcherServlet 现在支持接受 WebApplicationContext 的构造函数。这是 Javadoc:

虽然我们在上面使用了 XmlWebApplicationContext,但您当然可以选择使用 AnnotationConfigWebApplicationContext,并通过 @Configuration 类完全进行引导。

spring-web 模块 JAR 存在于您的类路径中时,您的 WebApplicationInitializer 实现将与 ServletContainerInitializer 机制结合,被 Spring 自动检测和处理。这意味着您可以按照您认为合适的方式在应用程序中打包它们(再见,WEB-INF!)我们已在 Glassfish 3.1 和 Tomcat 7.0.15 上成功测试了这一切,所以现在是您开始熟悉 Spring 3.1 和 Servlet 3.0 的绝佳时机。

完整的用法说明,请查看 WebApplicationInitializer 本身的 Javadoc:

对于从 web.xml 迁移到 WebApplicationInitializer 的完整(且简洁)示例,请查看 Spring 的 Greenhouse 参考应用 'servlet3' 分支中的这个提交:


改进的外部化值支持

M1 引入了 Environment 抽象和一个统一的 PropertySource API。在 M2 中,我们的目标是使这些组件的配置和使用尽可能简单。新的 @PropertySource 注解允许您从 @Configuration 类中向 Environment 贡献属性源:


 @Configuration
 @PropertySource("classpath:/com/myco/app.properties")
 public class AppConfig {
     @Autowired
     Environment env;

     @Bean
     public TestBean testBean() {
         TestBean testBean = new TestBean();
         testBean.setName(env.getProperty("testbean.name"));
         return testBean;
     }
 }

这与传统的 PropertyPlaceholderConfigurer (<context:property-placeholder>) 方法不同。在这里,我们将一个属性源贡献给 Environment,将 Environment 注入到我们的 @Configuration 类中,然后使用 Environment 的 #getProperty 方法系列查找所需的属性。有关完整详细信息,请查看 @PropertySourceEnvironment 的 Javadoc。


总结

如您所见,我们确实有一个重要的主题正在进行。从 Spring XML 命名空间和 FactoryBeans 的基于 Java 的替代方案,到甚至消除了 web.xml 和 persistence.xml 等非 Spring XML,我们现在可以自豪地说,Spring 的基于代码的配置在整个框架中都是一流的。唯一剩下的是您的反馈!

正如 Juergen 所提到的,如果您还没有开始尝试 3.1,现在正是时候。我们现在正进入候选发布阶段,这是根据您的实际使用情况进行改进的绝佳时机。请告诉我们您的体验如何!

哦,还有一件事……如果您还没有注意到,Spring 现在已入驻 Twitter!关注 @springframework 以随时了解发布信息,并从框架本身获取对 Spring 的深入见解。希望在 Twitter 上见到您,感谢阅读!

获取 Spring 通讯

通过 Spring 通讯保持联系

订阅

先行一步

VMware 提供培训和认证,助您快速提升。

了解更多

获取支持

Tanzu Spring 通过一份简单的订阅提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举办的活动

查看 Spring 社区所有即将举办的活动。

查看全部