原创

Dubbo 拦截器Filter实现类中 注入 Spring 类

现象

dubbo的设计思路是微内核+插件,Filter等插件被dubbo创建,而不是被spring创建。Filter和spring两不相认。

在开发功能时,经常需要使用dubbo的filter进行一些全局处理。于是在实现接口org.apache.dubbo.rpc.Filter后,按照正常思路添加了属性,代码如下:

@Slf4j
@Activate(group = {Constants.PROVIDER})
public class DubboOpsACContextFilter implements Filter {
    @Autowired
    private IAgentAccountService agentAccountService;
}

在invoke方法里使用到该 agentAccountService 时,agentAccountService一定为NULL!

那 如果想在Filter中使用被spring管理的对象,注入spring的bean,怎么办?

处理方式

Set 方法

在dubbo的拦截器中,可以采取通过setter方式来注入其他的bean,且不要标注注解!
dubbo自己会对这些bean进行注入。

@Slf4j
@Activate(group = {Constants.PROVIDER})
public class DubboOpsACContextFilter implements Filter {
    @Setter
    private IAgentAccountService agentAccountService;
}

切记:set注入注意方法名的规范!!!

从spring 上下文中取

自定义 ApplicationContext 并取实例对象即可。

源码分析

ExtensionLoader.getExtension(String name)

Dubbo SPI扩展点的入口为 ExtensionLoader, 因此分析也从 ExtensionLoader 开始。

Filter 插件也是被 Dubbo SPI机制管理,org.apache.dubbo.common.extension.ExtensionLoader<T> 的public T getExtension(String name)函数被用于加载特定的插件,其中有一层缓存,真正的创建过程在private T createExtension(String name, boolean wrap)函数中。

public T getExtension(String name) {
        return getExtension(name, true);
    }

    public T getExtension(String name, boolean wrap) {
        if (StringUtils.isEmpty(name)) {
            throw new IllegalArgumentException("Extension name == null");
        }
        if ("true".equals(name)) {
            return getDefaultExtension();
        }
        final Holder<Object> holder = getOrCreateHolder(name);
        Object instance = holder.get();
        if (instance == null) {
            synchronized (holder) {
                instance = holder.get();
                if (instance == null) {
                    instance = createExtension(name, wrap);
                    holder.set(instance);
                }
            }
        }
        return (T) instance;
    }

ExtensionLoader.createExtension(String name, boolean wrap)

createExtension(String name, boolean wrap) 函数源码如下

private T createExtension(String name, boolean wrap) {
        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);
            }
            injectExtension(instance);

            if (wrap) {
                List<Class<?>> wrapperClassesList = new ArrayList<>();
                if (cachedWrapperClasses != null) {
                    wrapperClassesList.addAll(cachedWrapperClasses);
                    wrapperClassesList.sort(WrapperComparator.COMPARATOR);
                    Collections.reverse(wrapperClassesList);
                }

                if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
                    for (Class<?> wrapperClass : wrapperClassesList) {
                        Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
                        if (wrapper == null
                                || (ArrayUtils.contains(wrapper.matches(), name) && !ArrayUtils.contains(wrapper.mismatches(), name))) {
                            instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                        }
                    }
                }
            }

            initExtension(instance);
            return instance;
        } catch (Throwable t) {
            throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
                    type + ") couldn't be instantiated: " + t.getMessage(), t);
        }
    }

其中的主要步骤:

  • 调用Class的newInstance()方法,实例化插件
  • 调用ExtensionLoader<T>的injectExtension(T instance),从objectFactory中拿一个bean,调用插件的setter方法
  • 处理wrapper

ExtensionLoader.injectExtension(T instance)

