依赖注入与JSR-330的参考实现——Guice
依赖注入(控制反转的一种形式),它是Java开发主流中一个重要的编程范式(思维方式)。简单的说,使用DI技术可以让对象从别处获得依赖项,而不是由它自己来构造。使用DI有很多好处,它能降低代码之间的耦合度,让代码更易于测试、更易读。Java DI的官方标准是JSR-330,本文我们还会介绍 IoC and DI使用IoC范式编程时,程序逻辑的流程通常是由一个功能中心来控制的。而使用IoC,这个“中心控制”的设计原则会被反转过来。调用者的代码处理程序的执行顺序,而程序逻辑则被封装在接受调用的子流程中。通过一个例子来理解IoC: 在GUI应用中,GUI框架负责控制调用事件处理器,而不是应用逻辑。当用户点击了一个动作,比如“向前”,GUI框架会自动调用 对应的事件处理器,而应用逻辑可以把重点放在处理动作上。程序的控制被反转了,将控制权由应用逻辑转移到了GUI框架。 IoC也被称为
IoC有多种不同的实现,包括工厂模式、服务器定位模式,当然还有依赖注入。需要注意的是,DI并不等于IoC,DI只是IoC的一种实现方式,IoC是一种机制。 DI是IoC的一种特定形态,是指寻找依赖项的过程不在当前执行代码的直接控制之下。Java中为DI提供的容器有Guice、Spring、PicoContainer等。DI的好处有:松耦合、易测试、强内聚、可重用、更轻盈的代码。 Example下面编写代码来解释到底什么是DI,如何使用DI。我们首先编写传统的代码,然后使用工厂模式解耦,进而再使用DI来改进代码,通过这个过程,你将了解到DI的精妙之处。这些改进都基于同一个关键技术,即面向接口编程。 假设你想找到所有对Java可开发人员比较友善的好莱坞经纪人。首先,我们有了一个 public interface AgentFinder { public List<Agent> findAllAgents(); } 传统方式寻找友善经纪人为了找到经纪人,项目中有个默认的 public class HollywoodService { public static List<Agent> getFriendlyAgents() { AgentFinder finder = new SpreadsheetAgentFinder(); List<Agent> agents = finder.findAllAgents(); List<Agent> friendlyAgents = filterAgents(agents,"Java Developers"); return friendlyAgents; } //filterAgents } 这是最传统的编码方式,显然, 为了改进这个问题,通常我们会想到一个常用的设计模式——工厂模式。工厂模式可以一定程度上解耦程序,它也是IoC的一种实现方式。 工厂模式利用工厂模式(其实这里用到的是一个简单工厂)重新编写上面的代码,如下: public List<Agent> getFriendlyAgents(String agentFinderType) { AgentFinderFactory factory = AgentFinderFactory.getInstance(); AgentFinder finder = factory.getAgentFinder(agentFinderType); List<Agent> agents = finder.findAllAgents(); return filterAgents(agents,"Java Developers"); } 如你所见,这里不再有具体的实现来黏住你,而是通过注入
我们需要通过DI来达成这两个目标。 手工实现DIpublic static List<Agent> getFriendlyAgents(AgentFinder finder){ List<Agent> agents = finder.findAllAgents(); return filterAgents(agents,"Java Developers"); } 上面的代码是一个纯手工打造的DI方案, 但是,这种手工方式的DI显然存在问题,如何配置 使用GuiceJava中DI方面的标准规范是 下面我们使用Guice来解决手工方式实现DI的不足问题: 首先我们需要创建一个定义绑定关系的AgentFinderModule模块(配置类)。 public class AgentFinderModule extends AbstractModule{ @Override protected void configure() { bind(AgentFinder.class).to(WebServiceAgentFinder.class); } } 绑定关系的确立在调用Guice的 下面我们来Guice版本的HollywoodService: public class HollywoodServiceGuice { private AgentFinder finder = null; @Inject public HollywoodServiceGuice(AgentFinder finder){ this.finder = finder; } public List<Agent> getFriendlyAgents(){ List<Agent> agents = finder.findAllAgents(); return filterAgents(agents,"Java Developers"); } //... } 我们在模块中声明了绑定关系,下面我们就可以让注入器构建对象关系图了。接下来我们看看在独立Java程序和Web应用程序这两种情况下分别要如何实现: 1.构建Guice对象关系图——独立Java程序 public class HollywoodServiceClient { public static void main(String[] args) { Injector injector = Guice.createInjector(new AgentFinderModule()); HollywoodServiceGuice hollywoodServiceGuice = injector.getInstance(HollywoodServiceGuice.class); List<Agent> agents = hollywoodServiceGuice.getFriendlyAgents(); } } 2.构建Guice对象关系图——Web应用程序 把 <filter> <filter-name>guiceFilter</filter-name> <filter-class>com.google.inject.servlet.GuiceFilter</filter-class> </filter> <filter-mapping> <filter-name>guiceFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> 3.然后是标准动作,扩展 public class MyGuiceServletConfig extends GuiceServletContextListener { @Override protected Injector getInjector() { return Guice.createInjector(new ServletModule()); } } 4.最好,将其加入到 <listener> <listener-class>com.example.MyGuiceServletConfig</listener-class> </listener> 经由注入器创建 关于JSR-330和Guice的更多用法,请参考其Github页面。 References
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |