zoukankan      html  css  js  c++  java
  • dubbo

    java spi 机制 java会加载解析项目或者jar包下如:resourcesMETA-INFservicesxyz.luofu.www.CarService(文件)路径下的文件,用户可根据这个特点开发一些可插拔的组件,目录结构及文件:


    文件内容:

    xyz.luofu.www.RedCar
    xyz.luofu.www.BlueCar
    
    public class App 
    {
        public static void main( String[] args )
        {
            ServiceLoader<CarService> serviceLoads = ServiceLoader.load(CarService.class); @1
    
            Iterator<CarService> iterator = serviceLoads.iterator(); //iterator 从这里点进去发现实现了Iterator里面的hasNext,next
            while (iterator.hasNext()){ @2
                CarService next = iterator.next();
                next.color();
            }
    }
    public class BlueCar implements CarService {
        @Override
        public void color() {
            System.out.println("blue");
        }
    }
    public class RedCar implements CarService {
        @Override
        public void color() {
            System.out.println("red");
        }
    }
    

    接着简单分析下java的spi源码

    @1 public static <S> ServiceLoader<S> load(Class<S> service) {
            ClassLoader cl = Thread.currentThread().getContextClassLoader();
            return ServiceLoader.load(service, cl)->ServiceLoader<>(service, loader)
        }
    private ServiceLoader(Class<S> svc, ClassLoader cl) {
            service = Objects.requireNonNull(svc, "Service interface cannot be null"); //service即我们传进去的接口
            loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
            acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
            reload();
        }
    public void reload() {
            providers.clear(); //providers 中存的是接口实现类 此处先清空
            lookupIterator = new LazyIterator(service, loader);
        }
    @2 public Iterator<S> iterator() {...
                public boolean hasNext() {...
                    return lookupIterator.hasNext()->hasNextService(){...
                      pending = parse(service, configs.nextElement());//解析文件中的每一行
                    }
                      nextName = pending.next();//文件中的每一行
                ...}
                }
                public S next() {...
                    return lookupIterator.next()->nextService(){...   
                          tring cn = nextName;
                      Class<?> c = null;
                      try {
                          c = Class.forName(cn, false, loader);//根据全类名获取类
                      } catch (ClassNotFoundException x) {
                          S p = service.cast(c.newInstance());//实例化
                          providers.put(cn, p);
                      ...}
    

    dubbo SPI及AOP、IOC实现

    public class App 
    {
        public static void main( String[] args )
        {
            ExtensionLoader<CarService> extensionLoader = ExtensionLoader.getExtensionLoader(CarService.class); //会检查接口类SPI注解 @1
            extensionLoader.getExtension("red"); @2
            System.out.println( "Hello World!" );
        }
    }
    @1 getExtensionLoader{...
          ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type); //ExtensionLoader 类拓展加载器
            if (loader == null) {
                EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type)); //有就取,没有就初始化并且放入一个map
                loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
            }
            return loader;
    ...}
    private ExtensionLoader(Class<?> type) {
            this.type = type; //接口类
            objectFactory = (type == ExtensionFactory.class ? null :                   ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); //初始化objectFactory @5
        }
    @5 getAdaptiveExtension{...
          instance = createAdaptiveExtension()->getAdaptiveExtensionClass{...
                getExtensionClasses();
                if (cachedAdaptiveClass != null) {
                  return cachedAdaptiveClass;
                }
                return cachedAdaptiveClass = createAdaptiveExtensionClass();//如果没有Adaptive注解的代理实现类则默认创建一个@6
          ...} ->getExtensionClasses()->..{
                if (clazz.isAnnotationPresent(Adaptive.class)) {
                      if (cachedAdaptiveClass == null) {
                          cachedAdaptiveClass = clazz;  //如果一个子类有 Adaptive注解则认为是接口代理类实现并且放入set,后面   
    }
    ...}
    @2 getExtension{...
          instance = createExtension(name); //获取拓展点实现类
    ...}
    createExtension{...
          Class<?> clazz = getExtensionClasses().get(name);
          try {
                T instance = (T) EXTENSION_INSTANCES.get(clazz); //dubbo会有很多类似的缓存结构数据
                if (instance == null) {
                    EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
                    instance = (T) EXTENSION_INSTANCES.get(clazz);
                }
                injectExtension(instance); //这里面处理生成代理实现类 @7
                Set<Class<?>> wrapperClasses = cachedWrapperClasses;
                if (wrapperClasses != null && !wrapperClasses.isEmpty()) { @4
                    for (Class<?> wrapperClass : wrapperClasses) {
                      //这里传red对应的instance实现类返回wrapper,并且循环所有wrapper完成AOP
                        instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                    }
                }
                return instance;
    ...}
    getExtensionClasses->loadExtensionClasses{...
          final SPI defaultAnnotation = type.getAnnotation(SPI.class);
            if (defaultAnnotation != null) {
                String value = defaultAnnotation.value();
                if ((value = value.trim()).length() > 0) {
                    String[] names = NAME_SEPARATOR.split(value);...
                    if (names.length == 1) {
                        cachedDefaultName = names[0];
                    }...
            Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
            //这里会加载几个位置的文件 DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";
            loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName());
            loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
            //加载DUBBO_DIRECTORY = "META-INF/dubbo/";
            loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName());
            loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
            //加载SERVICES_DIRECTORY = "META-INF/services/";
            loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName());
            loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
            
    ...}
    loadDirectory->loadResource{... //这里会把拓展文件传过来,然后读取每一行解析文件
        line = line.substring(i + 1).trim();
        if (line.length() > 0) {
            loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name);                      
    ...}
    
    loadClass{
            if (!type.isAssignableFrom(clazz)) { //校验解析类是否是接口类实现类
                throw new IllegalStateException("Error when load extension class(interface: " +
                        type + ", class line: " + clazz.getName() + "), class "
                        + clazz.getName() + "is not subtype of interface.");
            }
            if (clazz.isAnnotationPresent(Adaptive.class)) {
                if (cachedAdaptiveClass == null) {
                    cachedAdaptiveClass = clazz;
                } else if (!cachedAdaptiveClass.equals(clazz)) {
                    throw new IllegalStateException("More than 1 adaptive class found: "
                            + cachedAdaptiveClass.getClass().getName()
                            + ", " + clazz.getClass().getName());
                }
            } else if (isWrapperClass(clazz)) { //AOP实现 isWrapperClass-> clazz.getConstructor(type) 判断是否有接口参数的构造 @4
                Set<Class<?>> wrappers = cachedWrapperClasses;
                if (wrappers == null) {
                    cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
                    wrappers = cachedWrapperClasses;
                }
                wrappers.add(clazz); //添加AOP集合 AOP最后类似装饰器模式
            } else {
                clazz.getConstructor();...
                String[] names = NAME_SEPARATOR.split(name);
                if (names != null && names.length > 0) {...
                    for (String n : names) {
                        if (!cachedNames.containsKey(clazz)) {
                            cachedNames.put(clazz, n);
                        }
                        Class<?> c = extensionClasses.get(n);
                        if (c == null) {
                            extensionClasses.put(n, clazz); //把生成的类放进...
        }
    @7 injectExtension{...
          if (objectFactory != null) { //这里的objectFactory 生成于 @5
                    for (Method method : instance.getClass().getMethods()) {
                      try {
                                String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() +             method.getName().substring(4) : "";
                                Object object = objectFactory.getExtension(pt, property); //通过这里进行代理实现类的关联 @8
    ...}
    @6 createAdaptiveExtensionClass{...//生成一个代理类并且编译(得到Url中的属性参数,如:@Adaptive("red") 然后得到getExtension(String))
    String code = createAdaptiveExtensionClassCode();
            ClassLoader classLoader = findClassLoader();
            org.apache.dubbo.common.compiler.Compiler compiler =             ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
            return compiler.compile(code, classLoader);
    ...}
    createAdaptiveExtensionClassCode{...
          //解析接口方法上是否有Adaptive这个注解如果没有则生成的代理调用时会抛异常,生成的代理类可用Arthas 
          //Arthas(阿尔萨斯)是阿里巴巴开源的 Java 诊断工具 在线查看     
          Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class); 
                StringBuilder code = new StringBuilder(512);
                if (adaptiveAnnotation == null) {
                    code.append("throw new UnsupportedOperationException("method ")
    ...}
    @8 可以知道objectFactory的代理实现类为AdaptiveExtensionFactory(有@Adaptive修饰)
    @Override
        public <T> T getExtension(Class<T> type, String name) {
            for (ExtensionFactory factory : factories) {//SpiExtensionFactory
                T extension = factory.getExtension(type, name);
                if (extension != null) {
                    return extension;
                }
            }
            return null;
        }
    public class SpiExtensionFactory implements ExtensionFactory {
        @Override
        public <T> T getExtension(Class<T> type, String name) {
            if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
                ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
                if (!loader.getSupportedExtensions().isEmpty()) {
                    return loader.getAdaptiveExtension();
                }
            }
            return null;
        }
    
    }
    
    

    IOP部分相关代码:

    @SPI
    public interface CarService {
        @Adaptive("red")
        public void color(URL url);
    }
    
  • 相关阅读:
    案例分享:Qt+Arm基于RV1126平台的内窥镜软硬整套解决方案(实时影像、冻结、拍照、录像、背光调整、硬件光源调整,其他产品也可使用该平台,如视频监控,物联网产品等等)
    libzip开发笔记(二):libzip库介绍、ubuntu平台编译和工程模板
    案例分享:Qt西门子机床人机界面以及数据看板定制(西门子通讯,mysql数据库,生产信息,参数信息,信息化看板,权限控制,播放器,二维图表,参数调试界面)
    sshpass 简介
    SSH 协议及 OpenSSH 实现
    Linux从头学07:中断那么重要,它的本质到底是什么?
    Linux从头学06:16张结构图,彻底理解【代码重定位】的底层原理
    Linux从头学05-系统启动过程中的几个神秘地址,你知道是什么意思吗?
    所有编程语言中的栈操作,底层原理都在这里
    WSL2:Windows 亲生的 Linux 子系统
  • 原文地址:https://www.cnblogs.com/leifonlyone/p/12862590.html
Copyright © 2011-2022 走看看