MongoRepository動態代理及jpa方法解析原始碼分析
public interface FzkRepository extends MongoRepository<Fzk, String> { Fzk findByName(String name); }
@RestController
public class TestController { @Autowired private FzkRepository fzkReposiroty; }
為什麼一個介面,沒有實現類就能被注入?
首先如果想使用MongoRepository,一定會在配置中加入@EnableMongoRepositories,就從EnableMongoRepositories開始
@Import(MongoRepositoriesRegistrar.class)
跟蹤進入RepositoryBeanDefinitionRegistrarSupport
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) { .... AnnotationRepositoryConfigurationSource configurationSource = new AnnotationRepositoryConfigurationSource(annotationMetadata, getAnnotation(), resourceLoader, environment, registry);
if (annotationMetadata.getAnnotationAttributes(getAnnotation().getName()) == null) {
return;
}
RepositoryConfigurationExtension extension = getExtension(); RepositoryConfigurationUtils.exposeRegistration(extension, registry, configurationSource); RepositoryConfigurationDelegate delegate= new RepositoryConfigurationDelegate(configurationSource, resourceLoader, environment); delegate.registerRepositoriesIn(registry, extension); }
沒什麼可說的,只有使用了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方法中
public <T extends RepositoryConfigurationSource> Collection<RepositoryConfiguration<T>> getRepositoryConfigurations( T configSource, ResourceLoader loader, boolean strictMatchesOnly) { .... Set<RepositoryConfiguration<T>> result = new HashSet<RepositoryConfiguration<T>>(); for (BeanDefinition candidate : configSource.getCandidates(loader)) { RepositoryConfiguration<T> configuration = getRepositoryConfiguration(candidate, configSource); if (!strictMatchesOnly || configSource.usesExplicitFilters()) { result.add(configuration); continue; } Class<?> repositoryInterface = loadRepositoryInterface(configuration, loader); if (repositoryInterface == null || isStrictRepositoryCandidate(repositoryInterface)) { result.add(configuration); } } return result; }
繼續跟蹤RepositoryConfigurationSourceSupport.getCandidates
public Collection<BeanDefinition> getCandidates(ResourceLoader loader) { RepositoryComponentProvider scanner = new RepositoryComponentProvider(getIncludeFilters(), registry); scanner.setConsiderNestedRepositoryInterfaces(shouldConsiderNestedRepositories()); scanner.setEnvironment(environment); scanner.setResourceLoader(loader); for (TypeFilter filter : getExcludeFilters()) { scanner.addExcludeFilter(filter); } Set<BeanDefinition> result = new HashSet<BeanDefinition>(); for (String basePackage : getBasePackages()) { Set<BeanDefinition> candidate = scanner.findCandidateComponents(basePackage); result.addAll(candidate); } return result; }
RepositoryComponentProvider.findCandidateComponents,先由父類ClassPathScanningCandidateComponentProvider處理
public Set<BeanDefinition> findCandidateComponents(String basePackage) { Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>(); String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + (basePackage) + '/' + this.resourcePattern; Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath); ......for (Resource resource : resources) { ...... MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource); if (isCandidateComponent(metadataReader)) { ...... }
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
for (TypeFilter tf : this.excludeFilters) { //1
if (tf.match(metadataReader, this.metadataReaderFactory)) {
return false;
}
}
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。
public class MongoRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends RepositoryFactoryBeanSupport<T, S, ID> public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>, S, ID extends Serializable> implements InitializingBean, RepositoryFactoryInformation<S, ID>, FactoryBean<T>, BeanClassLoaderAware, BeanFactoryAware, ApplicationEventPublisherAware
MongoRepositoryFactoryBean間接實現InitializingBean,因此他會實現afterPropertiesSet方法
在AbstractApplicationContext -> refresh() -> finishBeanFactoryInitialization()階段,例項化bean時進行例項化。
這個例子裡,TestController注入了FzkRepository ,例項化TestController時發現需要注入FzkRepository 會先例項化FzkRepository。
在DefaultListableBeanFactory的preInstantiateSingletons()時
public void preInstantiateSingletons() throws BeansException { ...... for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName); boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { @Override public Boolean run() { return ((SmartFactoryBean<?>) factory).isEagerInit(); } }, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } else { getBean(beanName); } } }
......
}
protected <T> T doGetBean( final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { ...... // Create bean instance. if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { ...... } } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }...... return (T) bean; }
多次呼叫進入AbstractAutowireCapableBeanFactory.doCreateBean。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) throws BeanCreationException { ...... // Initialize the bean instance. Object exposedObject = bean; try { populateBean(beanName, mbd, instanceWrapper); if (exposedObject != null) { exposedObject = initializeBean(beanName, exposedObject, mbd); } }...... }
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { ...... invokeInitMethods(beanName, wrappedBean, mbd); ...... } protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable { ...... ((InitializingBean) bean).afterPropertiesSet(); ......
}
上面說了由BeanDefinitionBuilder構件出MongoRepositoryFactoryBean,而MongoRepositoryFactoryBean實現了InitializingBean,這裡進入到了MongoRepositoryFactoryBean.afterPropertiesSet
public void afterPropertiesSet() { super.afterPropertiesSet(); Assert.notNull(operations, "MongoTemplate must not be null!"); if (!mappingContextConfigured) { setMappingContext(operations.getConverter().getMappingContext()); } }
進入到父累RepositoryFactoryBeanSupport.afterPropertiesSet
public void afterPropertiesSet() { this.factory = createRepositoryFactory(); ...... if (publisher != null) { this.factory.addRepositoryProxyPostProcessor(new EventPublishingRepositoryProxyPostProcessor(publisher)); } this.repositoryMetadata = this.factory.getRepositoryMetadata(repositoryInterface); if (!lazyInit) { initAndReturn(); } } private T initAndReturn() { ...... if (this.repository == null) { this.repository = this.factory.getRepository(repositoryInterface, customImplementation); } return this.repository; }
這裡的factory是MongoRepositoryFactory,接下來,才是建立代理的部分
public <T> T getRepository(Class<T> repositoryInterface, Object customImplementation) { ...... // Create proxy ProxyFactory result = new ProxyFactory(); result.setTarget(target); result.setInterfaces(new Class[] { repositoryInterface, Repository.class }); ...... result.addAdvice(new QueryExecutorMethodInterceptor(information, customImplementation, target, projectionFactory)); return (T) result.getProxy(classLoader); }
第一重點是ProxyFactory,這裡target是SimpleMongoRepository,repositoryInterface是FzkRepository(自己的介面)。
另一個重點是增加了一個切入點QueryExecutorMethodInterceptor。看看QueryExecutorMethodInterceptor
public QueryExecutorMethodInterceptor(RepositoryInformation repositoryInformation, Object customImplementation, Object target, ProjectionFactory projectionFactory) { ...... this.resultHandler = new QueryExecutionResultHandler(); this.repositoryInformation = repositoryInformation; this.customImplementation = customImplementation; this.target = target; QueryLookupStrategy lookupStrategy = getQueryLookupStrategy(queryLookupStrategyKey, RepositoryFactorySupport.this.evaluationContextProvider); lookupStrategy = lookupStrategy == null ? getQueryLookupStrategy(queryLookupStrategyKey) : lookupStrategy; Iterable<Method> queryMethods = repositoryInformation.getQueryMethods(); ...... for (Method method : queryMethods) { RepositoryQuery query = lookupStrategy.resolveQuery(method, repositoryInformation, projectionFactory, namedQueries); invokeListeners(query); queries.put(method, query); } }
首先他是一個MethodInterceptor,一個有個invoke方法,這個方法之後在說。現在先看構造器裡幹了什麼。
首先構件一個MongoRepositoryFactory$MongoQueryLookupStrategy型別的lookupStrategy 。處理jpa寫法的方法就是由它來處理,這裡的例子是findByName方法。繼續跟蹤,看看是怎麼將findByName解析成{"name" : ***}的。寫了這麼多,終於快到終點了。繼續看,進入到MongoQueryLookupStrategy.resolveQuery
public RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, ProjectionFactory factory, NamedQueries namedQueries) { MongoQueryMethod queryMethod = new MongoQueryMethod(method, metadata, factory, mappingContext); String namedQueryName = queryMethod.getNamedQueryName(); if (namedQueries.hasQuery(namedQueryName)) { String namedQuery = namedQueries.getQuery(namedQueryName); return new StringBasedMongoQuery(namedQuery, queryMethod, operations, EXPRESSION_PARSER, evaluationContextProvider); } else if (queryMethod.hasAnnotatedQuery()) { return new StringBasedMongoQuery(queryMethod, operations, EXPRESSION_PARSER, evaluationContextProvider); } else { return new PartTreeMongoQuery(queryMethod, operations); } }
這裡,無@Query註解,進入PartTreeMongoQuery分支
public PartTreeMongoQuery(MongoQueryMethod method, MongoOperations mongoOperations) { super(method, mongoOperations); this.processor = method.getResultProcessor(); this.tree = new PartTree(method.getName(), processor.getReturnedType().getDomainType()); this.isGeoNearQuery = method.isGeoNearQuery(); this.context = mongoOperations.getConverter().getMappingContext(); } public class PartTree { private static final String KEYWORD_TEMPLATE = "(%s)(?=(\\p{Lu}|\\P{InBASIC_LATIN}))"; private static final String QUERY_PATTERN = "find|read|get|query|stream"; private static final String COUNT_PATTERN = "count"; private static final String EXISTS_PATTERN = "exists"; private static final String DELETE_PATTERN = "delete|remove"; private static final Pattern PREFIX_TEMPLATE = Pattern.compile( // "^(" + QUERY_PATTERN + "|" + COUNT_PATTERN + "|" + EXISTS_PATTERN + "|" + DELETE_PATTERN + ")((\\p{Lu}.*?))??By"); public PartTree(String source, Class<?> domainClass) { ...... Matcher matcher = PREFIX_TEMPLATE.matcher(source); if (!matcher.find()) { this.subject = new Subject(null); this.predicate = new Predicate(source, domainClass); } else { this.subject = new Subject(matcher.group(0)); this.predicate = new Predicate(source.substring(matcher.group().length()), domainClass); } } }
最終生成的query,已經將name(key)解析出來了。
至此,終於解析完,怎麼建立的代理,怎麼根據方法名來解析sql。最後就是使用點
上面說了,使用時,會呼叫QueryExecutorMethodInterceptor.invoke
public Object invoke(MethodInvocation invocation) throws Throwable { Object result = doInvoke(invocation); return resultHandler.postProcessInvocationResult(result, invocation.getMethod()); } private Object doInvoke(MethodInvocation invocation) throws Throwable { Method method = invocation.getMethod(); Object[] arguments = invocation.getArguments(); if (isCustomMethodInvocation(invocation)) { Method actualMethod = repositoryInformation.getTargetClassMethod(method); return executeMethodOn(customImplementation, actualMethod, arguments); } if (hasQueryFor(method)) { return queries.get(method).execute(arguments); } // Lookup actual method as it might be redeclared in the interface // and we have to use the repository instance nevertheless Method actualMethod = repositoryInformation.getTargetClassMethod(method); return executeMethodOn(target, actualMethod, arguments); }
queries.get(method)得到PartTreeMongoQuery
public Object execute(Object[] parameters) { MongoParameterAccessor accessor = new MongoParametersParameterAccessor(method, parameters); Query query = createQuery(new ConvertingParameterAccessor(operations.getConverter(), accessor)); applyQueryMetaAttributesWhenPresent(query); ResultProcessor processor = method.getResultProcessor().withDynamicProjection(accessor); String collection = method.getEntityInformation().getCollectionName(); MongoQueryExecution execution = getExecution(query, accessor, new ResultProcessingConverter(processor, operations, instantiators)); return execution.execute(query, processor.getReturnedType().getDomainType(), collection); }
構件出Query得到結果返回