Spring Data之EntityManager创建及源码分析

背景

前一篇文章介绍了EntityManagerFactory的创建过程,有了EntityManagerFactory接下来就是要获取EntityManager了,但EntityManager的创建不再是通过@Conditional注解,而是使用的@PersistenceContext注解,那么Spring Data是如何识别@PersistenceContext注解,并注入EntityManager实例的,又是怎样通过上一步创建的EntityManagerFactory来获取EntityManager的呢?这篇文章就来分析这两个问题。

动态注册Bean

日常开发中我们一般会在类上使用@Service、@Component或者在方法上使用@Bean注解,被注解的类或者方法的返回值的对象实例会被Spring维护到ApplicationContext中,在使用的时可以通过@Autowired、@Resource注解的类变量自动注入对象实例。

如果不使用注解,通过编程的方式也能创建一个对象实例交由ApplicationContext管理。

BeanDefinitionBuilder

 /**
 * Description:通过编码的方式创建一个Bean实例
 */
public class BeanDefinitionBuilderTest {

    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        //使用builder构建一个MyBean的Bean定义
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(MyBean.class);

        //为name属性赋值,会默认调用setName方法,如果没有setName方法会报错
        builder.addPropertyValue("name","张三");

        //往BeanFactory注册beanName为myBean的Bean定义
        beanFactory.registerBeanDefinition("myBean", builder.getRawBeanDefinition());

        //获取刚才注册的Bean
        MyBean myBean = beanFactory.getBean(MyBean.class);
        myBean.say();
    }

    private static class MyBean{
        private String name;

        public void setName(String name) {
            this.name = name;
        }

        public void say(){
            System.out.println("MyBean name is "+ name);
        }
    }
}

控制台输出

MyBean name is 张三

可以看到MyBean并未使用任何注解,而是通过BeanDefinitionBuilder创建了一个MyBean的实例并注册到beanFactory中,再从beanFactory获取出来调用say方法,为name设置的值被正确输出。

BeanFactoryPostProcessor

/**
 * Description:通过实现BeanFactoryPostProcessor接口创建对象实例
 *
 * @author fangliangsheng
 * @date 2018/11/18
 */
public class BeanFactoryPostProcessorTest {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        MyBean myBean = context.getBean(MyBean.class);

        myBean.say();
    }

    @Configuration
    public static class MyConfig{

        @Bean
        public MyConfigBean myConfigBean(){
            return new MyConfigBean();
        }
        
    }

    private static class MyConfigBean implements BeanFactoryPostProcessor{

        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(MyBean.class);
            builder.addPropertyValue("name","张三");

            ((DefaultListableBeanFactory) beanFactory)
                    .registerBeanDefinition("myBean", builder.getRawBeanDefinition());
        }
    }

    private static class MyBean{
        private String name;

        public void setName(String name) {
            this.name = name;
        }

        public void say(){
            System.out.println("MyBean name is "+ name);
        }
    }
}

控制台输出

MyBean name is 张三

BeanFactoryPostProcessor接口只有一个方法postProcessBeanFactory,该方法的调用时机是Application Context的Bean Factory初始化完成后。

InstantiationAwareBeanPostProcessor

private static class MyConfigBean3 implements InstantiationAwareBeanPostProcessor{
        @Override
        public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
            if (bean instanceof MyBean){
                System.out.println("set property value:" + beanName +" "+ pvs.getPropertyValues()[0].getName() + " "+pvs.getPropertyValues()[0].getValue());
            }

            return pvs;
        }
    }

控制台输出

set property value:myBean name 张三

InstantiationAwareBeanPostProcessor接口能够拦截对象实例化时对属性的赋值操作,实现该接口并判断想要监控的类及属性,在注入值时可以实现自己想要的逻辑。例如根据一个配置再赋值时选择不同的实例,或者通过编程的方式再动态创建一个实例。

这里介绍BeanDefinitionBuilder、BeanFactoryPostProcessor、InstantiationAwareBeanPostProcessor主要是因为在创建EntityManager时Spring Data就是通过这些接口的协作完成的。

创建EntityManager

