【源码】Spring Data JPA原理解析之Repository的自动注入(二)

 Spring Data JPA系列

1、SpringBoot集成JPA及基本使用

2、Spring Data JPA Criteria查询、部分字段查询

3、Spring Data JPA数据批量插入、批量更新真的用对了吗

4、Spring Data JPA的一对一、LazyInitializationException异常、一对多、多对多操作

5、Spring Data JPA自定义Id生成策略、复合主键配置、Auditing使用

6、【源码】Spring Data JPA原理解析之Repository的自动注入(一)

7、【源码】Spring Data JPA原理解析之Repository的自动注入(二)

8、【源码】Spring Data JPA原理解析之Repository执行过程及SimpleJpaRepository源码

9、【源码】Spring Data JPA原理解析之Repository自定义方法命名规则执行原理(一)

前言

上一篇限于篇幅,只讲解了Repository对应的BeanDefinition加入到Spring容器。在Spring框架中,Bean的自动装载分为两步,第一步是扫描并注册Bean的BeanDefinition到Spring容器,第二步实例化Bean对象、属性赋值并初始化。这一篇,继续分析Repository是如何被实例化的。

Repository实例化

通过手动的调用Spring容器的getBean()或者对应的Bean作为其他Bean的属性被赋值的时候,都会对对应的Bean进行实例化。实例化的入口在AbstractBeanFactory.getBean()方法。

AbstractBeanFactory核心代码如下:

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
    @Override
	public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}

	@Override
	public <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException {
		return doGetBean(name, requiredType, null, false);
	}

	@Override
	public Object getBean(String name, Object... args) throws BeansException {
		return doGetBean(name, null, args, false);
	}

	public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)
			throws BeansException {

		return doGetBean(name, requiredType, args, false);
	}

	/**
	 * 返回一个实例
	 */
	@SuppressWarnings("unchecked")
	protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {
		// 获取对应的beanName,如果bean对象实现FactoryBean接口,name会变成&beanName,另外如果存在别名,也需要进行转换
		// 会分析是否 以 & 从而为获取beanfactory 实例
		String beanName = transformedBeanName(name);
		// 定义一个对象,用来存放将来返回出来的bean
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
		// 提前检查单例缓冲中是否有手动注册的单例对象
		/**
		 * 一个bean被put到单例池的渠道有很多;除了spring容器初始化—扫描类----实例化-----put到容器这条线之外还有很多方法可以把一个对象put到单例池
		 * 举例说明实现方式:
		 * 1、new AnnotationConfigApplicationContenxt()对象ac,先不指定配置类
		 * 2、调用ac.getBeanFactory().registerSingleton("xx", a),即将a对象添加到单例池中
		 * 3、调用ac.register(App.class),添加配置类
		 * 4、调用ac.refresh(),执行refresh()时,在初始化时会扫描到A,此时a对象已经在单例池里了,所以需要有此判断
		 */
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			if (logger.isDebugEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
			// 返回对象的实例,当实现了FactoryBean接口的对象,需要获取具体的对象的时候需要此方法来进行获取
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		else {
			// 当对象都是单例的时候会尝试解决循环依赖的问题,但是原型模式下如果存在循环依赖的情况就直接抛出异常
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}
.
			// 获取父类容器
			BeanFactory parentBeanFactory = getParentBeanFactory();
			// 如果beanDefinitionMap中也就是在所有已经加载的类中不包含beanName,那么就尝试从父容器中获取
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// Not found -> check parent.
				//获取name对应的规范名称【全类名】,如果name前面有'&',则会返回'&'+规范名称【全类名】
				String nameToLookup = originalBeanName(name);
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					//调用父工厂的doGetBean方法,递归调用当前方法
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				else if (args != null) {//如果有创建bean实例时要使用的参数
					// Delegation to parent with explicit args.
					// 使用父工厂获取该bean对象带参数获取对象
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else {
					// No args -> delegate to standard getBean method.
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
			}
			// 如果不是做类型检查,那么表示要创建bean,此处在集合中做一个标记
			if (!typeCheckOnly) {
				// 将其加入到 alreadyCreated中,说明正在创建。bean从 mergedBeanDefinitions 中暂时去除,以免再次创建
				markBeanAsCreated(beanName);
			}

			try {
				// 此处做了BeanDefinition对象的转换,当从xml文件中加载beanDefinition对象的时候,封装的对象是GenericBeanDefinition,
				// 此处要做类型转换,如果是子类bean的话,会合并父类的相关属性
				RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				// 判断当前bean 类,是否为抽象类,是就报错
				checkMergedBeanDefinition(mbd, beanName, args);

				// Guarantee initialization of beans that the current bean depends on.
				// 如果存在依赖的bean的话,那么则优先实例化依赖的bean
				String[] dependsOn = mbd.getDependsOn();
				if (dependsOn != null) {
					// 如果存在依赖,则需要递归实例化依赖的bean
					for (String dep : dependsOn) {
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						// 注册各个bean的依赖关系,方便进行销毁
						registerDependentBean(dep, beanName);
						try {
							// 优先获取 dependon的bean
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}

				// Create bean instance.
				// 创建bean的实例对象
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							// 创建bean
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							destroySingleton(beanName);
							throw ex;
						}
					});
					// 包装一层
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
				// 原型模式的bean对象创建
				else if (mbd.isPrototype()) {
					// It's a prototype -> create a new instance.
					// 原型模式,即每次都创建
					Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
					// 包装
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}

				else {
					String scopeName = mbd.getScope();
					if (!StringUtils.hasLength(scopeName)) {
						throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
					}
					Scope scope = this.scopes.get(scopeName);
					if (scope == null) {
						throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
					}
					try {
						// 调用scope.get,而还是由createBean去创建bean
						Object scopedInstance = scope.get(beanName, () -> {
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							}
							finally {
								afterPrototypeCreation(beanName);
							}
						});
						bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
					}
					catch (IllegalStateException ex) {
						throw new BeanCreationException(beanName,
								"Scope '" + scopeName + "' is not active for the current thread; consider " +
								"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
								ex);
					}
				}
			}
			catch (BeansException ex) {
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
		}

		// Check if required type matches the type of the actual bean instance.
		if (requiredType != null && !requiredType.isInstance(bean)) {
			try {
				T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
				if (convertedBean == null) {
					throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
				}
				return convertedBean;
			}
			catch (TypeMismatchException ex) {
				if (logger.isDebugEnabled()) {
					logger.debug("Failed to convert bean '" + name + "' to required type '" +
							ClassUtils.getQualifiedName(requiredType) + "'", ex);
				}
				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
		}
		return (T) bean;
	}

    protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

		// Don't let calling code try to dereference the factory if the bean isn't a factory.
		// 如果Bean不是工厂,不要让调用代码尝试取消对工厂的引用
		// 判断是否为工厂引用。通过name是否以'&'开头来判断,是的话为FactoryBean
		if (BeanFactoryUtils.isFactoryDereference(name)) {
			if (beanInstance instanceof NullBean) {
				return beanInstance;
			}
			if (!(beanInstance instanceof FactoryBean)) {
				throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
			}
		}

		// 如果不是工厂实例,直接返回。除非调用者确实需要对工厂的引用,也直接返回
		if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
			return beanInstance;
		}

		// 从工厂bean中获取bean对象
		Object object = null;
		if (mbd == null) {
			//从FactoryBean获得的对象缓存集中获取beanName对应的Bean对象
			object = getCachedObjectForFactoryBean(beanName);
		}
		if (object == null) {
			// Return bean instance from factory.
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			// 如果对象是单例,则从FactoryBean缓存中获得对象
			// 如果mbd为null,且该bean的mbd在缓存中,则从缓存中获取mbd
			if (mbd == null && containsBeanDefinition(beanName)) {
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			// 是否是'synthetic'标记:mbd不为null && 返回此bean定义是否是"synthetic"
			// 【一般只有AOP相关的pointCut配置或者Advice配置才会将 synthetic设置为true】
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			//从BeanFactory对象中获取管理的对象.如果不是synthetic会对其对象进行该工厂的后置处理
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}
}

1.1 doGetBean()方法的核心逻辑是:

1.1.1 从单例池ConcurrentHashMap中通过beanName获取对应的对象bean实例,如果有,则调用getObjectForBeanInstance()返回;

1.1.2 如果没有,且有父Bean工厂,从父Bean工厂查找,递归调用doGetBean()方法;

1.1.3 否则获取beanName对应的RootBeanDefinition对象,该对象是基于beanName的BeanDefinition对象创建的;

1.1.4 调用createBean()创建bean实例,如果bean是单例的,会添加到单例池中。然后调用getObjectForBeanInstance()返回;

1.2 getObjectForBeanInstance()方法

上面的1.1.1和1.1.4最后都会调用getObjectForBeanInstance()方法,返回bean是最终实例。返回的实例可能是1.1.4中createBean()返回的实例,也可能是通过createBean()返回的FactoryBean.getObject()生产的实例。方法的核心逻辑如下:

1.2.1 如果不是FactoryBean,或者beanName不是"&"开头的,直接返回对应的bean实例;

1.2.2 否则的话,说明当前bean对应的bean实例是一个FactoryBean工厂bean【专门生产bean的工厂】,最后会执行FactoryBean的getObject()获得实际的bean实例;

1.3 createBean()方法

在上面的1.1.4中会调用createBean()方法创建bean实例。该方法在子类AbstractAutowireCapableBeanFactory中实现。进行验证后,会调用doCreateBean()方法。代码如下:

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
		implements AutowireCapableBeanFactory {

    Override
	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		if (logger.isDebugEnabled()) {
			logger.debug("Creating instance of bean '" + beanName + "'");
		}
		RootBeanDefinition mbdToUse = mbd;

		// 锁定class,根据设置的class属性或者根据className来解析class
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}

		// Prepare method overrides.
		// 验证及准备覆盖的方法
		try {
			mbdToUse.prepareMethodOverrides();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
					beanName, "Validation of method overrides failed", ex);
		}

		try {
			// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
			// 给BeanPostProcessors一个机会来返回代理来替代真正的实例
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
					"BeanPostProcessor before instantiation of bean failed", ex);
		}

		try {
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isDebugEnabled()) {
				logger.debug("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}
		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
		}
	}

    protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			// 从factoryBean实例缓存中移除当前bean定义信息
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			// 根据执行bean使用对应的策略创建实例对象,仅仅是对象。检查如工厂方法、构造函数主动注入、简单实例化
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		// 可以通过post-processors去修改合并的beanDefinition
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					// 应用MergedBeanDefinitionPostProcessors
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

		// 判断当前bean是否需要提前曝光:单例&允许循环依赖&当前bean正在创建中,检查循环依赖
		/**
		 * 可以通过修改allowCircularReferences的值设置是否支持循环依赖,设置的方式有多种
		 * 方式一,通过继承方式
		 * 自定义一个ApplicationContext类,继承ClassPathXmlApplicationContext,重写customizeBeanFactory()方法
		 * 在customizeBeanFactory方法中执行如下代码进行属性值的修改
		 * super.setAllowBeanDefinitionOverriding(true);
		 * super.setAllowCircularReferences(false);
		 * super.customizeBeanFactory(beanFactory)
		 * 方式二,
		 * 1、new一个不带配置文件的ClassPathXmlApplicationContext或配置类AnnotationConfigApplicationContext对象
		 * 2、调用ApplicationContext对象的setAllowCircularReferences()方法,修改allowCircularReferences的值
		 * 3、调用ApplicationContext对象的设置配置文件或配置类的方法
		 * 4、调用ApplicationContext对象的refresh()方法,完成初始化扫描操作
 		 */
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isDebugEnabled()) {
				logger.debug("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			// 为避免后期循环依赖,可以在bean初始化完成前将创建实例的ObjectFactory加入工厂
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		Object exposedObject = bean;
		try {
			// 对bean属性进行填充,将各个属性注入。其中,可能存在依赖于其他bean的属性,则会递归初始化依赖的bean
			populateBean(beanName, mbd, instanceWrapper);
			// 执行初始化逻辑【主要执行各种生命周期回调方法以及AOP等】
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}

		if (earlySingletonExposure) {
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		// Register bean as disposable.
		try {
			// 注册bean销毁的监听
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}
}

1.3.1 resolveBeanClass()方法

createBean()方法调用resolveBeanClass()方法,resolveBeanClass() 会调用doResolveBeanClass()。在该方法中,会从RootBeanDefinition中获取beanClass,返回beanClass的Class对象。

在上一篇

【源码】Spring Data JPA原理解析之Repository的自动注入(一)-CSDN博客

提到,Repository的BeanDefinition中对应的beanClass为"org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean"字符串,获得的Class为JpaRepositoryFactoryBean.class。

1.3.2 doCreateBean()方法

1.3.2.1 执行createBeanInstance()方法,根据执行bean使用对应的策略创建实例对象,仅仅是对象。检查如工厂方法、构造函数主动注入、简单实例化;

1.3.2.2 执行applyMergedBeanDefinitionPostProcessors(),循环遍历实现MergedBeanDefinitionPostProcessor接口的后置处理器,执行后置处理;

1.3.2.3 执行populateBean(),对bean属性进行填充,注入各个属性;

1.3.2.4 执行initializeBean(),执行初始化逻辑;其中一个初始化是执行InitializingBean.afterPropertiesSet();

在createBean()中根据BeanDefinition中的beanClass,创建一个bean的实例对象,然后调用1.2中的getObjectForBeanInstance()方法,

JpaRepositoryFactoryBean

对于Repository来说,通过1.3.2.1创建的实例为1.3.1中说的JpaRepositoryFactoryBean对象,该对象实现了InitializingBean接口,在1.3.2.4中,会执行InitializingBean.afterPropertiesSet()方法。该方法会执行父类RepositoryFactoryBeanSupport的.afterPropertiesSet()方法。

public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>, S, ID>
		implements InitializingBean, RepositoryFactoryInformation<S, ID>, FactoryBean<T>, BeanClassLoaderAware,
		BeanFactoryAware, ApplicationEventPublisherAware {

    public void afterPropertiesSet() {
		// 创建一个Repository工厂,TransactionalRepositoryFactoryBeanSupport对象
		this.factory = createRepositoryFactory();
		// 工厂赋值
		this.factory.setQueryLookupStrategyKey(queryLookupStrategyKey);
		this.factory.setNamedQueries(namedQueries);
		this.factory.setEvaluationContextProvider(
				evaluationContextProvider.orElseGet(() -> QueryMethodEvaluationContextProvider.DEFAULT));
		this.factory.setBeanClassLoader(classLoader);
		this.factory.setBeanFactory(beanFactory);

		if (publisher != null) {
			this.factory.addRepositoryProxyPostProcessor(new EventPublishingRepositoryProxyPostProcessor(publisher));
		}

		repositoryBaseClass.ifPresent(this.factory::setRepositoryBaseClass);

		this.repositoryFactoryCustomizers.forEach(customizer -> customizer.customize(this.factory));

		RepositoryFragments customImplementationFragment = customImplementation //
				.map(RepositoryFragments::just) //
				.orElseGet(RepositoryFragments::empty);

		RepositoryFragments repositoryFragmentsToUse = this.repositoryFragments //
				.orElseGet(RepositoryFragments::empty) //
				.append(customImplementationFragment);

		this.repositoryMetadata = this.factory.getRepositoryMetadata(repositoryInterface);
		// 执行工厂的getRepository()方法,创建一个代理的Repository对象
		this.repository = Lazy.of(() -> this.factory.getRepository(repositoryInterface, repositoryFragmentsToUse));

		// Make sure the aggregate root type is present in the MappingContext (e.g. for auditing)
		this.mappingContext.ifPresent(it -> it.getPersistentEntity(repositoryMetadata.getDomainType()));

		if (!lazyInit) {
			this.repository.get();
		}
	}
}

在该方法中,调用factory.getRepository()获取Repository对象。实现在RepositoryFactorySupport类。代码如下:

public abstract class RepositoryFactorySupport implements BeanClassLoaderAware, BeanFactoryAware {
    /**
	 * 返回给定接口的存储库实例,该实例由为自定义逻辑提供实现逻辑的实例支持。
	 */
	@SuppressWarnings({ "unchecked" })
	public <T> T getRepository(Class<T> repositoryInterface, RepositoryFragments fragments) {

		if (logger.isDebugEnabled()) {
			logger.debug(LogMessage.format("Initializing repository instance for %s…", repositoryInterface.getName()));
		}

		Assert.notNull(repositoryInterface, "Repository interface must not be null");
		Assert.notNull(fragments, "RepositoryFragments must not be null");

		ApplicationStartup applicationStartup = getStartup();

		StartupStep repositoryInit = onEvent(applicationStartup, "spring.data.repository.init", repositoryInterface);

		repositoryBaseClass.ifPresent(it -> repositoryInit.tag("baseClass", it.getName()));

		StartupStep repositoryMetadataStep = onEvent(applicationStartup, "spring.data.repository.metadata",
				repositoryInterface);
		// 获取repository元数据,包括Repository<T, ID>中的T类型、ID类型、接口类型(如GoodsRepository)等
		RepositoryMetadata metadata = getRepositoryMetadata(repositoryInterface);
		repositoryMetadataStep.end();

		StartupStep repositoryCompositionStep = onEvent(applicationStartup, "spring.data.repository.composition",
				repositoryInterface);
		repositoryCompositionStep.tag("fragment.count", String.valueOf(fragments.size()));
		// 获取
		RepositoryComposition composition = getRepositoryComposition(metadata, fragments);
		// 获取Repository信息,getRepositoryInformation()返回一个RepositoryInformation对象。
		// 如子类JpaRepositoryFactory,指定baseClass为SimpleJpaRepository.class
		RepositoryInformation information = getRepositoryInformation(metadata, composition);

		repositoryCompositionStep.tag("fragments", () -> {

			StringBuilder fragmentsTag = new StringBuilder();

			for (RepositoryFragment<?> fragment : composition.getFragments()) {

				if (fragmentsTag.length() > 0) {
					fragmentsTag.append(";");
				}

				fragmentsTag.append(fragment.getSignatureContributor().getName());
				fragmentsTag.append(fragment.getImplementation().map(it -> ":" + it.getClass().getName()).orElse(""));
			}

			return fragmentsTag.toString();
		});

		repositoryCompositionStep.end();

		StartupStep repositoryTargetStep = onEvent(applicationStartup, "spring.data.repository.target",
				repositoryInterface);
		// 获取目标Repository对象,SimpleJpaRepository对象
		Object target = getTargetRepository(information);

		repositoryTargetStep.tag("target", target.getClass().getName());
		repositoryTargetStep.end();

		RepositoryComposition compositionToUse = composition.append(RepositoryFragment.implemented(target));
		validate(information, compositionToUse);

		// Create proxy
		// 创建代理对象
		StartupStep repositoryProxyStep = onEvent(applicationStartup, "spring.data.repository.proxy", repositoryInterface);
		ProxyFactory result = new ProxyFactory();
		result.setTarget(target);
		// 代理对象实现的接口
		result.setInterfaces(repositoryInterface, Repository.class, TransactionalProxy.class);

		if (MethodInvocationValidator.supports(repositoryInterface)) {
			result.addAdvice(new MethodInvocationValidator());
		}
		// 添加界面
		result.addAdvisor(ExposeInvocationInterceptor.ADVISOR);

		if (!postProcessors.isEmpty()) {
			StartupStep repositoryPostprocessorsStep = onEvent(applicationStartup, "spring.data.repository.postprocessors",
					repositoryInterface);
			// 执行后置处理
			// CrudMethodMetadataPostProcessor
			// TransactionalRepositoryProxyPostProcessor
			// JpaRepositoryFactory构造方法中加入的内部处理器,
			// 添加SurroundingTransactionDetectorMethodInterceptor,记录是否处理状态
			// PersistenceExceptionTranslationRepositoryProxyPostProcessor
			// EventPublishingRepositoryProxyPostProcessor
			postProcessors.forEach(processor -> {

				StartupStep singlePostProcessor = onEvent(applicationStartup, "spring.data.repository.postprocessor",
						repositoryInterface);
				singlePostProcessor.tag("type", processor.getClass().getName());
				processor.postProcess(result, information);
				singlePostProcessor.end();
			});
			repositoryPostprocessorsStep.end();
		}

		if (DefaultMethodInvokingMethodInterceptor.hasDefaultMethods(repositoryInterface)) {
			// 添加DefaultMethodInvokingMethodInterceptor拦截器
			result.addAdvice(new DefaultMethodInvokingMethodInterceptor());
		}

		Optional<QueryLookupStrategy> queryLookupStrategy = getQueryLookupStrategy(queryLookupStrategyKey,
				evaluationContextProvider);
		// 添加QueryExecutorMethodInterceptor拦截器
		result.addAdvice(new QueryExecutorMethodInterceptor(information, getProjectionFactory(), queryLookupStrategy,
				namedQueries, queryPostProcessors, methodInvocationListeners));
		// 添加ImplementationMethodExecutionInterceptor拦截器
		result.addAdvice(
				new ImplementationMethodExecutionInterceptor(information, compositionToUse, methodInvocationListeners));

		T repository = (T) result.getProxy(classLoader);
		repositoryProxyStep.end();
		repositoryInit.end();

		if (logger.isDebugEnabled()) {
			logger
					.debug(LogMessage.format("Finished creation of repository instance for %s.",
				repositoryInterface.getName()));
		}

		return repository;
	}
}

在该方法中,使用ProxyFactory代理,代理实现了自定义的Repository接口、Repository以及TransactionProxy接口,且代理的target为SimpleJpaRepository对象。添加了MethodInvocationValidator、ExposeInvocationInterceptor、DefaultMethodInvokingMethodInterceptor、QueryExecutorMethodInterceptor、ImplementationMethodExecutionInterceptor拦截器。

小结

限于篇幅,本篇就分享到这里,这里做一个小结:

1)在Spring中,会执行AbstractBeanFactory.doGetBean()方法,先从Repository的BeanDefinition中,获取beanClass,为JpaRepositoryFactoryBean类名,然后创建JpaRepositoryFactoryBean对象。执行afterPropertiesSet()方法,完成初始化;

2)在JpaRepositoryFactoryBean的afterPropertiesSet()初始化方法中,会调用RepositoryFactorySupport.getRepository()方法。该方法通过代理的的方式,创建一个实现了自定义的Repository接口、Repository以及TransactionProxy接口,且代理的target为SimpleJpaRepository对象。代理的对象保存在repository属性中;

3)在Spring中,执行了JpaRepositoryFactoryBean对象的afterPropertiesSet()初始化之后,会调用AbstractBeanFactory.getObjectForBeanInstance(),从JpaRepositoryFactoryBean工厂bean中执行getObject(),返回创建的代理repository对象;

关于本篇内容你有什么自己的想法或独到见解,欢迎在评论区一起交流探讨下吧。

  • 26
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很抱歉,由于篇幅限制,我无法在这里提供整个项目的完整代码。但我可以为您提供一些示例代码来演示如何实现根据不同的登录方式使用不同的数据库操作方式。 首先,您可以创建一个包含用户信息的数据库表,并在应用程序中创建对应的Java实体类。例如,以下代码显示了一个名为User的实体类: ```java @Entity @Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String username; private String email; private String phone; private String password; // getters and setters } ``` 接下来,您可以为每种数据库操作方式创建相应的DAO接口。例如,以下代码显示了一个名为UserJdbcDao的JDBC DAO接口: ```java public interface UserJdbcDao { User findByUsernameAndPassword(String username, String password); } ``` 然后,您可以实现这些DAO接口。例如,以下代码显示了一个名为UserJdbcDaoImpl的JDBC DAO实现类: ```java @Repository public class UserJdbcDaoImpl implements UserJdbcDao { private final JdbcTemplate jdbcTemplate; @Autowired public UserJdbcDaoImpl(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } @Override public User findByUsernameAndPassword(String username, String password) { String sql = "SELECT * FROM users WHERE username = ? AND password = ?"; return jdbcTemplate.queryForObject(sql, new Object[]{username, password}, new UserRowMapper()); } private static class UserRowMapper implements RowMapper<User> { @Override public User mapRow(ResultSet rs, int rowNum) throws SQLException { User user = new User(); user.setId(rs.getLong("id")); user.setUsername(rs.getString("username")); user.setEmail(rs.getString("email")); user.setPhone(rs.getString("phone")); user.setPassword(rs.getString("password")); return user; } } } ``` 类似地,您可以创建相应的MyBatis DAO接口和Spring Data JPA DAO接口,并实现它们。 最后,您可以创建一个处理登录请求的控制器,并在其中根据用户输入的登录信息选择使用哪种DAO。例如,以下代码显示了一个名为LoginController的登录控制器: ```java @RestController @RequestMapping("/login") public class LoginController { private final UserJdbcDao userJdbcDao; private final UserMyBatisDao userMyBatisDao; private final UserRepository userRepository; @Autowired public LoginController(UserJdbcDao userJdbcDao, UserMyBatisDao userMyBatisDao, UserRepository userRepository) { this.userJdbcDao = userJdbcDao; this.userMyBatisDao = userMyBatisDao; this.userRepository = userRepository; } @PostMapping public ResponseEntity<?> login(@RequestBody LoginRequest loginRequest) { User user; if (isEmail(loginRequest.getUsername())) { user = userMyBatisDao.findByEmailAndPassword(loginRequest.getUsername(), loginRequest.getPassword()); } else if (isPhone(loginRequest.getUsername())) { user = userRepository.findByPhoneAndPassword(loginRequest.getUsername(), loginRequest.getPassword()); } else { user = userJdbcDao.findByUsernameAndPassword(loginRequest.getUsername(), loginRequest.getPassword()); } if (user == null) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } else { return ResponseEntity.ok(user); } } private boolean isEmail(String str) { // check if str is a valid email } private boolean isPhone(String str) { // check if str is a valid phone number } } ``` 在上面的代码中,LoginController使用了@Autowired注解注入了UserJdbcDao、UserMyBatisDao和UserRepository。然后,它使用isEmail()和isPhone()方法来判断用户输入的登录信息是用户名、邮箱还是手机号,并根据不同的情况选择使用不同的DAO。 当然,这只是一个简单的示例,您需要根据您的具体需求进行修改和完善。但是,希望这可以为您提供一些帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值