Section 1 Dubbo dynamically generated classes
When dubbo calls the exportServices() method, it will use code generation technology to dynamically generate the subclasses of Protocol$Adaptive, ProxyFactory$Adaptive and Wrapper.
Dubbo uses javassist to dynamically generate classes. Dubbo has two scenarios using dynamic classes.
1)ExtensionLoader.getExtensionLoader().getAdaptiveExtension() uses JavassistCompiler to generate Adaptive classes of each type. Protocol$Adaptive, ProxyFactory$Adaptive and other classes are generated by this method.
2)ServiceConfig.doExportUrlsFor1Protocol() uses javassistproxyfactory The getinvoker () method calls Wrapper The makewrapper () method generates Wrapper subclasses for < Dubbo: Service > in xml.
Section 2 Protocol$Adaptive class
GreetingService is defined as follows.
package org.example.dubbo2.provider.api; public interface GreetingService { String sayHi(String name); String sayBye(String name); }
The implementation of GreetingServiceImpl is as follows.
package org.example.dubbe2.provider.impl; import org.example.dubbo2.provider.api.GreetingService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class GreetingServiceImpl implements GreetingService { private static final Logger logger = LoggerFactory.getLogger(GreetingServiceImpl.class); @Override public String sayHi(String name) { logger.info(name); return "hi, " + name; } @Override public String sayBye(String name) { logger.info(name); return "bye, " + name; } }
The startup classes are as follows.
package org.example.dubbe2.provider.impl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.io.IOException; @Configuration public class Dubbo2ProviderApplication { private static final Logger logger = LoggerFactory.getLogger(Dubbo2ProviderApplication.class); public static void main(String[] args) throws IOException { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"/spring/dubbo-provider.xml"}); context.start(); System.in.read(); // press any key to exit } }
dubbo-provider. The XML content is as follows.
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://dubbo.apache.org/schema/dubbo" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> <dubbo:application name="dubbo2-provider"/> <dubbo:registry address="zookeeper://172.16.4.126:2181"/> <dubbo:metadata-report address="zookeeper://172.16.4.126:2181"/> <dubbo:protocol name="dubbo" port="20880"/> <dubbo:service interface="org.example.dubbo2.provider.api.GreetingService" ref="greetingService"/> <bean id="greetingService" class="org.example.dubbe2.provider.impl.GreetingServiceImpl"/> </beans>
ServiceConfig is defined as follows (excluding other information). When the JVM loads the ServiceConfig class, it initializes its two static static fields.
public class ServiceConfig<T> extends ServiceConfigBase<T> { private static final Protocol PROTOCOL = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); private static final ProxyFactory PROXY_FACTORY = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); }
When calling extensionloader When getadapteextension() method is used, createadapteextensionclass() method will be executed to dynamically generate Protocol$Adaptive and ProxyFactoryAdaptive classes. Add a breakpoint in the createadaptive extensionclass () code, start the program to the breakpoint, and check the value of the code, as shown in the following figure.
After the code value is copied and formatted, the dynamically generated Protocol$Adaptive class code is as follows.
package org.apache.dubbo.rpc; import org.apache.dubbo.common.extension.ExtensionLoader; public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol { public void destroy() { throw new UnsupportedOperationException("The method public abstract void org.apache.dubbo.rpc.Protocol.destroy() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!"); } public int getDefaultPort() { throw new UnsupportedOperationException("The method public abstract int org.apache.dubbo.rpc.Protocol.getDefaultPort() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!"); } public org.apache.dubbo.rpc.Invoker refer(java.lang.Class arg0, org.apache.dubbo.common.URL arg1) throws org.apache.dubbo.rpc.RpcException { if (arg1 == null) throw new IllegalArgumentException("url == null"); org.apache.dubbo.common.URL url = arg1; String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol()); if (extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])"); org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName); return extension.refer(arg0, arg1); } public org.apache.dubbo.rpc.Exporter export(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException { if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null"); if (arg0.getUrl() == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null"); org.apache.dubbo.common.URL url = arg0.getUrl(); String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol()); if (extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])"); org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName); return extension.export(arg0); } public java.util.List getServers() { throw new UnsupportedOperationException("The method public default java.util.List org.apache.dubbo.rpc.Protocol.getServers() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!"); } }
Section 3 ProxyFactory$Adaptive class
Dynamically copy the generated value of $factory class after formatting.
package org.apache.dubbo.rpc; import org.apache.dubbo.common.extension.ExtensionLoader; public class ProxyFactory$Adaptive implements org.apache.dubbo.rpc.ProxyFactory { public org.apache.dubbo.rpc.Invoker getInvoker(java.lang.Object arg0, java.lang.Class arg1, org.apache.dubbo.common.URL arg2) throws org.apache.dubbo.rpc.RpcException { if (arg2 == null) throw new IllegalArgumentException("url == null"); org.apache.dubbo.common.URL url = arg2; String extName = url.getParameter("proxy", "javassist"); if (extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" + url.toString() + ") use keys([proxy])"); org.apache.dubbo.rpc.ProxyFactory extension = (org.apache.dubbo.rpc.ProxyFactory) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.ProxyFactory.class).getExtension(extName); return extension.getInvoker(arg0, arg1, arg2); } public java.lang.Object getProxy(org.apache.dubbo.rpc.Invoker arg0, boolean arg1) throws org.apache.dubbo.rpc.RpcException { if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null"); if (arg0.getUrl() == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null"); org.apache.dubbo.common.URL url = arg0.getUrl(); String extName = url.getParameter("proxy", "javassist"); if (extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" + url.toString() + ") use keys([proxy])"); org.apache.dubbo.rpc.ProxyFactory extension = (org.apache.dubbo.rpc.ProxyFactory) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.ProxyFactory.class).getExtension(extName); return extension.getProxy(arg0, arg1); } public java.lang.Object getProxy(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException { if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null"); if (arg0.getUrl() == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null"); org.apache.dubbo.common.URL url = arg0.getUrl(); String extName = url.getParameter("proxy", "javassist"); if (extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" + url.toString() + ") use keys([proxy])"); org.apache.dubbo.rpc.ProxyFactory extension = (org.apache.dubbo.rpc.ProxyFactory) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.ProxyFactory.class).getExtension(extName); return extension.getProxy(arg0); } }
Section 4 ProxyFactory Extension instance
org.apache.dubbo.rpc.ProxyFactory configuration is as follows:
stub=org.apache.dubbo.rpc.proxy.wrapper.StubProxyFactoryWrapper jdk=org.apache.dubbo.rpc.proxy.jdk.JdkProxyFactory javassist=org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory
These classes all implement the proxyfactory interface.
When instantiating the JavassistProxyFactory object, the extesionloader loader of the ProxyFactory class will decorate the JavassistProxyProxyFactory instance with a StubProxyFactoryWrapper. Its purpose is to use the decorator pattern to realize the function of AOP.
Section 5 Wrapper subclass
In serviceconfig The doExportUrlsFor1Protocol () method invokes exportLocal() to increase the breakpoint, as shown in the following diagram, and the startup program executes here, then F7 executes into the exportLocal() method.
Execute to protocol export(PROXY_FACTORY.getInvoker(ref, interfaceClass, local)).
Then, call F7 to enter javassistproxfactory Getinvoker () method. Go down to wrapper Makewrapper() method.
In wrapper CC. In makewrapper() method Toclass() adds a breakpoint, runs here, and then press F7 to enter classgenerator Toclass () method, and then enter classgenerator Toclass (classloader, loader, protectiondomain PD) method, run F8 step by step until return mctc toClass(laoder, pd).
Open the Evaluate dialog box in the IDEA and enter the following code in the Expression edit box to write the dynamically generated CtClass object to local 1 Class file.
FileOutputStream out1 = new FileOutputStream("D:\\1.class");out1.write(mCtc.toBytecode());out1.close();return "";
Then find this 1 Class file, select it and drag it into the IDEA edit box to view the source code content corresponding to the class file.
<dubbo:service interface="org.example.dubbo2.provider.api.GreetingService" ref="greetingService"/> <bean id="greetingService" class="org.example.dubbe2.provider.impl.GreetingServiceImpl"/>
The dynamic classes generated for the above < Dubbo: Service > tags in xml are as follows, which are subclasses of Wrapper class.
package org.apache.dubbo.common.bytecode; import java.lang.reflect.InvocationTargetException; import java.util.Map; import org.apache.dubbo.common.bytecode.ClassGenerator.DC; import org.example.dubbe2.provider.impl.GreetingServiceImpl; public class Wrapper1 extends Wrapper implements DC { public static String[] pns; public static Map pts; public static String[] mns; public static String[] dmns; public static Class[] mts0; public static Class[] mts1; public String[] getPropertyNames() { return pns; } public boolean hasProperty(String var1) { return pts.containsKey(var1); } public Class getPropertyType(String var1) { return (Class)pts.get(var1); } public String[] getMethodNames() { return mns; } public String[] getDeclaredMethodNames() { return dmns; } public void setPropertyValue(Object var1, String var2, Object var3) { try { GreetingServiceImpl var4 = (GreetingServiceImpl)var1; } catch (Throwable var6) { throw new IllegalArgumentException(var6); } throw new NoSuchPropertyException("Not found property \"" + var2 + "\" field or setter method in class org.example.dubbe2.provider.impl.GreetingServiceImpl."); } public Object getPropertyValue(Object var1, String var2) { try { GreetingServiceImpl var3 = (GreetingServiceImpl)var1; } catch (Throwable var5) { throw new IllegalArgumentException(var5); } throw new NoSuchPropertyException("Not found property \"" + var2 + "\" field or getter method in class org.example.dubbe2.provider.impl.GreetingServiceImpl."); } public Object invokeMethod(Object var1, String var2, Class[] var3, Object[] var4) throws InvocationTargetException { GreetingServiceImpl var5; try { var5 = (GreetingServiceImpl)var1; } catch (Throwable var8) { throw new IllegalArgumentException(var8); } try { if ("sayHi".equals(var2) && var3.length == 1) { return var5.sayHi((String)var4[0]); } if ("sayBye".equals(var2) && var3.length == 1) { return var5.sayBye((String)var4[0]); } } catch (Throwable var9) { throw new InvocationTargetException(var9); } throw new NoSuchMethodException("Not found method \"" + var2 + "\" in class org.example.dubbe2.provider.impl.GreetingServiceImpl."); } public Wrapper1() { } }
Section 6 Protocol Extension instance
org. apache. dubbo. rpc. The protocol configuration is as follows:
filter=org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper listener=org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper mock=org.apache.dubbo.rpc.support.MockProtocol dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol injvm=org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol http=org.apache.dubbo.rpc.protocol.http.HttpProtocol rmi=org.apache.dubbo.rpc.protocol.rmi.RmiProtocol hessian=org.apache.dubbo.rpc.protocol.hessian.HessianProtocol webservice=org.apache.dubbo.rpc.protocol.webservice.WebServiceProtocol thrift=org.apache.dubbo.rpc.protocol.thrift.ThriftProtocol native-thrift=org.apache.dubbo.rpc.protocol.nativethrift.ThriftProtocol memcached=org.apache.dubbo.rpc.protocol.memcached.MemcachedProtocol redis=org.apache.dubbo.rpc.protocol.redis.RedisProtocol rest=org.apache.dubbo.rpc.protocol.rest.RestProtocol xmlrpc=org.apache.dubbo.xml.rpc.protocol.xmlrpc.XmlRpcProtocol grpc=org.apache.dubbo.rpc.protocol.grpc.GrpcProtocol registry=org.apache.dubbo.registry.integration.InterfaceCompatibleRegistryProtocol service-discovery-registry=org.apache.dubbo.registry.integration.RegistryProtocol qos=org.apache.dubbo.qos.protocol.QosProtocolWrapper
These classes implement the Protocol interface.
ProtocolFilterWrapper, ProtocolListenerWrapper and QosProtocolWrapper are three decorator classes used to decorate other Protocol instances. The decoration sequence is as follows
QosProtocolWrapper -> ProtocolFilterWrapper -> ProtocolListenerWrapper -> other Protocol Implementation class
Section 7 Filter Active Extension instance
org. apache. dubbo. rpc. The filter configuration is as follows:
cache=org.apache.dubbo.cache.filter.CacheFilter validation=org.apache.dubbo.validation.filter.ValidationFilter echo=org.apache.dubbo.rpc.filter.EchoFilter generic=org.apache.dubbo.rpc.filter.GenericFilter genericimpl=org.apache.dubbo.rpc.filter.GenericImplFilter token=org.apache.dubbo.rpc.filter.TokenFilter accesslog=org.apache.dubbo.rpc.filter.AccessLogFilter activelimit=org.apache.dubbo.rpc.filter.ActiveLimitFilter classloader=org.apache.dubbo.rpc.filter.ClassLoaderFilter context=org.apache.dubbo.rpc.filter.ContextFilter consumercontext=org.apache.dubbo.rpc.filter.ConsumerContextFilter exception=org.apache.dubbo.rpc.filter.ExceptionFilter executelimit=org.apache.dubbo.rpc.filter.ExecuteLimitFilter deprecated=org.apache.dubbo.rpc.filter.DeprecatedFilter compatible=org.apache.dubbo.rpc.filter.CompatibleFilter timeout=org.apache.dubbo.rpc.filter.TimeoutFilter tps=org.apache.dubbo.rpc.filter.TpsLimitFilter trace=org.apache.dubbo.rpc.protocol.dubbo.filter.TraceFilter future=org.apache.dubbo.rpc.protocol.dubbo.filter.FutureFilter monitor=org.apache.dubbo.monitor.support.MonitorFilter metrics=org.apache.dubbo.monitor.dubbo.MetricsFilter
Active Filter instance on provider side
ExtensionLoader. getExtensionLoader(Filter.class). Getactivateextension (invoker. Geturl(), "service. Filter", "provider") obtains the following valid filter instances on the provider side:
filters = {ArrayList@4255} size = 8 0 = {EchoFilter@5306} 1 = {ClassLoaderFilter@5307} 2 = {GenericFilter@5308} 3 = {ContextFilter@5309} 4 = {TraceFilter@5310} 5 = {TimeoutFilter@5311} 6 = {MonitorFilter@5312} 7 = {ExceptionFilter@5313}
Package the invoker with filter chain. The FilterNode chain is shown in the figure below