• IOC


    IOC

    当我们调用createAdaptiveExtension或者getExtension->createExtension都会有IOC的操作,使用的injectExtension方法

    分析下这句调用

    MyProtocol myExt = ExtensionLoader.getExtensionLoader(MyProtocol.class).getExtension("myExt");

    getExtension方法

    public T getExtension(String name) {
        if (name == null || name.length() == 0)
            throw new IllegalArgumentException("Extension name == null");
        if ("true".equals(name)) {
            return getDefaultExtension();
        }
      	// 持有当前扩展对象
        Holder<Object> holder = cachedInstances.get(name);
        if (holder == null) {
            cachedInstances.putIfAbsent(name, new Holder<Object>());
            holder = cachedInstances.get(name);
        }
        Object instance = holder.get();
        if (instance == null) {
            synchronized (holder) {
                instance = holder.get();
                if (instance == null) {
                  	//创建扩展对象
                    instance = createExtension(name);
                    holder.set(instance);
                }
            }
        }
        return (T) instance;
    }
    

    createExtension方法

    private T createExtension(String name) {
        Class<?> clazz = getExtensionClasses().get(name);
        if (clazz == null) {
            throw findException(name);
        }
        try {
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
                EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
          	// 对目标对象进行IOC处理
            injectExtension(instance);
            Set<Class<?>> wrapperClasses = cachedWrapperClasses;
            if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
                for (Class<?> wrapperClass : wrapperClasses) {
                  	// 对AOP扩展类进行IOC处理
                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                }
            }
            return instance;
        } catch (Throwable t) {
            ...
        }
    }
    

    injectExtension

    private T injectExtension(T instance) {
        try {
            if (objectFactory != null) {
                for (Method method : instance.getClass().getMethods()) {
                  	// IOC处理的方法必须满足三个条件
                  	// 1. set开头 2. 一个参数 3. public方法
                    if (method.getName().startsWith("set")
                            && method.getParameterTypes().length == 1
                            && Modifier.isPublic(method.getModifiers())) {
    					// set方法上标有@DisableInject注解的跳过
                        if (method.getAnnotation(DisableInject.class) != null) {
                            continue;
                        }
                        Class<?> pt = method.getParameterTypes()[0];
                        try {
                          	// 方法名length> 3, 例如setStudent 那么property = student
                            String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
                          	// 这里的objectFactory是AdaptiveExtensionFactory对象
                          	//这个student就是扩展类的名称
                            Object object = objectFactory.getExtension(pt, property);
                            if (object != null) {
                               //从spring或者dubbo中获取到set方法的参数实例后设置给当前instance
                                method.invoke(instance, object);
                            }
                        } catch (Exception e) {
                            ...
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return instance;
    }
    

    AdaptiveExtensionFactory

    @Adaptive
    public class AdaptiveExtensionFactory implements ExtensionFactory {
    
        private final List<ExtensionFactory> factories;
    
        //该方法用来初始化factories
        public AdaptiveExtensionFactory() {
          	// 加载ExtensionFactory类型
            ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
            List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
          	//1. 获取除了@Adaptive修饰的类和AOP扩展类之外的所有扩展类的名字
            for (String name : loader.getSupportedExtensions()) {
              	//2. 根据名字获取扩展类
                list.add(loader.getExtension(name));
            }
          	// 将除了@Adaptive修饰的类和AOP扩展类之外的所有扩展类封装在list中赋值给factories
            factories = Collections.unmodifiableList(list);
        }
    
        @Override
        public <T> T getExtension(Class<T> type, String name) {
            for (ExtensionFactory factory : factories) {
              	// 获取扩展类
                T extension = factory.getExtension(type, name);
                if (extension != null) {
                    return extension;
                }
            }
            return null;
        }
    
    }
    

    我们看到这个类上有个@Adaptive注解 那么调用getAdaptiveExtension方法时,就返回的它本身,在调用createAdaptiveExtension时,会创建该类的实例(调用构造方法)

    1、将SpiExtensionFactory和SpringExtensionFactory方在了factories中

    2、然后可以通过getExtension方法使用SpiExtensionFactory和SpringExtensionFactory分别获取dubbo扩展类和spring管理的类

    SpiExtensionFactory

    /**
     * 从dubbo中获取扩展类,需要注入的方法参数为@SPI标识的接口, 同时有普通的扩展类
     * 获取的扩展类是动态类型
     * SpiExtensionFactory
     */
    public class SpiExtensionFactory implements ExtensionFactory {
    
        @Override
        public <T> T getExtension(Class<T> type, String name) {
            // 注入的类型必须是接口,同时要被@SPI标识
            if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
                ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
                if (!loader.getSupportedExtensions().isEmpty()) {
                    return loader.getAdaptiveExtension();
                }
            }
            return null;
        }
    }
    

    上面说的普通的扩展类是指除了AOP类型(一般名字以Wrapper结尾),@Adaptive标识的类之外的其它所有类.

    我们发现上面获取的扩展类是getAdaptiveExtension动态生成的,那么就要求要么该类是被@Adaptive标识,

    要么就有个方法被@Adaptive标识,而且被@Adaptive标识的方法的参数有个限制条件

    1、必须有一个URL参数

    2、或者参数中有个对象包含pubilc URL getXXX();这种签名的方法;

    ? 该方法满足:1. public, 2.不带static, 3. get方法,4.没有参数,5. get方法的XXX不能为空

    那么在我们了解到IOC的原理后,自己写一个测试。

    自定义IOC应用

    接着AOP的demo继续写

    1. 自定义一个协议
    // 设置默认扩展类型
    @SPI(value = MyExtProtocol.NAME)
    public interface MyProtocol {
    
        String getName();
    }
    
    1. 默认扩展类(目标执行的扩展类)
    public class MyExtProtocol implements MyProtocol {
      
        public static final String NAME = "myExt";
      
        @Override
        public String getName() {
            System.out.println("MyExtProtocol.getName" + "目标方法被调用");
            return "MyExtProtocol.getName";
        }
    }
    
    1. AOP类型
    /**
     * MyProtocol类型的AOP扩展类
     * 与目标扩展类实现同一个接口
     */
    public class MyProtocolWrapper implements MyProtocol {
    
      	/**
      	 * AOP链式调用中的一节,这里我们只有一个AOP扩展类,故这个就是目标扩展类
      	 */
        private MyProtocol myProtocol;
    
       /**
         * 使用SpiExtensionFactory注入的dubbo扩展对象
         */
        private MySpringIOC mySpringIOC;
    
        /**
         * 使用SpringExtensionFactory注入的spring中的对象
         */
        private DubboIOC dubboIOC;
      
        public MyProtocolWrapper(MyProtocol myProtocol) {
            this.myProtocol = myProtocol;
        }
    
        @Override
        public String getName() {
            System.out.println("MyProtocolWrapper.getName === " + "前置方法被调用");
            String name = myProtocol.getName();
            System.out.println("MyProtocolWrapper.getName === " + "后置方法被调用");
          
     		iocInvoke();
            return name;
        }
       
       /**
        * dubboIOC是通过IOC注入的,它会是个动态扩展类,调用dubboIOC.sayHello(url);时会从URL中获取
        * 扩展类的名称,然后通过这个名称获取到扩展类实例, 调用目标扩展类的sayHello方法
        */
       public void iocInvoke() {
         mySpringIOC.say();
            URL url = URL.valueOf("registry://192.168.1.7:9090/com.alibaba.service1?param1=value1&amp;param2=value2&defaultIOC=myDubboIOC");
            dubboIOC.sayHello(url);
       }
      
       public MySpringIOC getMySpringIOC() {
            return mySpringIOC;
        }
    
        public void setMySpringIOC(MySpringIOC mySpringIOC) {
            this.mySpringIOC = mySpringIOC;
        }
    
        public DubboIOC getDubboIOC() {
            return dubboIOC;
        }
    
        public void setDubboIOC(DubboIOC dubboIOC) {
            this.dubboIOC = dubboIOC;
        }
    }
    

    ? 将IOC需要注入的参数写在了AOP扩展类中(当然你也可以写在目标类中)

    1. IOC注入的类型
    @SPI
    public interface DubboIOC {
    
        @Adaptive(value = "defaultIOC")
        void sayHello(URL url);
    
    }
    

    满足了 1.注入的类型接口被@SPI标识, 2,接口被@Adaptive标识或者接口中有方法被@Adaptive标识
    @Adaptive中的value是文件中配置的扩展类配置的别名在URL中的kye
    比如: URL = "registry://192.168.1.7:9090/com.alibaba.service1?defaultIOC=myDubboIOC"
    那么value应该为defaultIOC,然后会调用动态类中同名函数的如下语句

    String extName = url.getParameter("defaultIOC");  //获得扩展类的别名
    ExtensionLoader.getExtensionLoader(DubboIOC.class).getExtension(extName); //通过扩展类别名获取扩展类
    

    ? 3.如果是方法被@Adaptive标识, 该方法中有个参数为URL或参数的返回值是url的方法
    5. 扩展实现类

    public class MyDubboIOC implements DubboIOC {
    
        @Override
        public void sayHello(URL url) {
            System.out.println(url+ "==================");
            System.out.println("MyDubboIOC.sayHello ...........hello");
        }
    }
    
    public class MySpringIOC {
    
        public void say() {
            System.out.println("MySpringIOC.say=======");
        }
    }
    
    1. 扩展类配置文件

    per.qiao.myprotocol.MyProtocol

    #  目标扩展类
    myExt=per.qiao.myprotocol.impl.MyExtProtocol
    # AOP类型
    myWrapper=per.qiao.myprotocol.wrapper.MyProtocolWrapper
    

    per.qiao.myprotocol.DubboIOC

    myDubboIOC=per.qiao.myprotocol.myioc.MyDubboIOC
    

    然后在spring的配置文件中写通过SpringExtensionFactory注入

    <bean id="mySpringIOC" class="per.qiao.myprotocol.myioc.MySpringIOC"/>
    
    1. 调用
    MyProtocol myExt = ExtensionLoader.getExtensionLoader(MyProtocol.class).getExtension("myExt");
    myExt.getName();
    

    这样就写完了。

    总结:

    ? 自定协议:接口需要@SPI标识

    ? 自定义IOC:得满足需要注入的参数是Spring中的Bean或者dubbo中的扩展类

    ? 1. 如果是扩展类, 那么方法名set的后面对应的就是扩展名的名字,比如注入的方法名为:setMyIOC,那么必须有个扩展类与之对应 配置文件中 myIOC = xxx.xxx.xxIOC

    	2.  扩展类要么被@Adaptive修饰,要么有方法被@Adaptive修饰,
    

    ? 如果@Adaptive有value值,那么它就是URL中的一个参数的key,通过这个key从URL中获取value,那么这个value就是目标扩展类配置的名字 通过

    String extName = url.getParameter("@Adaptive中的value值"); //获得扩展类的别名
    ExtensionLoader.getExtensionLoader(DubboIOC.class).getExtension(extName);

    ? 如果@Adaptive没有value值, 那么默认的value就为接口名首字母小写

    关于@Adaptive注解,可以参考 关于@Adaptive注解

  • 相关阅读:
    淘宝从几百到千万级并发的十四次架构演进之路!
    19 个强大、有趣、好玩、又装B的 Linux 命令!
    Spring Boot实战:拦截器与过滤器
    初识zookeeper,linux 安装配置zookeeper
    Spring-boot:5分钟整合Dubbo构建分布式服务
    Spring-Boot:6分钟掌握SpringBoot开发
    Dubbo的使用及原理浅析.
    Java消息队列--ActiveMq 初体验
    关于Ubuntu 常用的简单指令
    IBM、HPUX、Solaris不同之处
  • 原文地址:https://www.cnblogs.com/qiaozhuangshi/p/11007079.html
Copyright © 2020-2023  润新知