前言
今天在學習swagger源碼時,發現其中使用到了spring-plugin組件,github地址,
這個組件很小眾,在其他框架中也使用不多,它被稱為最小的插件系統。

簡單使用
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組件其實很小,一共也沒有幾個類
入口在於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。