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 文件内容
查看 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();
- 本文标签: Dubbo Spring Boot
- 版权声明: 本站原创文章,于2021年03月05日由风杨发布,转载请注明出处