先行一步
VMware 提供培训和认证,助您快速提升。
了解更多正如 Juergen 在他昨天的文章中提到的,以及我在关于 3.1 M1 的我的之前的文章中提到的,Spring 3.1 的主要主题之一是完成我们在 Spring 中基于代码配置的愿景。我们认为现代企业级 Java 应用应该可以选择将 Java 和 XML 作为其配置的第一类选项。在本文中,我们将看到 Spring 3.1 M2 如何帮助实现这一目标。
请注意,尽管基于 Java 的配置自 Spring 3.0 起就已可用,但在此版本中,它已与多年来开发的许多基于 XML 的功能相媲美。我们认为结果非常有吸引力,并且在某些情况下甚至比基于 XML 的配置具有明显的优势。简而言之:如果您在 3.0 中没有考虑过它,那么这次您真的应该仔细研究一下。
如果您一直在密切关注,您会记得我们在 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 将在本系列的后续文章中详细介绍这个主题,敬请期待。
Spring 对 Hibernate 的支持一直是框架中更受欢迎的功能之一,并且一直是通过 XML 进行配置的。在 M2 版本中,我们引入了 SessionFactoryBuilder
和 AnnotationSessionFactoryBuilder
API,使得基于代码配置 Hibernate SessionFactory
变得轻而易举。请看示例:
@Configuration
public class DataConfig {
@Bean
public SessionFactory sessionFactory() {
return new AnnotationSessionFactoryBuilder()
.setDataSource(dataSource())
.setPackagesToScan("com.myco")
.buildSessionFactory();
}
}
更多示例和具体细节请参阅 Javadoc
使用 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;
}
}
Servlet 3.0 引入了一些非常有趣的新特性,用于基于代码配置 Servlet 容器。本质上,ServletContext
API 已得到增强,允许用户以基于类或基于实例的方式注册 Servlet、Filter 和 Listener。请看:
这意味着现在可以通过编程方式注册面向 Servlet 的组件,如 Spring 的 DispatcherServlet
和 ContextLoaderListener
,而不是通过 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' 分支中的这个提交:
web.xml -> WebApplicationInitializer
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
方法系列查找所需的属性。有关完整详细信息,请查看 @PropertySource
和 Environment
的 Javadoc。
FactoryBeans
的基于 Java 的替代方案,到甚至消除了 web.xml 和 persistence.xml 等非 Spring XML,我们现在可以自豪地说,Spring 的基于代码的配置在整个框架中都是一流的。唯一剩下的是您的反馈!正如 Juergen 所提到的,如果您还没有开始尝试 3.1,现在正是时候。我们现在正进入候选发布阶段,这是根据您的实际使用情况进行改进的绝佳时机。请告诉我们您的体验如何!
哦,还有一件事……如果您还没有注意到,Spring 现在已入驻 Twitter!关注 @springframework 以随时了解发布信息,并从框架本身获取对 Spring 的深入见解。希望在 Twitter 上见到您,感谢阅读!