如果您使用该框架已经超过一个月,那么在这篇回顾性文章中可能不会发现任何有趣的东西。 除了Scala中的最后一个示例,没有其他希望,这种语言在Spring中意外地很好用。
首先是XML [ 全文 ]:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd ">
<bean id="foo" class="com.blogspot.nurkiewicz.Foo">
<property name="bar" ref="bar"/>
<property name="jdbcOperations" ref="jdbcTemplate"/>
</bean>
<bean id="bar" class="com.blogspot.nurkiewicz.Bar" init-method="init"/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="org.h2.Driver"/>
<property name="url" value="jdbc:h2:mem:"/>
<property name="username" value="sa"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
</beans>
这个简单的应用程序仅获取H2数据库服务器时间并以完整格式打印它:
public class Foo {
private Bar bar;
private JdbcOperations jdbcOperations;
public String serverTime() {
return bar.format(
jdbcOperations.queryForObject("SELECT now()", Date.class)
);
}
public void setBar(Bar bar) {
this.bar = bar;
}
public void setJdbcOperations(JdbcOperations jdbcOperations) {
this.jdbcOperations = jdbcOperations;
}
}
public class Bar {
private FastDateFormat dateFormat;
public void init() {
dateFormat = FastDateFormat.getDateTimeInstance(FULL, FULL);
}
public String format(Date date) {
return dateFormat.format(date);
}
}
这段代码有些令人不安。 首先,令人惊讶的是有很多XML。 与类似的EJB 2.1应用程序相比,它仍然要少一些(此代码在2006年的Spring 1.2.6上进行了微小的更改 ),但是感觉很不对。 公共设置者更加令人不安–为什么我们被迫在任何时候任何人都公开覆盖对象依赖的能力? 顺便说一下,我从来没有真正理解过为什么为什么在使用tag时Spring不允许直接将依赖项注入到私有字段中,因为这样做可能……
批注 [ 全文 ]
Java 5和Spring 2.5带来了对注释驱动的依赖注入的支持:
<context:annotation-config/>
<!-- or even: -->
<context:component-scan base-package="com.blogspot.nurkiewicz"/>
从第一行开始,您不再需要在XML中定义<property>标签,只需定义<bean>。 该框架将获取标准的@Resource注释。 将其替换为第二行,甚至根本不需要在XML中指定bean:
@Service
public class Foo {
@Resource
private Bar bar;
@Resource
private JdbcOperations jdbcOperations;
public String serverTime() {
return bar.format(
jdbcOperations.queryForObject("SELECT now()", Date.class)
);
}
}
@Service
public class Bar {
private FastDateFormat dateFormat;
@PostConstruct
public void init() {
dateFormat = FastDateFormat.getDateTimeInstance(FULL, FULL);
}
public String format(Date date) {
return dateFormat.format(date);
}
}
当然,您不会留下深刻的印象! 尼尔·诺维(Nihil Novi) 。 另外,我们仍然必须使用XML,因为我们无法控制第三方类(例如数据源和JdbcTemplate ),因此无法对其进行注释。 但是Spring 3.0引入了:
@Configuration [ 完整源代码 ]
我已经在探索@ Configuration / @ Bean支持,因此这次请重点关注如何启动应用程序上下文。 您看到对XML文件的任何引用吗? applicationContext.xml描述符完全消失了:
@ComponentScan("com.blogspot.nurkiewicz")
public class Bootstrap {
private static final Logger log = LoggerFactory.getLogger(Bootstrap.class);
@Bean
public DataSource dataSource() {
final BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:mem:");
dataSource.setUsername("sa");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource());
}
public static void main(String[] args) {
final AbstractApplicationContext applicationContext = new AnnotationConfigApplicationContext(Bootstrap.class);
final Foo foo = applicationContext.getBean(Foo.class);
log.info(foo.serverTime());
applicationContext.close();
}
}
如您所见,Spring从使用大量XML到不使用XML的框架走了很长的路。 但最令人兴奋的部分是您可以使用喜欢的任何样式,甚至可以将它们混合使用。 您可以使用旧版Spring应用程序并开始使用批注或切换到XML,因为上帝知道这里或那里的原因。
我没有提到的一种技术是构造函数注入。 它有一些很大的好处(请参阅使用构造函数进行依赖注入? ),例如将依赖关系标记为最终的并禁止创建未初始化对象的能力:
@Service
public class Foo {
private final Bar bar;
private final JdbcOperations jdbcOperations;
@Autowired
public Foo(Bar bar, JdbcOperations jdbcOperations) {
this.bar = bar;
this.jdbcOperations = jdbcOperations;
}
//...
}
我希望构造函数注入,但是再次感到有点失望。 每个对象依赖项都需要(a)构造函数参数,(b)最终字段和(c)构造函数中的赋值操作。 我们最后得到十行代码,这些行什么都不做。 这个健谈的代码克服了所有优点。 当然,任何对象都不应具有超过(在这里输入您的数字)的依赖关系-借助构造函数注入,您会立即看到该对象具有太多的依赖关系-但我仍然发现此代码引入了太多的仪式。
用Scala注入Spring构造函数 [ 完整源代码 ]
Scala的一个功能完全适合Spring框架:默认情况下,任何Scala对象的每个参数都会创建与该参数相同的最终字段。 对我们而言,这意味着什么? 看看翻译成Scala的Foo类:
@Service
class Foo @Autowired() (bar: Bar, jdbcOperations: JdbcOperations) {
def serverTime() = bar.format(jdbcOperations.queryForObject("SELECT now()", classOf[Date]))
}
认真吗 但是……怎么了? 在这里深入了解Scala的优势之前,请看一下Java反编译器生成的等效Java代码:
@Service
public class Foo implements ScalaObject
{
private final Bar bar;
private final JdbcOperations jdbcOperations;
@Autowired
public Foo(Bar bar, JdbcOperations jdbcOperations)
{
this.bar = bar;
this.jdbcOperations = jdbcOperations;
}
public String serverTime()
{
return this.bar.format(this.jdbcOperations.queryForObject("SELECT now()", Date.class));
}
}
与我们用Java编写的代码几乎完全相同。 拥有所有优势:依赖最终将使我们的服务真正不变和无状态; 依赖是私有的,不会暴露给外界; 实际上,不需要额外的代码来管理依赖项:只需添加构造函数参数,Scala就会处理其余的工作。
总结一下–您拥有广泛的可能性。 从XML到Java代码再到Scala。 最后一种方法实际上很诱人,因为它使您摆脱了所有样板,并使您可以专注于业务功能。 完整的源代码可在我的GitHub存储库中找到,每个步骤都带有标签,因此您可以比较和选择最喜欢的方法。
参考资料: NoBlogDefFound的JCG合作伙伴Tomek Nurkiewicz提供的Spring依赖注入技术的 发展
编码愉快! 不要忘记分享!
相关文章:
翻译自: https://www.javacodegeeks.com/2011/09/evolution-of-spring-dependency.html