先看自动配置的入口类

@Configuration
//当存在DataSource实例和JpaRepository类时生效
@ConditionalOnBean(DataSource.class)
@ConditionalOnClass(JpaRepository.class)
//当还没有JpaRepositoryFactoryBean和JpaRepositoryConfigExtension实例时生效
//因为后面会创建这两个类的实例,意思就是不能重复创建
@ConditionalOnMissingBean({ JpaRepositoryFactoryBean.class,
		JpaRepositoryConfigExtension.class })
@ConditionalOnProperty(prefix = "spring.data.jpa.repositories", name = "enabled", havingValue = "true", matchIfMissing = true)
//条件校验通过后引入JpaRepositoriesAutoConfigureRegistrar
@Import(JpaRepositoriesAutoConfigureRegistrar.class)
//在HibernateJpaAutoConfiguration之后自动配置,这点很关键,因为要现有EntityManagerFactory,这步的EntityManager才能创建
@AutoConfigureAfter(HibernateJpaAutoConfiguration.class)
public class JpaRepositoriesAutoConfiguration {

}

Import的JpaRepositoriesAutoConfigureRegistrar继承了AbstractRepositoryConfigurationSourceSupport,我们先看这个抽象类。
在这里插入图片描述
该抽象类有很多子类,看到类名是不是有点眼熟,这些就是Spring JPA支持的持久化实现。

public abstract class AbstractRepositoryConfigurationSourceSupport
		implements BeanFactoryAware, ImportBeanDefinitionRegistrar, ResourceLoaderAware,
		EnvironmentAware {
		
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
			BeanDefinitionRegistry registry) {
		new RepositoryConfigurationDelegate(getConfigurationSource(registry),
				this.resourceLoader, this.environment).registerRepositoriesIn(registry,
						getRepositoryConfigurationExtension());
	}
}

它继承了ImportBeanDefinitionRegistrar接口实现了registerBeanDefinitions方法,这是一个重要的切入点。registerBeanDefinitions方法的第二个入参是BeanDefinitionRegistry,通过这个registry接口就可以往Bean Factory注册各种实例了。具体的创建是交给RepositoryConfigurationDelegate待办的。

/**
* 定义Repository的创建步骤
* 通过RepositoryConfigurationSource的配置来源和RepositoryConfigurationExtension的具体实现
*/
public class RepositoryConfigurationDelegate {

	private final RepositoryConfigurationSource configurationSource;

	/**
	 * 将找到的repositories注册到BeanDefinitionRegistry中
	 * 类似于模版方法
	 */
	public List<BeanComponentDefinition> registerRepositoriesIn(BeanDefinitionRegistry registry,
			RepositoryConfigurationExtension extension) {

		extension.registerBeansForRoot(registry, configurationSource);

		RepositoryBeanDefinitionBuilder builder = new RepositoryBeanDefinitionBuilder(registry, extension, resourceLoader,
				environment);
		List<BeanComponentDefinition> definitions = new ArrayList<>();

		//找到Repository接口的子类并封装为RepositoryConfiguration
		//Repository的子类也就是我们平时开发所定义的例如UserRepository
		for (RepositoryConfiguration<? extends RepositoryConfigurationSource> configuration : extension
				.getRepositoryConfigurations(configurationSource, resourceLoader, inMultiStoreMode)) {

			//将configuration转化为BeanDefinitionBuilder,用于创建具体的实例
			BeanDefinitionBuilder definitionBuilder = builder.build(configuration);

			//EntityManager如何创建的答案就在这个地方了
			//这里extension的子类是JpaRepositoryConfigExtension
			extension.postProcess(definitionBuilder, configurationSource);

			if (isXml) {
				extension.postProcess(definitionBuilder, (XmlRepositoryConfigurationSource) configurationSource);
			} else {
				extension.postProcess(definitionBuilder, (AnnotationRepositoryConfigurationSource) configurationSource);
			}

			AbstractBeanDefinition beanDefinition = definitionBuilder.getBeanDefinition();
			String beanName = configurationSource.generateBeanName(beanDefinition);

			if (LOGGER.isDebugEnabled()) {
				LOGGER.debug(REPOSITORY_REGISTRATION, extension.getModuleName(), beanName,
						configuration.getRepositoryInterface(), configuration.getRepositoryFactoryBeanClassName());
			}

			beanDefinition.setAttribute(FACTORY_BEAN_OBJECT_TYPE, configuration.getRepositoryInterface());

			registry.registerBeanDefinition(beanName, beanDefinition);
			definitions.add(new BeanComponentDefinition(beanDefinition, beanName));
		}

		return definitions;
	}
}

