Dubbo IOC AOP的实现

一.IOC

   Dubbo在SPI机制中实现了IOC功能, Dubbo IOC的主干业务逻辑就是在injectExtension方法中,

下面是对Dubbo IOC业务逻辑的梳理:

对于SPI中创建的任何对象都会判断是否有set开头的方法,然后进行IOC

 1. Dubbo的IOC是怎么获取对象的:

    当通过SPI机获取对象时,如果发现该类有set开头的方法,就会调用injectExtension方法,为其注入属性值, 被注入属性的对象有两类:

    1>该类/接口上有@SPI注解,则会通过SpiExtensionFactory来获取对象,并进行注入,具体使用方式如下:

//接口
@SPI
public interface Animal {
    public void speak();

    @Adaptive("friend")
    public void speak(URL url);
}

// 实现类
public class Cat implements Animal{
    @Override
    public void speak() {
        System.out.println("I'm a cat");
    }

    @Override
    public void speak(URL url) {
        System.out.println("I'm cat");
    }
}


public class Bird implements Animal{

    private Animal friend;

    public void setFriend(Animal friend) {
        this.friend = friend;
    }

    @Override
    public void speak() {
        System.out.println("I'm a bird");
      }

    @Override
    public void speak(URL url) {
        friend.speak(url);
    }

}


//测试类

public static void main(String[] args) {
    ExtensionLoader<Animal> extensionLoader = ExtensionLoader.getExtensionLoader(Animal.class);
    Animal animal = extensionLoader.getExtension("bird");

    Map<String,String> map = new HashMap<>();
    map.put("friend","cat");
    URL url = new URL("","",1,map);

    animal.speak(url);
}

// 代码摘自: https://blog.csdn.net/huangyu1985/article/details/104889081

2>如果没有@SPI注解,就会通过SpringExtensionFactory来获得该类的实例,因为Dubbo的实例对象本来就是通过Spring来管理的

   这里看下SpringExtensionFactory中的部分代码,如果看过Spring源码的可以知道,可以通过BeanPostProcessor来扩展对象,这里通过Spring的beanFactory来获取对象,Spring中的对象都是通过getBean来获取的,这个BeanFactory是通过继承ApplicationContextAware接口来获得的

 在spring的配置文件中,配置一个Bean对象 就可以通过 SpringExtensionFactory获得

beanFactory.getBean(beanNamesForType[0], type);

private <T> T getOptionalBean(ListableBeanFactory beanFactory, String name, Class<T> type) {
        if (StringUtils.isEmpty(name)) {
            String[] beanNamesForType = beanFactory.getBeanNamesForType(type, true, false);
            if (beanNamesForType != null) {
                if (beanNamesForType.length == 1) {
                    return beanFactory.getBean(beanNamesForType[0], type); //注意看这
                } else if (beanNamesForType.length > 1) {
                    throw new IllegalStateException("Expect single but found " + beanNamesForType.length + " beans in spring context: " +
                        Arrays.toString(beanNamesForType));
                }
            }
        } else {
            if (beanFactory.containsBean(name)) {
                return beanFactory.getBean(name, type);
            }
        }
        return null;
    }

2.上面介绍了Dubbo IOC通过什么获取注入的对象,接着这里介绍,怎么获取SpiExtensionFactory和SpringExtensionFactory对象的

       objectFactory是AdaptiveExtensionFactory实例,AdaptiveExtensionFactory,SpiExtensionFactory和SpringExtensionFactory都实现接口,而AdaptiveExtensionFactory类上面有个@Adaptive注解,所以它是个代理类,里面维护了一个list,里面存了SpiExtensionFactory和SpringExtensionFactory,通过objectFactory.getExtension获得某个类的实例时,他会挨着尝试使用这两个类来获取指定类的实例。

注意 Object object = objectFactory.getExtension(pt, property);这行代码,他就是用来获得具体实现类的,

