MongoRepository动态代理及jpa方法解析源码分析

1public interface FzkRepository extends MongoRepository<Fzk, String> { 2 Fzk findByName(String name); 3} 4 5@RestControllerpublic class TestController { 6 @Autowired 7 private FzkRepository fzkReposiroty; 8}

为什么一个接口,没有实现类就能被注入?

首先如果想使用MongoRepository,一定会在配置中加入@EnableMongoRepositories,就从EnableMongoRepositories开始

@Import(MongoRepositoriesRegistrar.class)

跟踪进入RepositoryBeanDefinitionRegistrarSupport

1public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) { 2.... 3 AnnotationRepositoryConfigurationSource configurationSource = new AnnotationRepositoryConfigurationSource(annotationMetadata, getAnnotation(), resourceLoader, environment, registry);

      if (annotationMetadata.getAnnotationAttributes(getAnnotation().getName()) == null) {
return;
}

1 RepositoryConfigurationExtension extension = getExtension(); 2 RepositoryConfigurationUtils.exposeRegistration(extension, registry, configurationSource); 3 4 RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(configurationSource, resourceLoader, 5 environment); 6 7 delegate.registerRepositoriesIn(registry, extension); 8 }

没什么可说的,只有使用了EnableMongoRepositories才会继续进行,注册bean交给了RepositoryConfigurationDelegate 来进行。继续进入RepositoryConfigurationDelegate.registerRepositoriesIn方法

1 public List<BeanComponentDefinition> registerRepositoriesIn(BeanDefinitionRegistry registry, 2 RepositoryConfigurationExtension extension) { 3 4 extension.registerBeansForRoot(registry, configurationSource); 5 6 RepositoryBeanDefinitionBuilder builder = new RepositoryBeanDefinitionBuilder(registry, extension, resourceLoader, 7 environment); 8 List<BeanComponentDefinition> definitions = new ArrayList<BeanComponentDefinition>(); 9 10 for (RepositoryConfiguration<? extends RepositoryConfigurationSource> configuration : extension 11 .getRepositoryConfigurations(configurationSource, resourceLoader, inMultiStoreMode)) { 12 13 BeanDefinitionBuilder definitionBuilder = builder.build(configuration); 14 15 extension.postProcess(definitionBuilder, configurationSource); 16 17 if (isXml) { 18 extension.postProcess(definitionBuilder, (XmlRepositoryConfigurationSource) configurationSource); 19 } else { 20 extension.postProcess(definitionBuilder, (AnnotationRepositoryConfigurationSource) configurationSource); 21 } 22 23 AbstractBeanDefinition beanDefinition = definitionBuilder.getBeanDefinition(); 24 String beanName = beanNameGenerator.generateBeanName(beanDefinition, registry); 25 26 if (LOGGER.isDebugEnabled()) { 27 LOGGER.debug(REPOSITORY_REGISTRATION, extension.getModuleName(), beanName, 28 configuration.getRepositoryInterface(), extension.getRepositoryFactoryClassName()); 29 } 30 31 beanDefinition.setAttribute(FACTORY_BEAN_OBJECT_TYPE, configuration.getRepositoryInterface()); 32 33 registry.registerBeanDefinition(beanName, beanDefinition); 34 definitions.add(new BeanComponentDefinition(beanDefinition, beanName)); 35 } 36 37 return definitions; 38 }

扫描实现了MongoRepository的接口并生成RepositoryConfigurationSource的逻辑在RepositoryConfigurationExtensionSupport.getRepositoryConfigurations方法中

1public <T extends RepositoryConfigurationSource> Collection<RepositoryConfiguration<T>> getRepositoryConfigurations( 2 T configSource, ResourceLoader loader, boolean strictMatchesOnly) { 3.... 4 Set<RepositoryConfiguration<T>> result = new HashSet<RepositoryConfiguration<T>>(); 5 6 for (BeanDefinition candidate : configSource.getCandidates(loader)) { 7 RepositoryConfiguration<T> configuration = getRepositoryConfiguration(candidate, configSource); 8 if (!strictMatchesOnly || configSource.usesExplicitFilters()) { 9 result.add(configuration); 10 continue; 11 } 12 Class<?> repositoryInterface = loadRepositoryInterface(configuration, loader); 13 if (repositoryInterface == null || isStrictRepositoryCandidate(repositoryInterface)) { 14 result.add(configuration); 15 } 16 } 17 return result; 18 }

