Packets can be scanned

@ComponentScan("org.zxp.esclientrhl")
Copy the code

ESCRegistrar ImportBeanDefinitionRegistrar mainly realized interface

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

Implement the following method, which is called to generate the proxy bean early in Spring startup

public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {// Scan for Entity new ESIndexProcessor().scan(annotationMetadata,beanFactory,applicationContext); / / scanning interface super. RegisterBeanDefinitions (the beanFactory, environment, resourceLoader, annotationMetadata, registry); }Copy the code

Scan entity, annotate configuration or launch directory to scan entity classes and host them for Spring management (independent of automatic proxy interface implementation classes, for automatic index creation)

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));
}
Copy the code

Get the interface that inherits ESCRepository by using the getCandidates method

public Stream<BeanDefinition> getCandidates(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry, Environment environment, ResourceLoader resourceLoader) { ESCRepositoryComponentProvider scanner = new ESCRepositoryComponentProvider(registry); scanner.setEnvironment(environment); scanner.setResourceLoader(resourceLoader); // Input is basepackages, Stream return getBasePackage(annotationMetadata). FlatMap (it -> scanner.findCandidateComponents(it).stream()); }Copy the code

The following two types of scan are different. The first one is that spring can recognize it after scanning, and the second one returns BeanDefinition after scanning

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

Gets the interface (BeanDefinition) that inherits ESCRepository and traverses it

Pass BeanDefinitionBuilder to RepositoryFactorySupport the class type scanned to the interface, along with the name of the proxy bean to be generated

Call beanDefinitionRegistry. RegisterBeanDefinition (beanName, bd); Hosting RepositoryFactorySupport to Spring (note that RepositoryFactorySupport is not the goal, it is to make proxy beans by RepositoryFactorySupport)

RepositoryFactorySupport is the job of registering beans

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(); . / / the incoming interface to instantiate beanDefinitionBuilder addConstructorArgValue (beanClassName); / / get the bean definition of BeanDefinition bd = beanDefinitionBuilder. GetRawBeanDefinition (); / / generated 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; / / registered bean beanName is agent is not the name of the bean RepositoryFactorySupport name beanDefinitionRegistry. RegisterBeanDefinition (beanName, bd); }); }Copy the code

RepositoryInterface to receive incoming interface class types (ready to be generated by a dynamic proxy)

After the RepositoryFactorySupport registration is complete, the real proxy bean is generated and registered using afterPropertiesSet

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);
 }
}
Copy the code

Note the details of generating proxy beans:

public <T> T getRepository(Class<T> repositoryInterface) throws Exception { SimpleESCRepository target = new SimpleESCRepository(applicationContext); // The purpose of passing the applicationContext is so that the proxy bean can get the bean getMetadata(target) at run time through the applicationContext; ProxyFactory result = new ProxyFactory(); 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; }Copy the code

As long as you get the interface or class, you can use the API to get the generic name that defines the interface.

The getEntityList() method iterates through and matches all entities with the cached Entitypaths

private void getMetadata(SimpleESCRepository target) throws Exception { Type[] types = repositoryInterface.getGenericInterfaces(); ParameterizedType parameterized = (ParameterizedType) types[0]; / / entity class type name String domainClassName. = the parameterized getActualTypeArguments () [0]. GetTypeName (); / / entity class primary key type name String idClassName. = the parameterized getActualTypeArguments () [1]. GetTypeName (); If (org. ZXP. Esclientrhl. Auto. Util. EnableESTools. IsPrintregmsg ()) {logger. The 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 !" ); }}Copy the code

Implementing FactoryBeans allows you to host the generated proxy beans to Spring

/** * Implementing a FactoryBean can host the generated proxy bean to Spring ** @return * @throws Exception */ @Override public T getObject() throws Exception { return this.repository; } /* Override public Class<? > getObjectType() { return repositoryInterface; }Copy the code