Spring Plugin插件系统入门

前言

今天在学习swagger源码时,发现其中使用到了spring-plugin组件,github地址
这个组件很小众,在其他框架中也使用不多,它被称为最小的插件系统。

Spring Plugin插件系统入门

简单使用

maven依赖

<dependency>
   <groupId>org.springframework.plugin</groupId>
   <artifactId>spring-plugin-core</artifactId>
   <version>2.0.0.RELEASE</version>
</dependency>

定义接口

import org.springframework.plugin.core.Plugin;

public interface SmsService extends Plugin<String> {

  void sendSms(String mobile);
}

定义一个短信服务接口,接口必须继承Plugin接口

接口实现类

public class SmsServiceImpl implements SmsService {

  @Override
  public boolean supports(String s) {
    return s.startsWith("139");
  }

  @Override
  public void sendSms(String mobile) {
    if (supports(mobile)) {
      System.out.println("SmsServiceImpl 发送短信成功:" + mobile);
    }
  }
}
public class SmsServiceImpl2 implements SmsService {

  @Override
  public boolean supports(String s) {
    return s.startsWith("138");
  }

  @Override
  public void sendSms(String mobile) {
    if (supports(mobile)) {
      System.out.println("SmsServiceImpl2 发送短信成功:" + mobile);
    }
  }
}

定义两个短信服务实现类,一个支持发送139开头的手机号,一个支持发送138开头的手机号。

Spring配置

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.plugin.core.config.EnablePluginRegistries;

@Configuration
@EnablePluginRegistries(SmsService.class)
public class BeanConfig {

  @Bean
  public SmsServiceImpl smsService() {
    return new SmsServiceImpl();
  }

  @Bean
  public SmsServiceImpl2 smsService2() {
    return new SmsServiceImpl2();
  }
}

主要在于EnablePluginRegistries注解,用来注入PluginRegistry

客户端

import java.util.List;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.plugin.core.PluginRegistry;

public class Client {

  public static void main(String[] args) {
    ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
    PluginRegistry<SmsService, String> registry = context.getBean(PluginRegistry.class);
    List<SmsService> plugins = registry.getPlugins();
    for (SmsService plugin : plugins) {
      plugin.sendSms("1391xxxxxxxx");
      plugin.sendSms("1381xxxxxxxx");
    }
  }

}

spring-plugin会帮我们向IOC容器自动注入PluginRegistry,我们通过它来获取plugin。

源码分析

spring-plugin组件其实很小,一共也没有几个类

Spring Plugin插件系统入门

入口在于EnablePluginRegistries注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(PluginRegistriesBeanDefinitionRegistrar.class)
public @interface EnablePluginRegistries {

	/**
	 * The {@link Plugin} types to register {@link PluginRegistry} instances for. The registries will be named after the
	 * uncapitalized plugin type extended with {@code Registry}. So for a plugin interface {@code SamplePlugin} the
	 * exposed bean name will be {@code samplePluginRegistry}. This can be used on the client side to make sure you get
	 * the right {@link PluginRegistry} injected by using the {@link Qualifier} annotation and referring to that bean
	 * name. If the auto-generated bean name collides with one already in your application you can use the
	 * {@link Qualifier} annotation right at the plugin interface to define a custom name.
	 * 
	 * @return
	 */
	Class<? extends Plugin<?>>[] value();
}

跟进去PluginRegistriesBeanDefinitionRegistrar

public class PluginRegistriesBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

	private static final Logger LOG = LoggerFactory.getLogger(PluginRegistriesBeanDefinitionRegistrar.class);

	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

		//获取注解的各种属性
		Map<String, Object> annotationAttributes = importingClassMetadata
				.getAnnotationAttributes(EnablePluginRegistries.class.getName());

		if (annotationAttributes == null) {
			LOG.info("No EnablePluginRegistries annotation found on type {}!", importingClassMetadata.getClassName());
			return;
		}
		//获取value属性值,这里就是SmsService接口	
		Class<?>[] types = (Class<?>[]) annotationAttributes.get("value");

		for (Class<?> type : types) {
			//定义一个类型为PluginRegistryFactoryBean的bean,这是一个FactoryBean
			BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(PluginRegistryFactoryBean.class);
			builder.addPropertyValue("type", type);

			RootBeanDefinition beanDefinition = (RootBeanDefinition) builder.getBeanDefinition();
			beanDefinition.setTargetType(getTargetType(type));

			Qualifier annotation = type.getAnnotation(Qualifier.class);

			// If the plugin interface has a Qualifier annotation, propagate that to the bean definition of the registry
			if (annotation != null) {
				AutowireCandidateQualifier qualifierMetadata = new AutowireCandidateQualifier(Qualifier.class);
				qualifierMetadata.setAttribute(AutowireCandidateQualifier.VALUE_KEY, annotation.value());
				beanDefinition.addQualifier(qualifierMetadata);
			}

			// Default
			String beanName = annotation == null //
					? StringUtils.uncapitalize(type.getSimpleName() + "Registry") //
					: annotation.value();
                        //最终的名称为 smsServiceRegistry
			registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
		}
	}

	/**
	 * Returns the target type of the {@link PluginRegistry} for the given plugin type.
	 *
	 * @param pluginType must not be {@literal null}.
	 * @return
	 */
	private static ResolvableType getTargetType(Class<?> pluginClass) {

		Assert.notNull(pluginClass, "Plugin type must not be null!");

		ResolvableType delimiterType = ResolvableType.forClass(Plugin.class, pluginClass).getGeneric(0);
		ResolvableType pluginType = ResolvableType.forClass(pluginClass);

		return ResolvableType.forClassWithGenerics(OrderAwarePluginRegistry.class, pluginType, delimiterType);
	}
}

继续看PluginRegistry是如何被创建的

/**
 * {@link FactoryBean} to create {@link PluginRegistry} instances. Wraps a {@link BeanListFactoryBean}.
 *
 * @author Oliver Gierke
 */
public class PluginRegistryFactoryBean<T extends Plugin<S>, S> extends AbstractTypeAwareSupport<T>
		implements FactoryBean<PluginRegistry<T, S>> {

	/*
	 * (non-Javadoc)
	 * @see org.springframework.beans.factory.FactoryBean#getObject()
	 */
	@NonNull
	public OrderAwarePluginRegistry<T, S> getObject() {
		return OrderAwarePluginRegistry.of(getBeans());
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.beans.factory.FactoryBean#getObjectType()
	 */
	@NonNull
	public Class<?> getObjectType() {
		return OrderAwarePluginRegistry.class;
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.beans.factory.FactoryBean#isSingleton()
	 */
	public boolean isSingleton() {
		return true;
	}
}

最终的实现类为OrderAwarePluginRegistry。

参考

springfox 源码分析(三) 初探Spring Plugin插件系统
spring plugin

上一篇:注解与反射,测试用例


下一篇:Mybatis-Plus - 分页查询