private T injectExtension(T instance) {
    try {
        if (objectFactory != null) {
            // 遍历目标类的所有方法
            for (Method method : instance.getClass().getMethods()) {
                // 检测方法是否以 set 开头,且方法仅有一个参数,且方法访问级别为 public
                if (method.getName().startsWith("set")
                    && method.getParameterTypes().length == 1
                    && Modifier.isPublic(method.getModifiers())) {
                    // 获取 setter 方法参数类型
                    Class<?> pt = method.getParameterTypes()[0];
                    try {
                        // 获取属性名,比如 setName 方法对应属性名 name
                        String property = method.getName().length() > 3 ? 
                            method.getName().substring(3, 4).toLowerCase() + 
                            	method.getName().substring(4) : "";
                        // 从 ObjectFactory 中获取依赖对象
//  =================== 注意 =========================
                        Object object = objectFactory.getExtension(pt, property);
                        if (object != null) {
                            // 通过反射调用 setter 方法设置依赖
                            method.invoke(instance, object);
                        }
                    } catch (Exception e) {
                        logger.error("fail to inject via method...");
                    }
                }
            }
        }
    } catch (Exception e) {
        logger.error(e.getMessage(), e);
    }
    return instance;
}

参考:

dubbo系列(三) DUBBO IOC、AOP_宇的博客-CSDN博客1. 介绍  在dubbo系列上一篇文章中已经介绍了SPI的基本使用,我们可以创建指定的扩展点对象,那如果扩展点中包含另一个扩展点属性,属性是如何创建的,如果我们期望在扩展点目标方法前后增加切面,dubbo又是如何处理的,本章将介绍这些内容。2.Dubbo IOC示例  业务场景说明:bird有一个Animal属性,我们在运行时会通过Url总线设置这个属性的类型为cat,然后通过bird调用...https://blog.csdn.net/huangyu1985/article/details/104889081 Dubbo IOC源码分析_wangxuelei036的博客-CSDN博客_dubbo ioc这里我们先回顾以下之前得dubbo实例化对象的过程:看个小离职Dubbo IOC原理  熟悉spring的同学应该清楚,在spring的ioc中,例如A中有B属性,那么要注入B,会通过xml或注解指定B的引用,然后在A实例化时,会通过指定的引用实例化B。但是在上面的例子中,在我们创建bird扩展点时,并没有指定friend属性的类型,而是在运行speak方法时,通过url参数指定了friend的类型,这个动作似乎和上一篇文章介绍的自适应扩展点很相似,没错,dubbo的ioc就是通过自适应.https://blog.csdn.net/wangxuelei036/article/details/106827665

 二.AOP

      包装类是因为一个扩展接口可能有多个扩展实现类,而这些扩展实现类会有一个相同的或者公共的逻辑,如果每个实现类都写一遍代码就重复了,并且比较不好维护。

     因此就搞了个包装类,Dubbo 里帮你自动包装,只需要某个扩展类的构造函数只有一个参数,并且是扩展接口类型,就会被判定为包装类,然后记录下来,用来包装别的实现类。
比较简单,具体可以参考:

dubbo系列(三) DUBBO IOC、AOP_宇的博客-CSDN博客1. 介绍  在dubbo系列上一篇文章中已经介绍了SPI的基本使用,我们可以创建指定的扩展点对象,那如果扩展点中包含另一个扩展点属性,属性是如何创建的,如果我们期望在扩展点目标方法前后增加切面,dubbo又是如何处理的,本章将介绍这些内容。2.Dubbo IOC示例  业务场景说明:bird有一个Animal属性,我们在运行时会通过Url总线设置这个属性的类型为cat,然后通过bird调用...https://blog.csdn.net/huangyu1985/article/details/104889081

注意Dubbo的IOC 和AOP必须配合SPI机制来使用,因为是在实现SPI代码中扩展的IOC AOP

Dubbo SPI使用示例(含AOP和IOC机制示例)_诺浅的专栏-CSDN博客_dubbo spi使用为什么要写这篇文章百度或者Google搜Dubbo SPI机制,出来的基本都是列出来一个很简单的例子,然后开始对源码解析,但是源码解析的时候又会涉及到Dubbo SPI的AOP和IOC机制,所以让人看的云里雾里,本文旨在通过几个简单的例子,带你了解Dubbo SPI的基本使用,本文会举三个例子,分别讲述普通的使用方式,AOP机制,IOC机制。要运行这些例子你需要先引入Dubbo的jar包。Dubbo SPI普通的使用方式新建一个接口Robot,并加上@SPI注解来表示这是一个扩展点@SPIpublhttps://blog.csdn.net/qq32933432/article/details/108345760

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值