com.github.dadiyang.httpinvoker.spring.ClassPathHttpApiScanner Maven / Gradle / Ivy
package com.github.dadiyang.httpinvoker.spring;
import com.github.dadiyang.httpinvoker.annotation.HttpApi;
import com.github.dadiyang.httpinvoker.propertyresolver.PropertyResolver;
import com.github.dadiyang.httpinvoker.requestor.RequestPreprocessor;
import com.github.dadiyang.httpinvoker.requestor.Requestor;
import com.github.dadiyang.httpinvoker.requestor.ResponseProcessor;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.*;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Set;
/**
* scan the given basePackages and register bean of includeAnn-annotated interfaces' implementation that HttpProxyBeanFactory generated
*
* @author huangxuyang
* date 2018/11/1
*/
public class ClassPathHttpApiScanner extends ClassPathBeanDefinitionScanner {
private static final String HTTP_API_PREFIX = "$HttpApi$";
private Class extends FactoryBean> factoryBean;
private Class extends Annotation> includeAnn;
private PropertyResolver propertyResolver;
private Requestor requestor;
private RequestPreprocessor requestPreprocessor;
private ResponseProcessor responseProcessor;
private BeanDefinitionRegistry registry;
public ClassPathHttpApiScanner(BeanDefinitionRegistry registry, PropertyResolver propertyResolver,
Requestor requestor, RequestPreprocessor requestPreprocessor,
ResponseProcessor responseProcessor) {
super(registry, false);
// use DefaultBeanNameGenerator to prevent bean name conflict
setBeanNameGenerator(new DefaultBeanNameGenerator());
this.registry = registry;
this.propertyResolver = propertyResolver;
this.factoryBean = HttpApiProxyFactoryBean.class;
this.includeAnn = HttpApi.class;
addIncludeFilter(new AnnotationTypeFilter(includeAnn));
this.requestor = requestor;
this.requestPreprocessor = requestPreprocessor;
this.responseProcessor = responseProcessor;
}
@Override
public Set doScan(String... basePackages) {
Set beanDefinitions = super.doScan(basePackages);
if (beanDefinitions.isEmpty()) {
logger.warn("No " + includeAnn.getSimpleName() + " was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
}
return beanDefinitions;
}
/**
* {@inheritDoc}
*/
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
}
/**
* {@inheritDoc}
*/
@Override
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) {
// Sometimes, the package scan will be conflicted with MyBatis
// so the existing is not the expected one, we remove it.
if (this.registry.containsBeanDefinition(beanName)) {
// an HttpApi bean exists, we ignore the others.
if (isHttpApiBean(beanName)) {
logger.info("an HttpApi bean [" + beanName + "] exists, we ignore the others");
return false;
}
logger.warn("an not HttpApi bean named [" + beanName + "] exists, we remove it, so that we can generate a new bean.");
registry.removeBeanDefinition(beanName);
}
if (super.checkCandidate(beanName, beanDefinition)) {
return true;
} else {
logger.warn("Skipping " + factoryBean.getSimpleName() + " with name '" + beanName
+ "' and '" + beanDefinition.getBeanClassName() + "' interface"
+ ". Bean already defined with the same name!");
return false;
}
}
private boolean isHttpApiBean(String beanName) {
if (registry instanceof DefaultListableBeanFactory) {
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) registry;
return beanFactory.containsBean(beanName) && beanFactory.getBean(beanName).toString().startsWith(HTTP_API_PREFIX);
}
return false;
}
/**
* registry the bean with FactoryBean
*/
@Override
protected void registerBeanDefinition(BeanDefinitionHolder holder, BeanDefinitionRegistry registry) {
GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition();
if (logger.isDebugEnabled()) {
logger.debug(includeAnn.getSimpleName() + ": Bean with name '" + holder.getBeanName()
+ "' and '" + definition.getBeanClassName() + "' interface");
}
if (logger.isDebugEnabled()) {
logger.debug("Enabling autowire by type for " + factoryBean.getSimpleName() + " with name '" + holder.getBeanName() + "'.");
}
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
// 需要被代理的接口 the interface
definition.getPropertyValues().add("interfaceClass", definition.getBeanClassName());
// 配置项
definition.getPropertyValues().add("propertyResolver", propertyResolver);
if (requestor != null) {
definition.getPropertyValues().add("requestor", requestor);
}
if (requestPreprocessor != null) {
definition.getPropertyValues().add("requestPreprocessor", requestPreprocessor);
}
if (responseProcessor != null) {
definition.getPropertyValues().add("responseProcessor", responseProcessor);
}
// 获取bean名,注意:获取 BeanName 要在setBeanClass之前,否则BeanName就会被覆盖
// caution! we nned to getBeanName first before setBeanClass
String beanName = holder.getBeanName();
// 将BeanClass设置成Bean工厂
definition.setBeanClass(factoryBean);
// 注册Bean
registry.registerBeanDefinition(beanName, definition);
}
}