在消费者端,dubbo通过AnnotationBean类实现了BeanPostProcessor接口用来对beanFactory的中bean进行相应的处理。
关于消费者的bean以及bean中@Reference注解的处理在AnnotationBean的postProcessBeforeInitialization()方法当中。
对于bean中采用了@Reference注解的属性的处理在下面这段代码中。
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
try {
if (! field.isAccessible()) {
field.setAccessible(true);
}
Reference reference = field.getAnnotation(Reference.class);
if (reference != null) {
Object value = refer(reference, field.getType());
if (value != null) {
field.set(bean, value);
}
}
} catch (Throwable e) {
logger.error("Failed to init remote service reference at filed " + field.getName() + " in class " + bean.getClass().getName() + ", cause: " + e.getMessage(), e);
}
}
在这里将会遍历bean当中所有的属性,当找到带有@Reference注解的属性的时候,马上会尝试通过refer()方法完成对于@Reference的属性类型类的代理生成,以便在下面的代码中通过set()方法将代理了相应所需要代理的方法的代理set()进bean相应的的属性上。
看到实现同样实现在AnnotationBean类中的refer()方法。
String interfaceName;
if (! "".equals(reference.interfaceName())) {
interfaceName = reference.interfaceName();
} else if (! void.class.equals(reference.interfaceClass())) {
interfaceName = reference.interfaceClass().getName();
} else if (referenceClass.isInterface()) {
interfaceName = referenceClass.getName();
} else {
throw new IllegalStateException("The @Reference undefined interfaceClass or interfaceName, and the property type " + referenceClass.getName() + " is not a interface.");
}
String key = reference.group() + "/" + interfaceName + ":" + reference.version();
ReferenceBean<?> referenceConfig = referenceConfigs.get(key);
在refer()方法的一开始,会根据@Reference的配置,或者本身配置了@Reference注解属性的实现接口来确定这个属性的接口名称(优先选择配置在注解当中的接口属性),因此将会构造成这个ReferenceBean的key(由reference的组名,接口名称以及版本号组成),如果在这里之前的bean已经构造过相同key的referenceBean,那么可以直接将直接的referenceBean取出而不用重新创建新的referenceBean来创建代理。
当然,如果没有通过key取得到相应的referenceBean的话,将会在下面的代码当中重新创建referenceBean,并根据Spring所提供的的上下文将referenceBean所需要的属性配置在ReferenceBean当中。
if (reference.consumer() != null && reference.consumer().length() > 0) {
referenceConfig.setConsumer((ConsumerConfig)applicationContext.getBean(reference.consumer(), ConsumerConfig.class));
}
if (reference.monitor() != null && reference.monitor().length() > 0) {
referenceConfig.setMonitor((MonitorConfig)applicationContext.getBean(reference.monitor(), MonitorConfig.class));
}
if (reference.application() != null && reference.application().length() > 0) {
referenceConfig.setApplication((ApplicationConfig)applicationContext.getBean(reference.application(), ApplicationConfig.class));
}
if (reference.module() != null && reference.module().length() > 0) {
referenceConfig.setModule((ModuleConfig)applicationContext.getBean(reference.module(), ModuleConfig.class));
}
if (reference.consumer() != null && reference.consumer().length() > 0) {
referenceConfig.setConsumer((ConsumerConfig)applicationContext.getBean(reference.consumer(), ConsumerConfig.class));
}
try {
referenceConfig.afterPropertiesSet();
} catch (RuntimeException e) {
throw (RuntimeException) e;
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
以上面的代码为例子,如果这@Reference注解当中配置了相应的监控中心消费者等属性,都将会在这里尝试从spring的上下文当中去取得相应的bean注入到referenceBean当中。
在这之后调用referenceBean的afterPropertiesSet()方法。
在afterPropertiesSet()方法中,首先是对在@Reference注解当中并没有进行配置的属性进行设置。以Registry(注册中心)为例子。
if ((getRegistries() == null || getRegistries().size() == 0)
&& (getConsumer() == null || getConsumer().getRegistries() == null || getConsumer().getRegistries().size() == 0)
&& (getApplication() == null || getApplication().getRegistries() == null || getApplication().getRegistries().size() == 0)) {
Map<String, RegistryConfig> registryConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class, false, false);
if (registryConfigMap != null && registryConfigMap.size() > 0) {
List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>();
for (RegistryConfig config : registryConfigMap.values()) {
if (config.isDefault() == null || config.isDefault().booleanValue()) {
registryConfigs.add(config);
}
}
if (registryConfigs != null && registryConfigs.size() > 0) {
super.setRegistries(registryConfigs);
}
}
}
如果在之前的注解当中并没有配置注册中心或者在referenceBean的消费者配置以及应用配置中都没有配置上注册中心的属性,那么将会遍历Spring上下文当中所有RegistryConfig类配置在ReferenceBean的超类ReferenceConfig当中。
在这个方法中,针对其他属性,例如moniter监控中心的操作与这里的注册中心的操作完全类似。
之后在确认所有属性配置完毕,并且消费者也已经初始化完毕之后,将会通过getObject()方法尝试取得referenceBean当中的ref属性,而这个属性恰恰就是代理了referenceBean当中消费者所要调用方法的代理类。
public Object getObject() throws Exception {
return get();
}
public synchronized T get() {
if (destroyed){
throw new IllegalStateException("Already destroyed!");
}
if (ref == null) {
init();
}
return ref;
}
由上文可见,当第一次调用getObject()方法的时候将会毫无疑问的调用ReferenceConfig的init()方法。
在init()方法的开头,仍旧是检察ReferenceBean的属性的配置是否已经完毕,并在这里对之前方法仍旧没有配置的属性进行配置。同时针对ReferenceBean的接口以及所要实现代理的方法进行验证,该方法是否是该接口下面的方法。
if (methods != null && methods.size() > 0) {
for (MethodConfig methodBean : methods) {
String methodName = methodBean.getName();
if (methodName == null || methodName.length() == 0) {
throw new IllegalStateException("<dubbo:method> name attribute is required! Please check: <dubbo:service interface=\"" + interfaceClass.getName() + "\" ... ><dubbo:method name=\"\" ... /></<dubbo:reference>");
}
boolean hasMethod = false;
for (java.lang.reflect.Method method : interfaceClass.getMethods()) {
if (method.getName().equals(methodName)) {
hasMethod = true;
break;
}
}
if (!hasMethod) {
throw new IllegalStateException("The interface " + interfaceClass.getName()
+ " not found method " + methodName);
}
}
}
在上面的代码中确保了所要代理的方法一定是接口所声明的方法。
Map<String, String> map = new HashMap<String, String>();
Map<Object, Object> attributes = new HashMap<Object, Object>();
map.put(Constants.SIDE_KEY, Constants.CONSUMER_SIDE);
map.put(Constants.DUBBO_VERSION_KEY, Version.getVersion());
map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
if (ConfigUtils.getPid() > 0) {
map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
}
if (! isGeneric()) {
String revision = Version.getVersion(interfaceClass, version);
if (revision != null && revision.length() > 0) {
map.put("revision", revision);
}
String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
if(methods.length == 0) {
logger.warn("NO method found in service interface " + interfaceClass.getName());
map.put("methods", Constants.ANY_VALUE);
}
else {
map.put("methods", StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));
}
}
map.put(Constants.INTERFACE_KEY, interfaceName);
appendParameters(map, application);
appendParameters(map, module);
appendParameters(map, consumer, Constants.DEFAULT_KEY);
appendParameters(map, this);
在接下来,将会构造两个hashMap,其中的map将会存放是实现代理的必要属性,也将是之后生成代理的重要参数。
在这里,消费者的身份属性,版本属性,创建时间,进程id都将在这里被设置在map当中。如果没有才用泛化引用,在这里会给非动态类的将要被代理的接口生产相应的wrapper。
public static Wrapper getWrapper(Class<?> c)
{
while( ClassGenerator.isDynamicClass(c) ) // can not wrapper on dynamic class.
c = c.getSuperclass();
if( c == Object.class )
return OBJECT_WRAPPER;
Wrapper ret = WRAPPER_MAP.get(c);
if( ret == null )
{
ret = makeWrapper(c);
WRAPPER_MAP.put(c,ret);
}
return ret;
}可以看到,在这里会给接口的父类创建wrapper,如果父类直接是Object,那么直接会返回默认的ObjectWrapper,但是如果父类不是,那么将会通过makeWrapper()方法动态生成wrapper。
Wrapper通过包装目标类,动态根据目标类生成相应的get和set方法。拿field属性来做例子。
StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o, String n, Object v){ ");
StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o, String n){ ");
c1.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
c2.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
for( Field f : c.getFields() )
{
String fn = f.getName();
Class<?> ft = f.getType();
if( Modifier.isStatic(f.getModifiers()) || Modifier.isTransient(f.getModifiers()) )
continue;
c1.append(" if( $2.equals(\"").append(fn).append("\") ){ w.").append(fn).append("=").append(arg(ft, "$3")).append("; return; }");
c2.append(" if( $2.equals(\"").append(fn).append("\") ){ return ($w)w.").append(fn).append("; }");
pts.put(fn, ft);
}
在这里动态根据目标类的属性生成了相应的针对被包装类的get和set方法用来在接下里的操作可以方便取得目标的属性。同理被包装类的方法,经过wrapper的包装,方法的取得也动态生成了相应的方法。
在通过wrapper取得相应的方法之后,将所有的方法通过逗号隔开组成新的字符串放在map当中。
同时,在AbstractConfig类中,给出了appendParameters()方法。
protected static void appendParameters(Map<String, String> parameters, Object config, String prefix) {
if (config == null) {
return;
}
Method[] methods = config.getClass().getMethods();
for (Method method : methods) {
try {
String name = method.getName();
if ((name.startsWith("get") || name.startsWith("is"))
&& ! "getClass".equals(name)
&& Modifier.isPublic(method.getModifiers())
&& method.getParameterTypes().length == 0
&& isPrimitive(method.getReturnType())) {
Parameter parameter = method.getAnnotation(Parameter.class);
if (method.getReturnType() == Object.class || parameter != null && parameter.excluded()) {
continue;
}
int i = name.startsWith("get") ? 3 : 2;
String prop = StringUtils.camelToSplitName(name.substring(i, i + 1).toLowerCase() + name.substring(i + 1), ".");
String key;
if (parameter != null && parameter.key() != null && parameter.key().length() > 0) {
key = parameter.key();
} else {
key = prop;
}
Object value = method.invoke(config, new Object[0]);
String str = String.valueOf(value).trim();
if (value != null && str.length() > 0) {
if (parameter != null && parameter.escaped()) {
str = URL.encode(str);
}
if (parameter != null && parameter.append()) {
String pre = (String)parameters.get(Constants.DEFAULT_KEY + "." + key);
if (pre != null && pre.length() > 0) {
str = pre + "," + str;
}
pre = (String)parameters.get(key);
if (pre != null && pre.length() > 0) {
str = pre + "," + str;
}
}
if (prefix != null && prefix.length() > 0) {
key = prefix + "." + key;
}
parameters.put(key, str);
} else if (parameter != null && parameter.required()) {
throw new IllegalStateException(config.getClass().getSimpleName() + "." + key + " == null");
}
} else if ("getParameters".equals(name)
&& Modifier.isPublic(method.getModifiers())
&& method.getParameterTypes().length == 0
&& method.getReturnType() == Map.class) {
Map<String, String> map = (Map<String, String>) method.invoke(config, new Object[0]);
if (map != null && map.size() > 0) {
String pre = (prefix != null && prefix.length() > 0 ? prefix + "." : "");
for (Map.Entry<String, String> entry : map.entrySet()) {
parameters.put(pre + entry.getKey().replace('-', '.'), entry.getValue());
}
}
}
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
}在这个方法中,将会遍历目标类当中的is和get方法,并通过反射获得相应的值,如果在该方法的上面实现了@Parameter注解,那么还将会对相应的值进行url编码,在获得相应的值之后通过注解当中配置的key或者属性名加上默认的前缀,作为键值对存放在map中,同样作为创建代理的参数存放在map中。在具体的参数获得中,application,Consumer,module以及该referenceBean和目标接口下的get和is方法都会把属性存放在map中,在init()方法的最后通过createProxy()方法,将Map作为参数,获取代理。
在createProxy()方法当中,首先,会根据是否配置了url来确定是否配置在了一开始的ReferenceBean当中,如果没有,则判断本地是否有接口暴露,如果有则采用本地服务。
这里默认不是本地服务,而是配置了注册中心往下走。
如果没有配置url在referenceBean当中,则会loadRegistries()当中url的数组。
protected List<URL> loadRegistries(boolean provider) {
checkRegistry();
List<URL> registryList = new ArrayList<URL>();
if (registries != null && registries.size() > 0) {
for (RegistryConfig config : registries) {
String address = config.getAddress();
if (address == null || address.length() == 0) {
address = Constants.ANYHOST_VALUE;
}
String sysaddress = System.getProperty("dubbo.registry.address");
if (sysaddress != null && sysaddress.length() > 0) {
address = sysaddress;
}
if (address != null && address.length() > 0
&& ! RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) {
Map<String, String> map = new HashMap<String, String>();
appendParameters(map, application);
appendParameters(map, config);
map.put("path", RegistryService.class.getName());
map.put("dubbo", Version.getVersion());
map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
if (ConfigUtils.getPid() > 0) {
map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
}
if (! map.containsKey("protocol")) {
if (ExtensionLoader.getExtensionLoader(RegistryFactory.class).hasExtension("remote")) {
map.put("protocol", "remote");
} else {
map.put("protocol", "dubbo");
}
}
List<URL> urls = UrlUtils.parseURLs(address, map);
for (URL url : urls) {
url = url.addParameter(Constants.REGISTRY_KEY, url.getProtocol());
url = url.setProtocol(Constants.REGISTRY_PROTOCOL);
if ((provider && url.getParameter(Constants.REGISTER_KEY, true))
|| (! provider && url.getParameter(Constants.SUBSCRIBE_KEY, true))) {
registryList.add(url);
}
}
}
}
}
return registryList;
}在loadRegistries方法中,首先会遍历所有的registryConfig,优先配置url为配置文件的url,如果没有则为本身所配置的url。接下里跟之前准备创建代理的参数的map一样,在这里类似的跟之前的操作一样构造url以及map。具体的url构造在urlUtils中实现。这里不展开。
在根据注册中心构造完毕url之后,也会根据是否配置了监控中心的url,添加监控中心的url属性,最后,所有参数将会被构造成get的形式作为最后的url保存下来。
在下面,每一个生成的url都会生成对应的invoker。
List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();
URL registryURL = null;
for (URL url : urls) {
invokers.add(refprotocol.refer(interfaceClass, url));
if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
registryURL = url; // 用了最后一个registry url
}
}
假如这里采用了dubbo协议,这里将会生成dubbo invoker。
这里生成的invoker将在方法最后最后在ProxyFactory当中通过getProxy()获得最后所需要的代理对象并返回。
在AbstractProxyFactory当中的getProxy()方法中。
public <T> T getProxy(Invoker<T> invoker) throws RpcException {
Class<?>[] interfaces = null;
String config = invoker.getUrl().getParameter("interfaces");
if (config != null && config.length() > 0) {
String[] types = Constants.COMMA_SPLIT_PATTERN.split(config);
if (types != null && types.length > 0) {
interfaces = new Class<?>[types.length + 2];
interfaces[0] = invoker.getInterface();
interfaces[1] = EchoService.class;
for (int i = 0; i < types.length; i ++) {
interfaces[i + 1] = ReflectUtils.forName(types[i]);
}
}
}
if (interfaces == null) {
interfaces = new Class<?>[] {invoker.getInterface(), EchoService.class};
}
return getProxy(invoker, interfaces);
}在这里,在除了定义在了invoker中的接口外,还将会固定将所代理的接口以及EchoService接口加在代理的类型当中。
接下来以jdk创建代理为例子,直接就在JdkProxyFactory中的getProxy()方法通过jdk实现了Invoker以及接口实现了关于Invoker的代理创建。
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new InvokerInvocationHandler(invoker));
}
参数与一般的jdk代理实现并无区别,只是Invoker在最后还是作为参数用来还是生成被代理鄂最终类InvokerInvocationHandler。
消费者的代理创建就此结束。
















