前言
今天在学习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。
参考
springfox 源码分析(三) 初探Spring Plugin插件系统
spring plugin