依赖注入
最新一代容器称为轻量级容器,它们使用一个共同设计原理:依赖注入。 对这个简单思想来说,这是一个复杂的术语。依赖注入让您将对象和它所依赖的东西交给第三方。然后第三方创建所有对象并将它们绑在一起。比方说,称为 myDao 的数据访问对象需要一个称为 ds 的数据源。那么该容器会一同创建它们,并设置一个属性:
清单 1. 创建一个第三方汇编程序
myDao = new Dao(); ds = new DataSource(); myDao.setDataSource(ds);
|
当然,不创建这种第三方汇编程序的话,您也可以使用框架来做其他附加的工作(如提供配置支持)。Spring 框架、Pico 和 HiveMind 就扮演了这个角色。其他像 JavaServer Faces(JSF) 框架也利用了依赖注入。
依赖注入
在 Java 技术中,依赖注入正迅速地改变我们构建应用程序的方式。这种概念相对简单:一个消费者(类似下面的 Consumer 类)需要一个服务。您为指向该服务(类似下面的 Speaker 类)的消费者添加一个属性。清单 1 展示了此概念的示例。
清单 1. 依赖注入的示例
class Speaker { void speak(String words) { System.out.println(words); } }
class Consumer { Speaker mySpeaker; void saySomething() { mySpeaker.speak("something"); } }
|
请注意 Consumer 类。它没有实例化 Speaker 类。有了依赖注入,该工作就由称之为 Container 类(参阅清单 2)的第三方来处理。
清单 2. Container 类
class Container { public static void main(String[] args) { Speaker speaker=new Speaker(); Consumer consumer=new Consumer(); consumer.speaker = speaker; consumer.saySomething(); } }
|
Container 类实例化了 Speaker 和 Consumer 类。然后 Container 类将 speaker 属性设置为新的 Speaker 类。最后一步表示依赖注入。
接口的强大功能
让我们稍微对该段代码进行重构。构建一个称为 Speaker 的接口和两个不同的实现:一个 Canadian speaker 和一个 Californian speaker。因此,您现在拥有了 Speaker 接口:
interface Speaker { void speak(String words); }
|
CanadianSpeaker 和 CalifornianSpeaker:
class CanadianSpeaker implements Speaker { public void speak(String words) { System.out.println(words + ", ay?"); } }
class CalifornianSpeaker implements Speaker { public void speak(String words) { System.out.println("Like, " + words); } }
|
还有容器中的单行更改:
... Speaker speaker=new CalifornianSpeaker();
|
注意,您现在可以在 speaker 的两个实现之间变化,而惟一需要改变的代码就是容器。更关键的是,您可以轻松地注入模拟对象来替代真正的 Speaker 实现,并且无需影响其他的代码基就可以进行测试。
当然,最终目标是用专门定制的容器来替代这个手写容器。例如,使用 Spring 容器。在本例中,替换的是您的 Container 类,并且您可以使用类似清单 3 中代码的简单 XML 文件。
清单 3. 用于 Spring 容器的 XML 文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="mySpeaker" class="CanadianSpeaker"> </bean>
<bean id="consumer" class="Consumer"> <property name="speaker"><ref local= "mySpeaker"/></property> </bean>
</beans> </code>
|
现在,您可以下载上下文,获取 Consumer bean,然后像下面这样运行它:
ApplicationContext ac = new FileSystemXmlApplicationContext("context.xml"); Consumer c=(HelloWorld)ac.getBean("consumer"); c.saySomething();
|
Spring 容器与您的容器完成相同的事情。它实例化 beans,并通过设置属性而将它们绑在一起。注意,两部分代码是完全去耦的;接口和容器确保了这一点。您可以使用依赖注入来满足进行企业级开发(例如,数据源或事务管理器)所遇到的许多依赖性
面向方面编程
使用面向方面编程(AOP),您可以编写通用的功能性模块(称为方面) —— 例如,日志、事务、安全或持久性。AOP 使您可以将这些方面联系到 POJO,然后指定一个时间点(如方法开始时或产生异常时)和另一个需要联系的方面。例如,您可能想要创建一个外观事务对象。您可以在调用方法时将 TransactionBegin 方面关联到外观方法。然后在产生异常时将 RollBack 方面关联到外观的异常。最后,在方法结束时将 Commit 方面关联到外观的方法。您在配置中完成这些工作,而不是通过编写代码。依靠这种能力,您可以创建一个简单的 POJO 事务、安全或远程访问。