继续跟踪RepositoryConfigurationSourceSupport.getCandidates

1public Collection<BeanDefinition> getCandidates(ResourceLoader loader) { 2 RepositoryComponentProvider scanner = new RepositoryComponentProvider(getIncludeFilters(), registry); 3 scanner.setConsiderNestedRepositoryInterfaces(shouldConsiderNestedRepositories()); 4 scanner.setEnvironment(environment); 5 scanner.setResourceLoader(loader); 6 for (TypeFilter filter : getExcludeFilters()) { 7 scanner.addExcludeFilter(filter); 8 } 9 Set<BeanDefinition> result = new HashSet<BeanDefinition>(); 10 for (String basePackage : getBasePackages()) { 11 Set<BeanDefinition> candidate = scanner.findCandidateComponents(basePackage); 12 result.addAll(candidate); 13 } 14 return result; 15 }

RepositoryComponentProvider.findCandidateComponents,先由父类ClassPathScanningCandidateComponentProvider处理

1public Set<BeanDefinition> findCandidateComponents(String basePackage) { 2 Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>(); 3 String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + (basePackage) + '/' + this.resourcePattern; 4 Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath); 5 ......for (Resource resource : resources) { 6 ...... 7 MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource); 8 if (isCandidateComponent(metadataReader)) { 9 ...... 10 } 11 12protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException { 13 for (TypeFilter tf : this.excludeFilters) { //1 14 if (tf.match(metadataReader, this.metadataReaderFactory)) { 15 return false; 16 } 17 } 18 for (TypeFilter tf : this.includeFilters) { //2 if (tf.match(metadataReader, this.metadataReaderFactory)) { return isConditionMatch(metadataReader); } } return false; }

  private boolean isConditionMatch(MetadataReader metadataReader) {
    if (this.conditionEvaluator == null) {
      this.conditionEvaluator = new ConditionEvaluator(getRegistry(), getEnvironment(), getResourceLoader());
    }
    return !this.conditionEvaluator.shouldSkip(metadataReader.getAnnotationMetadata());
  }

判断条件,1.如果是注解了NoRepositoryBean就不处理,2.判断了是Repository后,继续判断是否有@Condition。找到了所有复合条件的类后,组成RepositoryConfiguration后,继续跟踪RepositoryConfigurationDelegate.registerRepositoriesIn,组成BeanDefinitionBuilder,构件出MongoRepositoryFactoryBean。

1public class MongoRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> 2 extends RepositoryFactoryBeanSupport<T, S, ID> 3 4public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>, S, ID extends Serializable> 5 implements InitializingBean, RepositoryFactoryInformation<S, ID>, FactoryBean<T>, BeanClassLoaderAware, 6 BeanFactoryAware, ApplicationEventPublisherAware

MongoRepositoryFactoryBean间接实现InitializingBean,因此他会实现afterPropertiesSet方法

在AbstractApplicationContext  ->  refresh()   ->   finishBeanFactoryInitialization()阶段,实例化bean时进行实例化。
这个例子里,TestController注入了FzkRepository ,实例化TestController时发现需要注入FzkRepository 会先实例化FzkRepository。
在DefaultListableBeanFactory的preInstantiateSingletons()时

1public void preInstantiateSingletons() throws BeansException { 2...... 3 for (String beanName : beanNames) { 4 RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); 5 if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { 6 if (isFactoryBean(beanName)) { 7 final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName); 8 boolean isEagerInit; 9 if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { 10 isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { 11 @Override 12 public Boolean run() { 13 return ((SmartFactoryBean<?>) factory).isEagerInit(); 14 } 15 }, getAccessControlContext()); 16 } 17 else { 18 isEagerInit = (factory instanceof SmartFactoryBean && 19 ((SmartFactoryBean<?>) factory).isEagerInit()); 20 } 21 if (isEagerInit) { 22 getBean(beanName); 23 } 24 } 25 else { 26 getBean(beanName); 27 } 28 } 29 }...... 30 } 31 32protected <T> T doGetBean( 33 final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) 34 throws BeansException { 35...... 36 // Create bean instance. 37 if (mbd.isSingleton()) { 38 sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() { 39 @Override 40 public Object getObject() throws BeansException { 41 try { 42 return createBean(beanName, mbd, args); 43 } 44 catch (BeansException ex) { 45...... 46 } 47 } 48 }); 49 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 50 }...... 51 return (T) bean; 52 }

多次调用进入AbstractAutowireCapableBeanFactory.doCreateBean。

1protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) 2 throws BeanCreationException { 3...... 4 // Initialize the bean instance. 5 Object exposedObject = bean; 6 try { 7 populateBean(beanName, mbd, instanceWrapper); 8 if (exposedObject != null) { 9 exposedObject = initializeBean(beanName, exposedObject, mbd); 10 } 11 }...... 12 } 13 14protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { 15...... 16 invokeInitMethods(beanName, wrappedBean, mbd); 17...... 18 } 19 20protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd) 21 throws Throwable { 22...... 23 ((InitializingBean) bean).afterPropertiesSet(); 24...... }

上面说了由BeanDefinitionBuilder构件出MongoRepositoryFactoryBean,而MongoRepositoryFactoryBean实现了InitializingBean,这里进入到了MongoRepositoryFactoryBean.afterPropertiesSet

1public void afterPropertiesSet() { 2 3 super.afterPropertiesSet(); 4 Assert.notNull(operations, "MongoTemplate must not be null!"); 5 6 if (!mappingContextConfigured) { 7 setMappingContext(operations.getConverter().getMappingContext()); 8 } 9 }

进入到父累RepositoryFactoryBeanSupport.afterPropertiesSet

1public void afterPropertiesSet() { 2 3 this.factory = createRepositoryFactory(); 4...... 5 if (publisher != null) { 6 this.factory.addRepositoryProxyPostProcessor(new EventPublishingRepositoryProxyPostProcessor(publisher)); 7 } 8 9 this.repositoryMetadata = this.factory.getRepositoryMetadata(repositoryInterface); 10 11 if (!lazyInit) { 12 initAndReturn(); 13 } 14 } 15 16 private T initAndReturn() { 17...... 18 if (this.repository == null) { 19 this.repository = this.factory.getRepository(repositoryInterface, customImplementation); 20 } 21 return this.repository; 22 }

这里的factory是MongoRepositoryFactory,接下来,才是创建代理的部分

1public <T> T getRepository(Class<T> repositoryInterface, Object customImplementation) { 2...... 3 // Create proxy 4 ProxyFactory result = new ProxyFactory(); 5 result.setTarget(target);  6 result.setInterfaces(new Class[] { repositoryInterface, Repository.class }); 7...... 8 result.addAdvice(new QueryExecutorMethodInterceptor(information, customImplementation, target, projectionFactory)); 9 10 return (T) result.getProxy(classLoader); 11 }

第一重点是ProxyFactory,这里target是SimpleMongoRepository,repositoryInterface是FzkRepository(自己的接口)。
另一个重点是增加了一个切入点QueryExecutorMethodInterceptor。看看QueryExecutorMethodInterceptor

1 public QueryExecutorMethodInterceptor(RepositoryInformation repositoryInformation, Object customImplementation, 2 Object target, ProjectionFactory projectionFactory) { 3...... 4 this.resultHandler = new QueryExecutionResultHandler(); 5 this.repositoryInformation = repositoryInformation; 6 this.customImplementation = customImplementation; 7 this.target = target; 8 9 QueryLookupStrategy lookupStrategy = getQueryLookupStrategy(queryLookupStrategyKey, 10 RepositoryFactorySupport.this.evaluationContextProvider); 11 lookupStrategy = lookupStrategy == null ? getQueryLookupStrategy(queryLookupStrategyKey) : lookupStrategy; 12 Iterable<Method> queryMethods = repositoryInformation.getQueryMethods(); 13...... 14 for (Method method : queryMethods) { 15 RepositoryQuery query = lookupStrategy.resolveQuery(method, repositoryInformation, projectionFactory, 16 namedQueries); 17 18 invokeListeners(query); 19 queries.put(method, query); 20 } 21 }

首先他是一个MethodInterceptor,一个有个invoke方法,这个方法之后在说。现在先看构造器里干了什么。
首先构件一个MongoRepositoryFactory$MongoQueryLookupStrategy类型的lookupStrategy 。处理jpa写法的方法就是由它来处理,这里的例子是findByName方法。继续跟踪,看看是怎么将findByName解析成{"name" : ***}的。写了这么多,终于快到终点了。继续看,进入到MongoQueryLookupStrategy.resolveQuery

1public RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, ProjectionFactory factory, 2 NamedQueries namedQueries) { 3 4 MongoQueryMethod queryMethod = new MongoQueryMethod(method, metadata, factory, mappingContext); 5 String namedQueryName = queryMethod.getNamedQueryName(); 6 7 if (namedQueries.hasQuery(namedQueryName)) { 8 String namedQuery = namedQueries.getQuery(namedQueryName); 9 return new StringBasedMongoQuery(namedQuery, queryMethod, operations, EXPRESSION_PARSER, 10 evaluationContextProvider); 11 } else if (queryMethod.hasAnnotatedQuery()) { 12 return new StringBasedMongoQuery(queryMethod, operations, EXPRESSION_PARSER, evaluationContextProvider); 13 } else { 14 return new PartTreeMongoQuery(queryMethod, operations); 15 } 16 }

这里,无@Query注解,进入PartTreeMongoQuery分支

1public PartTreeMongoQuery(MongoQueryMethod method, MongoOperations mongoOperations) { 2 3 super(method, mongoOperations); 4 5 this.processor = method.getResultProcessor(); 6 this.tree = new PartTree(method.getName(), processor.getReturnedType().getDomainType()); 7 this.isGeoNearQuery = method.isGeoNearQuery(); 8 this.context = mongoOperations.getConverter().getMappingContext(); 9 } 10 11public class PartTree { 12 private static final String KEYWORD_TEMPLATE = "(%s)(?=(\\p{Lu}|\\P{InBASIC_LATIN}))"; 13 private static final String QUERY_PATTERN = "find|read|get|query|stream"; 14 private static final String COUNT_PATTERN = "count"; 15 private static final String EXISTS_PATTERN = "exists"; 16 private static final String DELETE_PATTERN = "delete|remove"; 17 private static final Pattern PREFIX_TEMPLATE = Pattern.compile( // 18 "^(" + QUERY_PATTERN + "|" + COUNT_PATTERN + "|" + EXISTS_PATTERN + "|" + DELETE_PATTERN + ")((\\p{Lu}.*?))??By"); 19 public PartTree(String source, Class<?> domainClass) { 20...... 21 Matcher matcher = PREFIX_TEMPLATE.matcher(source); 22 if (!matcher.find()) { 23 this.subject = new Subject(null); 24 this.predicate = new Predicate(source, domainClass); 25 } else { 26 this.subject = new Subject(matcher.group(0)); 27 this.predicate = new Predicate(source.substring(matcher.group().length()), domainClass); 28 } 29 } 30}

最终生成的query,已经将name(key)解析出来了。

至此,终于解析完,怎么创建的代理,怎么根据方法名来解析sql。最后就是使用点

上面说了,使用时,会调用QueryExecutorMethodInterceptor.invoke

1public Object invoke(MethodInvocation invocation) throws Throwable { 2 3 Object result = doInvoke(invocation); 4 5 return resultHandler.postProcessInvocationResult(result, invocation.getMethod()); 6 } 7 8 private Object doInvoke(MethodInvocation invocation) throws Throwable { 9 10 Method method = invocation.getMethod(); 11 Object[] arguments = invocation.getArguments(); 12 13 if (isCustomMethodInvocation(invocation)) { 14 15 Method actualMethod = repositoryInformation.getTargetClassMethod(method); 16 return executeMethodOn(customImplementation, actualMethod, arguments); 17 } 18 19 if (hasQueryFor(method)) { 20 return queries.get(method).execute(arguments); 21 } 22 23 // Lookup actual method as it might be redeclared in the interface 24 // and we have to use the repository instance nevertheless 25 Method actualMethod = repositoryInformation.getTargetClassMethod(method); 26 return executeMethodOn(target, actualMethod, arguments); 27 }

queries.get(method)得到PartTreeMongoQuery

1public Object execute(Object[] parameters) { 2 3 MongoParameterAccessor accessor = new MongoParametersParameterAccessor(method, parameters); 4 Query query = createQuery(new ConvertingParameterAccessor(operations.getConverter(), accessor)); 5 6 applyQueryMetaAttributesWhenPresent(query); 7 8 ResultProcessor processor = method.getResultProcessor().withDynamicProjection(accessor); 9 String collection = method.getEntityInformation().getCollectionName(); 10 11 MongoQueryExecution execution = getExecution(query, accessor, 12 new ResultProcessingConverter(processor, operations, instantiators)); 13 14 return execution.execute(query, processor.getReturnedType().getDomainType(), collection); 15 }

构件出Query得到结果返回

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )