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<BeanDefinitionHolder> doScan(String... basePackages) { Set<BeanDefinitionHolder> 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); } }