领先一步
VMware 提供培训和认证,助您加速进步。
了解更多正如 Juergen 在昨天发布的帖子中提到的,以及我在关于 3.1 M1 的我的先前帖子中提到的,Spring 3.1 的主要主题之一是实现我们对 Spring 中基于代码的配置的愿景。我们认为,现代企业 Java 应用程序应该在 Java 和 XML 之间拥有两种同等重要的配置选项。在这篇文章中,我们将看到 Spring 3.1 M2 如何帮助实现这一目标。
请注意,尽管自 Spring 3.0 起就提供了基于 Java 的配置,但在本次发布中,它在许多方面已与多年来开发的许多基于 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>
这当然启用了 Spring 对使用 @Transactional 注解的事务管理的支持。现在让我们看看代码中的等效配置
@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。看看吧
这意味着现在可以通过编程方式而不是通过 web.xml 声明式地注册面向 Servlet 的组件,例如 Spring 的 DispatcherServlet 和 ContextLoaderListener。
唯一缺少的是一个引导机制——一个在 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 实现将由 Spring 与 ServletContainerInitializer 机制结合自动检测和处理。这意味着您可以根据自己的需要将它们打包到应用程序中(再见了,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 -> WebApplicationInitializerM1 引入了 Environment 抽象和统一的 PropertySource API。在 M2 中,我们的目标是使这些组件尽可能易于配置和使用。新的 @PropertySource 注解允许您从 @Configuration 类中向环境中贡献属性源
@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>)方法不同。在这里,我们将一个属性源贡献给环境,将环境注入我们的 @Configuration 类,然后使用环境的 #getProperty 系列方法查找所需的属性。有关详细信息,请查看 @PropertySource 和 Environment 的 Javadoc。
FactoryBeans,再到消除像 web.xml 和 persistence.xml 这样的非 Spring XML,我们现在可以自豪地说,Spring 的基于代码的配置在整个框架中都是一流的。唯一剩下的就是您的反馈!正如 Juergen 所提到的,如果您还没有开始,现在是尝试 3.1 的时候了。我们现在正进入发布候选阶段,这是根据您的实际使用进行改进的理想时机。请让我们知道进展如何!
哦,还有一件事……如果您还没有注意到,Spring 现在在 Twitter 上!关注 @springframework 以获取最新版本信息,并从框架本身获得有关 Spring 的见解。希望在那里见到您,感谢您的阅读!