《Spring入门经典》第1章习题答案

转载至《Spring入门经典》 纯手打

习题1
研究一下容器内测试框架的可用性。相对于容器外测试,容器内测试具有哪些明显的优点和缺点?
答案:
可用的容器内的服务器端测试框架非常少。其中一个是由JBoss.org开发的Arquillian。它能够让开发人员为在一个容器中执行的业务对象编写集成测试代码。该容器可以是Java EE应用程序服务器或者Serlvet/Web容器。可以从http://arquillian.org/找到更多关于Arquillian的信息。
另一个可用的容器内测试框架是Jersey Test Frameword。Jersey是JAX-RS规范的参考实现,而Jersey Test Framework用来对远程使用Jersey开发的REST风格的Web应用程序进行测试。可以从https://jersey.java.net/documentation/latest/test-framework.html 找到更多关于Jersey Test Framework的信息。
容器内测试的优点包括:
1. 可以在一个实际的全堆栈环境中部署应用程序并运行测试,而不是在测试设置过程中构建的模拟环境。
2. 在目标环境中编写并运行的测试能够让开发人员检查实际使用情况,而模拟测试则与实际用户体验完全无关。
容器内测试的缺点包括:
1. 比在容器之外运行测试要慢一些,因为需要花费时间将应用程序部署到目标环境中并运行。
2. 运行整个应用程序可能会消耗更多的资源,比如CPU时间和内存空间。
3. 易于偏离测试驱动编程,因为开发人员更倾向于先编写组件,然后将它们组合在一起,从而在容器中进行测试。

习题2
新的EJB编程模型使用了哪些IoC方法?
参考答案
Java EE使用CDI(Context and Dependency Injection,上下文和依赖注入)作为其依赖注入方法。通过JSR-299对其进行标准化。CDI为Java EE平台提供了类型安全和注解驱动的依赖注入功能。除了依赖注入功能之外,CDI还通过两种重要的方法增强了Java EE的编程模型。首先,它允许直接使用EJB作为JSF支持Bean。其次,允许以一种声明方式管理对象的范围、状态、生命周期和上下文。JSR 299利用了Dependency Injection for Java(JSR300)规范作为其基础API,其主要是使用了JSR 300注解,比如@Inject、@Qualifier和@ScopeType。可以从https://docs.oracle.com/javaee/6/tutorial/doc/giwhl.html 了解更多关于CDI的信息。

习题3
哪些依赖注入方法可以处理“循环依赖”,哪些不可以?
参考答案
构造函数注入不能处理循环依赖。假设定义了如下所示的Bean配置:

<bean id=“foo” class=“com.wiley.beginningspring.exercises.chl.Foo”>
    <constructor-arg ref=“bar”/>
</bean>

<bean id=“bar” class=“com.wiley.beginningspring.exercises.chl.Bar”>
    <constructor-arg ref=”foo”/>
</bean>

当创建foo Bean时,Spring容器将尝试获取bar Bean并通过Foo类的构造函数将其注入foo Bean。再尝试创建bar Bean,但此次,它尝试获取fooBean以将其注入到barBean(类似于Foo类)。而此时,无法为了注入而获取foo Bean,因为它还没有为依赖注入做好准备。其结果是,Spring抛出BeanCurrentlyInCreationException,以表明循环依赖问题。
另一方面,setter注入可以注入循环依赖。请查看一下下面所示的Bean配置:

<bean id=”foo” class=”com.wiley.beginningspring.exercises.chl.Foo”>
    <property name=”bar” ref=”bar”/>
</bean>

<bean id=”bar” class=”com.wiley.beginningspring.exercises.chl.Bar”>
    <property name=”foo” ref=”foo”/>
</bean>

Spring 首先通过调用Foo类的默认构造函数创建了foo Bean,然后尝试注入bar依赖。因此,Spring进入bar Bean定义,并开始创建bar Bean,以便执行依赖注入。此时,Spring容器通过调用Bar类的默认构造函数能够创建bar Bean,并尝试注入foo依赖。由于在第1步中已经创建了foo Bean,因此Spring容器获取foo Bean并注入到bar Bean。现在,bar Bean已经做好了进行依赖注入的准备,容器可以获取bar Bean并注入到foo Bean。
然而,许多Spring功能并不能用于循环依赖Bean,即使能够使用setter注入创建并注入依赖项,因为Spring容器所提供的许多中间件功能(比如事务、验证、缓存和安全性)都依赖BeanPostProcessors,它们是Spring自身的特殊基础Bean。当应用程序级别的Bean被创建并注入依赖项之后,这些基础Bean将对这些Bean(比如foo和bar Bean)进行后处理(postprocess),以便将这些应用程序级别的Bean做好准备作为依赖项被注入容器中其他Bean之前可以应用相关的中间件功能。在前面的示例中你可能已经注意到,当将foo Bean注入bar Bean时,为了进行后处理并没有对foo Bean进行完全初始化。因此,如果被配置为拥有此类中间件功能,那么这些功能将无法在已注入到bar Bean的foo Bean实例上使用。
所以,通常最好的做法是减少应用程序中的循环依赖,以便Bean可以受益于Spring容器所提供的中间件功能。此外,还可以使用AbstractRefreshableApplicationContext.setAllowCircularReferences(false)来禁用循环依赖解决方案,从而防止此类问题的发生。

猜你喜欢

转载自blog.csdn.net/fantasy0422/article/details/81216425
今日推荐