可以掃描到包spring
@ComponentScan("org.zxp.esclientrhl")
ESCRegistrar類主要實現ImportBeanDefinitionRegistrar接口api
@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管理(和自動代理接口實現類無關,用於自動建立索引)app
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的接口dom
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識別,第二個是掃描到後返回BeanDefinitionide
scanner.findCandidateComponents(it) scanner.scan(getBasePackage.getEntityPackage(annotationMetadata).toArray(String[]::new));
獲取繼承ESCRepository的接口(BeanDefinition)並遍歷ui
經過BeanDefinitionBuilder給RepositoryFactorySupport傳遞掃描到接口的類類型、以及要生成代理bean的namethis
調用beanDefinitionRegistry.registerBeanDefinition(beanName, bd);將RepositoryFactorySupport託管給spring(注意RepositoryFactorySupport並非目的,是經過RepositoryFactorySupport生成代理bean)spa
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; }