接下来看下JpaRepositoryConfigExtension的实现

public class JpaRepositoryConfigExtension extends RepositoryConfigurationExtensionSupport
	//该方法是在上一个类的registerRepositoriesIn中调用的
	//给builder指定类entityManager属性的赋值方法
	@Override
	public void postProcess(BeanDefinitionBuilder builder, RepositoryConfigurationSource source) {

		Optional<String> transactionManagerRef = source.getAttribute("transactionManagerRef");
		builder.addPropertyValue("transactionManager", transactionManagerRef.orElse(DEFAULT_TRANSACTION_MANAGER_BEAN_NAME));
		builder.addPropertyValue("entityManager", getEntityManagerBeanDefinitionFor(source, source.getSource()));
		builder.addPropertyReference("mappingContext", JPA_MAPPING_CONTEXT_BEAN_NAME);
	}

	//通过BeanDefinitionBuilder定义了SharedEntityManagerCreator的createSharedEntityManager
	//为entityManager的创建方法
	private static AbstractBeanDefinition getEntityManagerBeanDefinitionFor(RepositoryConfigurationSource config,
			@Nullable Object source) {

		BeanDefinitionBuilder builder = BeanDefinitionBuilder
				.rootBeanDefinition("org.springframework.orm.jpa.SharedEntityManagerCreator");
		builder.setFactoryMethod("createSharedEntityManager");
		builder.addConstructorArgReference(getEntityManagerBeanRef(config));

		AbstractBeanDefinition bean = builder.getRawBeanDefinition();
		bean.setSource(source);

		return bean;
	}
}

结合动态注册Bean章节的内容,可以知道BeanDefinitionBuilder的作用。所以EntityManager的实际创建是通过SharedEntityManagerCreator的createSharedEntityManager方法。以上只是定义好了BeanDefinitionBuilder,builder中属性的赋值操作是对象实际实例时调用的。

接下来我们再看PersistenceAnnotationBeanPostProcessor,该类继承了InstantiationAwareBeanPostProcessor实现了postProcessPropertyValues方法,在动态注册Bean章节中,介绍了postProcessPropertyValues的作用。

public class PersistenceAnnotationBeanPostProcessor
		implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor,
		MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware, Serializable{

    //拦截实例化对象时的赋值操作
	@Override
	public PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {

		//找到@PersistenceContext、@PersistenceUnit注解的方法
		InjectionMetadata metadata = findPersistenceMetadata(beanName, bean.getClass(), pvs);
		try {
			metadata.inject(bean, beanName, pvs);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of persistence dependencies failed", ex);
		}
		return pvs;
	}
}

PersistenceAnnotationBeanPostProcessor的作用是实现PersistenceContext和PersistenceUnit注解的作用,即JPA规范定义通过@PersistenceContext注解的方法或者属性将会注入EntityManger实例,@PersistenceUnit注解的方法或者属性将会注入EntityManagerFactory实例.

结束

这篇文章主要分析了EntityManger的创建过程,

  1. AbstractRepositoryConfigurationSourceSupport的registerBeanDefinitions为切入点
  2. RepositoryConfigurationDelegate定义创建步骤
  3. JpaRepositoryConfigExtension通过BeanDefinitionBuilder指定了EntityManager的具体创建方法

以上涉及到的相关类,用一张类图展示
在这里插入图片描述

EntityManager是为谁创建的呢,创建出来后又是如何使用的呢,下一篇文章继续分析。

猜你喜欢

转载自blog.csdn.net/f4761/article/details/84133768