Spring只定义接口自动代理接口实现类

856 阅读3分钟

能够扫描到包

@ComponentScan("org.zxp.esclientrhl")

ESCRegistrar类主要实现ImportBeanDefinitionRegistrar接口

@Configuration
public class ESCRegistrar extends AbstractESCRegister implements BeanFactoryAware,ApplicationContextAware, ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {

实现下面方法,会在spring启动早期调用生成代理bean

public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) { 
 //扫描entity new ESIndexProcessor().scan(annotationMetadata,beanFactory,applicationContext); 
 //扫描接口 
 super.registerBeanDefinitions(beanFactory, environment, resourceLoader, annotationMetadata, registry);
 }

扫描entity,通过注解配置或者启动目录扫描实体类并托管给Spring管理(和自动代理接口实现类无关,用于自动创建索引)

public void scan(AnnotationMetadata annotationMetadata,BeanFactory beanFactory,ApplicationContext applicationContext){
 GetBasePackage getBasePackage = new GetBasePackage(EnableESTools.class);
 ESEntityScanner scanner = new ESEntityScanner((BeanDefinitionRegistry) beanFactory);
 scanner.setResourceLoader(applicationContext);
 scanner.scan(getBasePackage.getEntityPackage(annotationMetadata).toArray(String[]::new));
}

通过getCandidates方法获取继承ESCRepository的接口

public Stream<BeanDefinition> getCandidates(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry, Environment environment, ResourceLoader resourceLoader) {
 ESCRepositoryComponentProvider scanner = new ESCRepositoryComponentProvider(registry);
 scanner.setEnvironment(environment);
 scanner.setResourceLoader(resourceLoader);
 //输入是basepackages,输出是BeanDefinition的Stream
 return getBasePackage(annotationMetadata).flatMap(it -> scanner.findCandidateComponents(it).stream());
}

下面这两种scan不同,第一个就是扫描后能被spring识别,第二个是扫描到后返回BeanDefinition

scanner.findCandidateComponents(it)
scanner.scan(getBasePackage.getEntityPackage(annotationMetadata).toArray(String[]::new));

获取继承ESCRepository的接口(BeanDefinition)并遍历

通过BeanDefinitionBuilder给RepositoryFactorySupport传递扫描到接口的类类型、以及要生成代理bean的name

调用beanDefinitionRegistry.registerBeanDefinition(beanName, bd);将RepositoryFactorySupport托管给spring(注意RepositoryFactorySupport并不是目的,是通过RepositoryFactorySupport生成代理bean)

RepositoryFactorySupport的作用就是注册bean

public void registerBeanDefinitions(BeanFactory factory, Environment environment, ResourceLoader resourceLoader, AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
 getCandidates(annotationMetadata, registry, environment, resourceLoader).forEach(beanDefinition -> {
 BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(RepositoryFactorySupport.class);
 String beanClassName = beanDefinition.getBeanClassName();
 //传入要实例化的接口
 beanDefinitionBuilder.addConstructorArgValue(beanClassName);
 //获取bean的定义
 BeanDefinition bd = beanDefinitionBuilder.getRawBeanDefinition();
 //生成beanname
 String beanName = beanClassName.substring(beanClassName.lastIndexOf(".") + 1);
 if(org.zxp.esclientrhl.auto.util.EnableESTools.isPrintregmsg()){
 logger.info("generate ESCRegistrar beanClassName:" + beanClassName);
 logger.info("generate ESCRegistrar beanName:" + beanName);
 }
 BeanDefinitionRegistry beanDefinitionRegistry = (BeanDefinitionRegistry) factory;
 //注册bean beanName是代理bean的名字 不是RepositoryFactorySupport的名字
 beanDefinitionRegistry.registerBeanDefinition(beanName, bd);
 });
}

repositoryInterface用于接收传入的接口类类型(准备通过动态代理生成)

通过afterPropertiesSet在RepositoryFactorySupport注册完成后生成并注册真正的代理bean

public class RepositoryFactorySupport<T extends ESCRepository<S, ID>, S, ID> implements ApplicationContextAware, ResourceLoaderAware, InitializingBean, FactoryBean<T>, BeanClassLoaderAware,
 BeanFactoryAware, ApplicationEventPublisherAware {
 ……
 private final Class<? extends T> repositoryInterface;
 public RepositoryFactorySupport(Class<? extends T> repositoryInterface) {
 this.repositoryInterface = repositoryInterface;
 }
 @Override
 public void afterPropertiesSet() {
 try {
 this.repository = this.getRepository(repositoryInterface);
 } catch (Exception e) {
 logger.error("ESCRepository proxy create fail !", e);
 }
}

生成代理bean的细节注意注释:

public <T> T getRepository(Class<T> repositoryInterface) throws Exception {
 SimpleESCRepository target = new SimpleESCRepository(applicationContext);//传入applicationContext的目的是为了能让代理bean在运行时能通过applicationContext获取需要注入的bean
 getMetadata(target);//下面单独说,获取对应实体类的类类型以及主键类型
 //spring动态代理用法
 ProxyFactory result = new ProxyFactory();
 result.setTarget(target);
 result.addAdvice(new MethodInterceptor() {
 @Override
 public Object invoke(MethodInvocation invocation) throws Throwable {
 Object result = invocation.proceed();
 return result;
 }
 });
 result.setInterfaces(this.repositoryInterface, ESCRepository.class);
 T repository = (T) result.getProxy(classLoader);
 return repository;
}

只要拿到了接口或者类,是能通过api获得定义接口的泛型名称的(不能获得全限定类名,有类名就可以匹配)

getEntityList()方法通过缓存的entitypaths遍历所有的entity并与之匹配

private void getMetadata(SimpleESCRepository target) throws Exception {
 Type[] types = repositoryInterface.getGenericInterfaces();
 ParameterizedType parameterized = (ParameterizedType) types[0];
 //实体类类型名称
 String domainClassName = parameterized.getActualTypeArguments()[0].getTypeName();
 //实体类主键类型名称
 String idClassName = parameterized.getActualTypeArguments()[1].getTypeName();
 if (org.zxp.esclientrhl.auto.util.EnableESTools.isPrintregmsg()) {
 logger.info("domainClassName:" + domainClassName + " idClassName:" + idClassName);
 }
 //按照实体类类型名称匹配实体类类型
 List<String> entityList = getEntityList();
 for (int i = 0; i < entityList.size(); i++) {
 if (entityList.get(i).lastIndexOf("." + domainClassName) != -1) {
 if (target.getDomainClass() == null) {
 target.setDomainClass(Class.forName(entityList.get(i)));
 break;
 } else {
 target.setDomainClass(null);
 throw new Exception("Entity Overmatched !");
 }
 }
 }
 //按照实体类主键类型名称主键类型
 Map<String, Class> idTypeMap = getIdTypeMap();
 if (idTypeMap.containsKey(idClassName)) {
 target.setIdClass(idTypeMap.get(idClassName));
 } else {
 throw new Exception("Not Supported ID Type !");
 }
}

实现了FactoryBean可以将生成的代理bean托管给spring

/**
 * 实现了FactoryBean可以将生成的代理bean托管给spring
 *
 * @return
 * @throws Exception
 */
@Override
public T getObject() throws Exception {
 return this.repository;
}
/**
 * 实现了FactoryBean可以将生成的代理bean托管给spring
 *
 * @return
 */
@Override
public Class<?> getObjectType() {
 return repositoryInterface;
}