Dubbo IOC AOP的实现
Posted 技术无产者
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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的IOC 和AOP必须配合SPI机制来使用,因为是在实现SPI代码中扩展的IOC AOP
以上是关于Dubbo IOC AOP的实现的主要内容,如果未能解决你的问题,请参考以下文章