private T injectExtension(T instance) {

        if (objectFactory == null) {
            return instance;
        }

        try {
            for (Method method : instance.getClass().getMethods()) {
                if (!isSetter(method)) {
                    continue;
                }
                /**
                 * Check {@link DisableInject} to see if we need auto injection for this property
                 */
                if (method.getAnnotation(DisableInject.class) != null) {
                    continue;
                }
                Class<?> pt = method.getParameterTypes()[0];
                if (ReflectUtils.isPrimitives(pt)) {
                    continue;
                }

                try {
                    String property = getSetterProperty(method);
                    Object object = objectFactory.getExtension(pt, property);
                    if (object != null) {
                        method.invoke(instance, object);
                    }
                } catch (Exception e) {
                    logger.error("Failed to inject via method " + method.getName()
                            + " of interface " + type.getName() + ": " + e.getMessage(), e);
                }

            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return instance;
    }

其中的主要步骤:

  • 遍历方法
  • 如果方法不是 setter方法则忽略(即,方法名以“set”开头,有1个参数,是public)。
    method.getName().startsWith("set") && method.getParameterTypes().length == 1 && Modifier.isPublic(method.getModifiers())

  • 如果方法是 @DisableInject 修饰的,则为忽略。

  • 根据 method 得到属性名
  • 从objectFactory中得到bean
  • 调用setter。 method.invoke

objectFactory 从何处来?

objectFactory是 ExtensionFactory 接口类型的, 该定义在 ExtensionLoader 中被定义为 private final ,objectFactory 初始化来自 ExtensionLoader 私有构造函数。

public class ExtensionLoader<T> {
    ......
    private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<>(64);
    private final Class<?> type;

    private final ExtensionFactory objectFactory;

    private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<>();
    ......

    private ExtensionLoader(Class<?> type) {
        this.type = type;
            objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }

    ......

org.apache.dubbo.config.spring.extension.SpringExtensionFactory 是 ExtensionFactory 接口的一个实现类。

接口 ExtensionFactory

只有一个方法

@SPI
public interface ExtensionFactory {

    /**
     * Get extension.
     *
     * @param type object type.
     * @param name object name.
     * @return object instance.
     */
    <T> T getExtension(Class<T> type, String name);

}

按照dubbo的SPI机制,见 META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionFactory 文件内容
file

查看 SpringExtensionFactory 源码

    private static final Set<ApplicationContext> CONTEXTS = new ConcurrentHashSet<ApplicationContext>();

    public static void addApplicationContext(ApplicationContext context) {
        CONTEXTS.add(context);
        if (context instanceof ConfigurableApplicationContext) {
            ((ConfigurableApplicationContext) context).registerShutdownHook();
        }
    }


    public <T> T getExtension(Class<T> type, String name) {
        //SPI should be get from SpiExtensionFactory
        if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
            return null;
        }

        for (ApplicationContext context : CONTEXTS) {
            T bean = BeanFactoryUtils.getOptionalBean(context, name, type);
            if (bean != null) {
                return bean;
            }
        }

        //logger.warn("No spring extension (bean) named:" + name + ", try to find an extension (bean) of type " + type.getName());

        return null;
    }

其中查找逻辑:

  • 如果为接口或者 SPI注解,返回 null
  • 遍历ApplicationContext
  • 先按名字找bean,要求类型必须正确.
  • 找到则返回。 找不到则返回 null

Dubbo 本身与Spring无关, addApplicationContext(ApplicationContext context)是在哪儿设置的?

dubbo-spring(dubbo-spring-boot-autoconfigure) 初始化入口为 DubboAutoConfiguration, 该类实现了 dubbo 与 Spring 的无缝融合。

/**
 * Dubbo Auto {@link Configuration}
 *
 * @see DubboReference
 * @see DubboService
 * @see ServiceClassPostProcessor
 * @see ReferenceAnnotationBeanPostProcessor
 * @since 2.7.0
 */
@ConditionalOnProperty(prefix = DUBBO_PREFIX, name = "enabled", matchIfMissing = true)
@Configuration
@AutoConfigureAfter(DubboRelaxedBindingAutoConfiguration.class)
@EnableConfigurationProperties(DubboConfigurationProperties.class)
@EnableDubboConfig
public class DubboAutoConfiguration implements ApplicationContextAware, BeanDefinitionRegistryPostProcessor {
    ......
}

查找 SpringExtensionFactory 被调用的地方,涉及 ConfigCenterBean、ReferenceBean 和 ServiceBean。且三个类均实现了 ApplicationContextAware 接口。
在这三个类的 setApplicationContext 方法中,进行了 addApplicationContext 操作。

@Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        SpringExtensionFactory.addApplicationContext(applicationContext);
    }

ReferenceBean 类的实例化

通过 ReferenceBeanBuilder 的 build 方法

ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder
                    .create(attributes, applicationContext)
                    .interfaceClass(referencedType);
            referenceBean = beanBuilder.build();
正文到此结束
广告是为了更好的提供数据服务
本文目录