spring依赖注入
如果您使用该框架已经超过一个月,那么在这篇回顾性文章中可能不会发现任何有趣的东西。 除了Scala中的最后一个示例,没有其他东西希望如此。
首先是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 {@Resourceprivate Bar bar;@Resourceprivate JdbcOperations jdbcOperations;public String serverTime() {return bar.format(jdbcOperations.queryForObject("SELECT now()", Date.class));}
}
@Service
public class Bar {private FastDateFormat dateFormat;@PostConstructpublic 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);@Beanpublic DataSource dataSource() {final BasicDataSource dataSource = new BasicDataSource();dataSource.setDriverClassName("org.h2.Driver");dataSource.setUrl("jdbc:h2:mem:");dataSource.setUsername("sa");return dataSource;}@Beanpublic 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;@Autowiredpublic 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;@Autowiredpublic 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依赖注入技术的 发展
编码愉快! 不要忘记分享!
相关文章:
- Java最佳实践系列
- 正确记录应用程序的10个技巧
- 每个程序员都应该知道的事情
- 生存在荒野西部开发过程中的9条提示
- 软件设计法则
- Java Fork / Join进行并行编程
翻译自: https://www.javacodegeeks.com/2011/09/evolution-of-spring-dependency.html
spring依赖注入