I want to continue dubbo's source code journey here, learn its design and techniques in the process, and look at the excellent code. I think it will certainly be helpful for our schedule coding. And those open source codes are things that have been tried and tested, and I hope to share with you.
Take ProtocolListener Wrapper as an example. When we look at the source code, we find that it is a standard implementation of decorative class. It has its own copy constructor, which copies the wrapped person in, and then combines the operation of decorative part. Look at the ProtocolListenerWrapper class for code like this:
public class ProtocolListenerWrapper implements Protocol { private final Protocol protocol; public ProtocolListenerWrapper(Protocol protocol){ if (protocol == null) { throw new IllegalArgumentException("protocol == null"); } this.protocol = protocol; } public int getDefaultPort() { return protocol.getDefaultPort(); } public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) { return protocol.export(invoker); } return new ListenerExporterWrapper<T>(protocol.export(invoker), Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class) .getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY))); } public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException { if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { return protocol.refer(type, url); } return new ListenerInvokerWrapper<T>(protocol.refer(type, url), Collections.unmodifiableList( ExtensionLoader.getExtensionLoader(InvokerListener.class) .getActivateExtension(url, Constants.INVOKER_LISTENER_KEY))); } public void destroy() { protocol.destroy(); } }
try { clazz.getConstructor(type); Set<Class<?>> wrappers = cachedWrapperClasses; if (wrappers == null) { cachedWrapperClasses = new ConcurrentHashSet<Class<?>>(); wrappers = cachedWrapperClasses; } wrappers.add(clazz); } catch (NoSuchMethodException e) {
As you can see above, use a field as a logic of judgment.
The getExtension(String name) method in Extension Loader calls createExtension(String name), which uses cachedWrapper Classes as a parameter to call the warpper class's own replication constructor, so that the decorated class can be packaged accurately, so that it can be persistent when the decorated class is called. The logical code in warpper is implemented by calling clazz.getConstructor method. The code snippet:
Set<Class<?>> wrapperClasses = cachedWrapperClasses; if (wrapperClasses != null && wrapperClasses.size() > 0) { for (Class<?> wrapperClass : wrapperClasses) { instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)); } }
public abstract class ExporterListenerAdapter implements ExporterListener { public void exported(Exporter<?> exporter) throws RpcException { } public void unexported(Exporter<?> exporter) throws RpcException { } }
This is a trick. When I just mentioned that I want to write extension classes, I don't inherit ExporterListener directly, because direct inheritance interface will force the implementation of two methods, and the author of dubbo in actual coding should also find that these two methods are used in totally different business, so we can only inherit ExporterListener Adapter, so our own business generation. There is no need for an empty method in the code.