当前位置: 首页 > 后端技术 > Java

dubbospi机制

时间:2023-04-02 02:15:09 Java

框架设计灵活,可扩展,给用户带来极大的便利。如果业务有新的变化,用新的实现替换之前的实现就行了,我们也知道怎么加载框架。不用太在意,显然这对我们开发者是很友好的。java中的SPI也是这个思路,dubbo中的SPI也是这个思路。java中的spi不够灵活,因为会一次性执行扩展点逻辑,所以这里就不展开了(可以参考javaspi),这里重点介绍dubbo中的SPI。使用方法一,根据接口全路径名在META-INF/services目录下创建文件,文件内容为key=value形式2、ExtensionLoader.getExtensionLoader(xxx.class).getExtension("key")这样我们就可以得到我们的自定义实现。实现分析下面展开ExtensionLoader.getExtensionLoader(xxx.class).getExtension(name)这行代码。publicstaticExtensionLoadergetExtensionLoader(Classtype){if(type==null)thrownewIllegalArgumentException("扩展类型==null");//判断给定类型是否为接口if(!type.isInterface()){thrownewIllegalArgumentException("扩展类型("+type+")不是接口!");}//判断给定接口上是否有SPI注解getSimpleName()+"注解!");}//先从map中获取ExtensionLoader,如果没有创建ExtensionLoaderloader=(ExtensionLoader)EXTENSION_LOADERS.get(type);if(loader==null){EXTENSION_LOADERS.putIfAbsent(type,newExtensionLoader(type));装载机=(ExtensionLoader)EXTENSION_LOADERS。得到(类型);}返回装载机;}该方法主要是获取ExtensionLoader:1、判断给定的类型,首先判断是否是接口类型;二、判断接口2是否有SPI注解,先根据给定的类型从Map中获取对应的ExtensionLoader,如果没有创建接下来,让我们看看getExtension(name)方法:publicTgetExtension(Stringname){if(name==null||name.length()==0)thrownewIllegalArgumentException("Extensionname==null");if("true".equals(name)){返回getDefaultExtension();}//首先获取包装类HolderHolderholder=cachedInstances.get(name);if(holder==null){cachedInstances.putIfAbsent(name,newHolder());holder=cachedInstances.get(名称);}//从包装类中获取实现类的实例,需要重点关注createExtensionObjectinstance=holder.get();if(instance==null){synchronized(holder){instance=holder.get();if(instance==null){instance=createExtension(名称);holder.set(实例);}}}返回(T)实例;}getExtension(name)方法的逻辑清晰明了:1.首先获取包装类Holder2,从包装类Hol在der中获取具体实现类的实例实现类的实例是如何创建的?查看createExtension(name)privateTcreateExtension(Stringname){/***getExtensionClasses会加载META-INF/services/、META-INF/dubbo/、META-INF/dubbo/internal/这三个*目录下的所有类*/Classclazz=getExtensionClasses().get(name);如果(clazz==null){抛出findException(名称);}try{//通过反射创建name对应的实例,并放入map中,下次可以直接从map中取T。instance=(T)EXTENSION_INSTANCES.get(clazz);如果(实例==null){EXTENSION_INSTANCES.putIfAbsent(clazz,clazz.newInstance());instance=(T)EXTENSION_INSTANCES.get(clazz);}/***如果实现类对象中有set方法,框架也会根据依赖对象的实际情况进行自动注入工作*注意只有满足以下两个条件才会进行注入:*1.依赖对象也在services、dubbo、internal这三个目录下*2.set方法上没有使用DisableInject注解*/injectExtension(instance);设置<类>wrapperClasses=cachedWrapperClasses;如果(wrapperClasses!=null&&!wrapperClasses.isEmpty()){for(ClasswrapperClass:wrapperClasses){instance=injectExtension((T)wrapperClass.getConstructor(type).newInstance(instance));}}返回实例;}catch(Throwablet){thrownewIllegalStateException("Extensioninstance(name:"+name+",class:"+type+")无法实例化:"+t.getMessage(),t);}}该方法的主要逻辑:1.通过Class.forName加载META-INF/services/、META-INF/dubbo/、META-INF/dubbo/internal/中的所有类2.通过反射创建对应的实例3到类型。如果满足注入条件,框架也会进行自动注入。最后用一张图来总结一下整个过程:创建对象后,会将对象放入缓存中,下次直接获取。

猜你喜欢