码迷,mamicode.com
首页 > 其他好文 > 详细

IOC

时间:2019-06-12 00:49:08      阅读:91      评论:0      收藏:0      [点我收藏+]

标签:ram   ret   分析   dex   ble   ann   url参数   文件   null   

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的方法

  1. 扩展实现类
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注解

IOC

标签:ram   ret   分析   dex   ble   ann   url参数   文件   null   

原文地址:https://www.cnblogs.com/qiaozhuangshi/p/11007079.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!