pigeon Pigeon开发指南 中指出,调用 pigeon 服务用有多种方式:spring 配置,annotation方式、spring schema定义方式、api方式。一般使用传统的 spring 配置方式,具体示例如下:
<bean id="echoService" class="com.dianping.pigeon.remoting.invoker.config.spring.ReferenceBean" init-method="init">
<!-- 服务全局唯一的标识url,默认是服务接口类名,必须设置 -->
<property name="url" value="http://service.dianping.com/demoService/echoService_1.0.0" />
<!-- 接口名称,必须设置 -->
<property name="interfaceName" value="com.dianping.pigeon.demo.EchoService" />
<!-- 超时时间,毫秒,默认5000,建议自己设置 -->
<property name="timeout" value="2000" />
<!-- 序列化,hessian/fst/protostuff,默认hessian,可不设置-->
<property name="serialize" value="hessian" />
<!-- 调用方式,sync/future/callback/oneway,默认sync,可不设置 -->
<property name="callType" value="sync" />
<!-- 失败策略,快速失败failfast/失败转移failover/失败忽略failsafe/并发取最快返回forking,默认failfast,可不设置 -->
<property name="cluster" value="failfast" />
<!-- 是否超时重试,默认false,可不设置 -->
<property name="timeoutRetry" value="false" />
<!-- 重试次数,默认1,可不设置 -->
<property name="retries" value="1" />
</bean>
然后,使用时,在相应的 field 上使用 @Autowire 注解指明即可,如下:
@Controller
public class Demo {
@Autowired
private EchoService echoService;
}
那么问题来了,被注入的 Field 的类型是 EchoService,但是配置的 bean 是的类型是 ReferenceBean,怎么匹配上的?再延伸一下,所有的 service 在调用声明的时候都是 ReferenceBean 类型,但是被注入的 field 类型不定,又是怎么分别匹配的?
ReferenceBean 详解
看下 ReferenceBean 的定义就知道了,实现了 FactoryBean 接口,看下这个接口的定义是什么:
* Interface to be implemented by objects used within a {@link BeanFactory}
* which are themselves factories. If a bean implements this interface,
* it is used as a factory for an object to expose, not directly as a bean
* instance that will be exposed itself.
*
* <p><b>NB: A bean that implements this interface cannot be used as a
* normal bean.</b> A FactoryBean is defined in a bean style, but the
* object exposed for bean references ({@link #getObject()} is always
* the object that it creates.
*
* <p>FactoryBeans can support singletons and prototypes, and can
* either create objects lazily on demand or eagerly on startup.
* The {@link SmartFactoryBean} interface allows for exposing
* more fine-grained behavioral metadata.
*
* <p>This interface is heavily used within the framework itself, for
* example for the AOP {@link org.springframework.aop.framework.ProxyFactoryBean}
* or the {@link org.springframework.jndi.JndiObjectFactoryBean}.
* It can be used for application components as well; however,
* this is not common outside of infrastructure code.
总的来说,这是提供 bean 的一种方式,真正提供的产物是 #getObejct()
方法生成的 bean,文档也提到,框架内部大量使用这个接口提供 bean
看看接口内容:
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
boolean isSingleton();
}
pigeon 的 ReferenceBean 实现中, isSingleton()
方法总是返回 true,就是说生成的都是单例
getObject()
方法返回真正的 bean,那么它是在哪里生成的呢?答案就是 spring 配置中的 init()
方法。
init 方法
来看方法的实现:
public void init() throws Exception {
if (StringUtils.isBlank(interfaceName)) {
throw new IllegalArgumentException("invalid interface:" + interfaceName);
}
this.objType = ClassUtils.loadClass(this.classLoader, this.interfaceName.trim());
InvokerConfig<?> invokerConfig = new InvokerConfig(this.objType, this.url, this.timeout, this.callType,
this.serialize, this.callback, this.suffix, this.writeBufferLimit, this.loadBalance, this.cluster,
this.retries, this.timeoutRetry, this.vip, this.version, this.protocol);
invokerConfig.setClassLoader(classLoader);
// ...
this.obj = ServiceFactory.getService(invokerConfig);
configLoadBalance(invokerConfig);
}
设置了 InvokerConfig,之后生成代理,this.Obj
就是 FactoryBean 返回的对象。
具体在使用的时候,Autowire 注解的 field 在注入时会触发从 BeanFactory 获取相应的 bean,此时根据 field 的类型查找 candidate bean,此时遍历 BeanDefinition,如果发现是 FactoryBean,则会做一些标记,然后 getBean()
时就从 FactoryBean 获取。具体逻辑在:org.springframework.beans.factory.support.DefaultListableBeanFactory#findAutowireCandidates
,这里就不详细展开了。
总的来说,就是 FactoryBean 和 Autowire 机制的合理使用。