Spring依赖注入技术的发展

回顾Spring框架的历史,您会发现实现依赖注入的方式在每个发行版中都在增加。

如果您使用该框架已经超过一个月,那么在这篇回顾性文章中可能不会发现任何有趣的东西。 除了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存储库中找到,每个步骤都带有标签,因此您可以比较和选择最喜欢的方法。

参考资料: NoBlogDefFoundJCG合作伙伴Tomek Nurkiewicz提供的Spring依赖注入技术的 发展

编码愉快! 不要忘记分享!

相关文章:


翻译自: https://www.javacodegeeks.com/2011/09/evolution-of-spring-dependency.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值