前两篇文章讲到了项目用到的消息中心和工作流模块,这篇文章来了解一下怎么样使用模块里面的功能。
spring的核心是DI 和IOC,那到底什么是DI(依赖注入)和IOC(控制反转)呢,依赖在core java里面讲过,依赖是对象之间的关系,A对象依赖B对象,就是说A对象中有关于B对象的引用,比如说我们自己写的类里面需要输入输出,用到了InputStream或者是时间DateFormat,在我们使用这些工具类的时候我们都要实例化它们,这就是依赖。依赖注入我们就可以简单的理解为,我们A对象依赖的B对象是Spring像打针一样把B对象的实例注入到A对象中了,一想到打针就觉得屁股一阵酸爽。而我们都知道设计原则告诉我们,要依赖接口不要依赖实现类,这样就降低了耦合,增加了灵活性,不得不说一个是实现类一个是接口,带来了翻天覆地的变化。
而整个上面的过程即:A对象靠Spring的注入依赖B对象的过程,叫控制反转。
用我们生活中的例子讲:大熊想要造一座自己的房子(好开心),在没有哆啦A梦(Spring)这个逆天的助手之前,他要自己买制砖机,水泥搅拌机等等工具(光联系厂家,决定什么牌子就花费好多时间,而且房子造完之后这些大型机器就没有用了)。但是自从有了哆啦A梦就不一样啦,腰不疼了,腿不酸了,上楼梯不费劲!他只要告诉哆啦A梦自己需要一个能造砖头的机器(我不管你是哪个牌子的),一个搅拌水泥的机器(我也不管是哪个牌子的),哆啦A梦就在自己的小口袋里面找啊,找到以前自己装进口袋的宝贝,翻出来一盒咸鱼,不是,一盒皮皮虾,不是,一个不耐烦就给大熊一记大飞脚。最终找到了需要的机器,大熊造完房子之后哆啦A梦又把机器放回小口袋,是不是很方便。
那我们就看看源码中Bean的配置和依赖注入
首先我们知道Facade是提供对外能力输入的接口,这个就要先放到Spring的小口袋里:
//第一个Bean是具体的实现类
<bean class=""></bean>
//第二个Bean是像容器中注入上面的实现类,注意,此处一起配置了接口和版本号。容器使用了Map,key就是接口名称+版本号,而value就是包含接口信息和版本号以及实现类的整个类。
<bean class="" init-method="init">
<property name="delegateInterface" value=""></property>
<property name="version" value="0.0.1"></property>
<property name="target" ref="bidItemQueryFacade"></property>
</bean>
String key = () + "_" + ();
if ((key) != null) {
throw new CriticalSystemError("重复注册服务导致系统无法启动[" + key + "]");
}
(key, provider);
上面这个是Spring的bean的配置过程,宝贝已经放入Spring的小口袋里面了,下面的工程需要使用这个宝贝的时候是按照能力(接口和版本)检索的,比如需要实现了BidItemQueryFacade接口版本是0.0.1的实现类
<bean class="">
<property name="delegateInterface" value=""></property>
<property name="version" value="0.0.1"></property>
</bean>
<bean factory-bean="bidItemQueryFacade_consumer" factory-method="init"></bean>
<bean class="">
<property name="bidItemQueryFacade" ref="bidItemQueryFacade"></property>
</bean>
上面的配置就是先把需要的接口和版本号告诉工程类bidItemQueryFacade_consumer,然后用工程类init方法来生成具体的实例对象。(这里面用到了发射和代理,很刺激)
第一个bean生成FacadeConsumer实例,并把我们希望的接口和版本号注入,
第二个bean就是用init方法生成具体的实例对象
if ((version) || (delegateInterface)) {
throw new CriticalSystemError("服务消费者,version[" + version + "]和delegateInterface["
+ delegateInterface + "]不可为空:");
}
if (proxyObj == null) {
Class<?> delegateInterfaceCls = (delegateInterface, false,
().getContextClassLoader());//(delegateInterface);
Class<?>[] tmp = new Class<?>[1];
tmp[0] = delegateInterfaceCls;
// proxyObj = (().getClassLoader(), tmp, this);
proxyObj = (().getContextClassLoader(),
tmp, this);
}
return proxyObj;
我们看到这个地方实际上就是用到反射生成接口的实例,然后用到代理实现接口,
每次调用代理的方法时,我们就会
/**
* 动态代理回调接口
* @see #invoke(, , [])
*/
public Object invoke(Object proxy, Method method, Object[] args) {
if (() == null) {
(null);
}
FacadeProvider provider = null;
switch (consumerType) {
case JVM_LOCAL:
provider = (delegateInterface, version);
break;
default:
throw new RpcException("consumerType is not support:" + consumerType);
}
if (provider == null) {
throw new RpcException(
"找不到对应的服务提供者:interface[" + delegateInterface + "], version[" + version + "]");
}
String invoker = ().getClass().getName() + "." + () + "("
+ () + ")";
try {
(invoker);
return ((), args);
、、我们看到代理回调的时候,先找到我们之前注入的provider。然后找出具体实现类,调用((), args)。
我们不得不佩服Spring在帮助我们完成自己的心愿时付出的努力。也不得不佩服大熊有这么好的伙伴