【Free style】Java 依赖注入总结
最近在研读Hive社区版本的源码,发现其中多处用到了Java依赖注入,这里简单总结一下依赖注入的几种实现方法。在谈java依赖注入之前,有必要先回顾一下设计模式中的Proxy模式。
其实每个模式名称就表明了该模式的作用,代理模式就是多一个代理类出来,替原对象进行一些操作,比如我们在租房子的时候回去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做,此处的代理就是这个意思。再如我们有的时候打官司,我们需要请律师,因为律师在法律方面有专长,可以替我们进行操作,表达我们的想法。先来看看关系图:
根据上文的阐述,代理模式就比较容易的理解了,我们看下代码:
public interface Sourceable { public void method(); }
public class Source implements Sourceable { @Override public void method() { System.out.println("the original method!"); } }
public class Proxy implements Sourceable { private Source source; public Proxy(){ super(); this.source = new Source(); } @Override public void method() { before(); source.method(); atfer(); } private void atfer() { System.out.println("after proxy!"); } private void before() { System.out.println("before proxy!"); } }
测试类
public class ProxyTest { public static void main(String[] args) { Sourceable source = new Proxy(); source.method(); } }
输出:
before proxy!
the original method!
after proxy!
代理模式的应用场景:
如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法:
1、修改原有的方法来适应。这样违反了“对扩展开放,对修改关闭”的原则。
2、就是采用一个代理类调用原有的方法,且对产生的结果进行控制。这种方法就是代理模式。
使用代理模式,可以将功能划分的更加清晰,有助于后期维护!
下面我们要说的Java依赖注入可以说就是proxy模式的一种应用,这里总结一下常用的三种依赖注入方法
1. 接口注入
我们常常借助接口来将调用者与实现者分离。如:
public class ClassA { private InterfaceB clzB; public init() { Ojbect obj = Class.forName(Config.BImplementation).newInstance(); clzB = (InterfaceB)obj; } …… }
上面的代码中,ClassA依赖于Inte*** ceB的实现,如何获得Inte*** ceB实现类的实例?传统的方法是在代码中创建Inte*** ceB实现类的实例,并将起赋予clzB。而这样一来,ClassA在编译期即依赖于Inte*** ceB的实现。为了将调用者与实现者在编译期分离,于是有了上面的代码,我们根据预先在配置文件中设定的实现类的类名,动态加载实现类,并通过Inte*** ceB强制转型后为ClassA所用。
这就是接口注入的一个最原始的雏形。而对于一个接口注入型IOC容器而言,加载接口实现并创建其实例的工作由容器完成,如J2EE开发中常用的Context.lookup(ServletContext.getXXX),都是接口注入型IOC的表现形式。
Apache Avalon是一个典型的Type1型IOC容器。
2. 构造子注入
构造子注入,即通过构造函数完成依赖关系的设定,如:
public class DIByConstructor { private final DataSource dataSource; private final String message; public DIByConstructor(DataSource ds, String msg) { this.dataSource = ds; this.message = msg; } …… }
可以看到,在Type2类型的依赖注入机制中,依赖关系是通过类构造函数建立,容器通过调用类的构
造方法,将其所需的依赖关系注入其中。
PicoContainer(另一种实现了依赖注入模式的轻量级容器)首先实现了Type2类型的依赖注入模式。
3. 设置注入
这种方式广泛应用在Spring框架的参数配置中,客户代码仅仅面向接口编程,而无需知道实现类的具体名称。同时,我们可以很简单的通过修改配置文件来切换具体的底层实现类。下面我们抛开Spring框架本身,使用一个简单的例子来实现类似Spring的依赖注入
public class ActionFactory { public static Action getAction(String actionName) { Properties pro = new Properties(); try { pro.load(new FileInputStream("config.properties")); String actionImplName = (String) pro.get(actionName); String actionMessage = (String) pro.get(actionName + "_msg"); Object obj = Class.forName(actionImplName).newInstance(); // BeanUtils是Apache Commons BeanUtils提供的辅助类 BeanUtils.setProperty(obj, "message", actionMessage); return (Action) obj; } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return null; } }
配置文件则采用最简单的properties文件形式:
TheAction=net.xiaxin.spring.qs.UpperAction
TheAction_msg=HeLLo
测试类:
public void testFactory(){ Action action = ActionFactory.getAction("TheAction"); System.out.println(action.execute("Rod Johnson")); }
上面的例子中,我们通过设置注入,在运行期动态将字符串“HeLLo” 注入到Action实现类的Message属性中。用同样的方法,我们可以通过修改配置文件让程序调用不同的实现方法,从而实现灵活的依赖注入。在Hive源码中,HiveDriverRunHook类也是使用这种方式实现注入的
- 点赞
- 收藏
- 关注作者
评论(0)