对于最新的稳定版本,请使用 Spring Framework 7.0.6!spring-doc.cadn.net.cn

JPA

Spring JPA,可在 org.springframework.orm.jpa 包下获得,提供了对 Java Persistence API 的全面支持,其方式类似于与 Hibernate 的集成,同时了解底层实现以提供额外的功能。spring-doc.cadn.net.cn

Spring环境中JPA配置的三种方案

Spring JPA 支持提供了三种设置应用程序用于获取实体管理器的 JPA EntityManagerFactory 的方法。spring-doc.cadn.net.cn

使用 LocalEntityManagerFactoryBean

你只能在简单的部署环境(如独立应用程序和集成测试)中使用此选项。spring-doc.cadn.net.cn

LocalEntityManagerFactoryBean 会创建一个适合于仅使用 JPA 进行数据访问的简单部署环境的 EntityManagerFactory。 工厂 Bean 使用 JPA PersistenceProvider 的自动检测机制(根据 JPA 的 Java SE 引导方式),在大多数情况下,只需指定持久化单元名称即可。以下 XML 示例配置了这样的 Bean:spring-doc.cadn.net.cn

<beans>
	<bean id="myEmf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
		<property name="persistenceUnitName" value="myPersistenceUnit"/>
	</bean>
</beans>

这种JPA部署方式最简单,但功能也最有限。您无法引用现有的JDBC DataSource bean定义,也没有全局事务的支持。此外,持久化类的编织(字节码转换)是提供商特定的,通常需要在启动时指定特定的JVM代理。此选项仅适用于独立应用程序和测试环境,这正是JPA规范所设计的用途。spring-doc.cadn.net.cn

从JNDI获取EntityManagerFactory

在部署到 Jakarta EE 服务器时,您可以使用此选项。请查阅服务器文档了解如何将自定义 JPA 提供程序部署至服务器,从而允许使用与服务器默认提供程序不同的提供程序。spring-doc.cadn.net.cn

从JNDI获取EntityManagerFactory(例如在Jakarta EE环境中),只需修改XML配置即可,如下例所示:spring-doc.cadn.net.cn

<beans>
	<jee:jndi-lookup id="myEmf" jndi-name="persistence/myPersistenceUnit"/>
</beans>

此操作假设采用标准的Jakarta EE引导过程。Jakarta EE服务器会自动检测 持久化单元(实质上是应用jar包中的META-INF/persistence.xml文件)以及 Jakarta EE部署描述符中的persistence-unit-ref条目(例如 web.xml),并为这些持久化单元定义环境命名上下文位置。spring-doc.cadn.net.cn

在此场景下,整个持久化单元部署(包括持久化类的编织(字节码转换))由 Jakarta EE 服务器负责。JDBC DataSourceMETA-INF/persistence.xml 文件中通过 JNDI 位置定义。 EntityManager 事务与服务器的 JTA 子系统集成。Spring 仅使用获取的 EntityManagerFactory,通过依赖注入将其传递给应用对象,并管理持久化单元的事务(通常通过 JtaTransactionManager 实现)。spring-doc.cadn.net.cn

如果在同一个应用程序中使用多个持久化单元,通过JNDI检索到的持久化单元的bean名称应与应用程序用来引用它们的持久化单元名称匹配(例如,在@PersistenceUnit@PersistenceContext注释中)。spring-doc.cadn.net.cn

使用 LocalContainerEntityManagerFactoryBean

你可以使用此选项在基于 Spring 的应用程序环境中实现完整的 JPA 功能。 这包括如 Tomcat 等 Web 容器、独立应用程序以及具有复杂持久化需求的集成测试。spring-doc.cadn.net.cn

LocalContainerEntityManagerFactoryBean 提供了对 EntityManagerFactory 配置的完全控制,并且适用于需要精细自定义的环境。LocalContainerEntityManagerFactoryBean 会根据 persistence.xml 文件、提供的 dataSourceLookup 策略以及指定的 loadTimeWeaver 创建一个 PersistenceUnitInfo 实例。因此,可以使用 JNDI 之外的自定义数据源并控制织入过程。下面的示例显示了一个 LocalContainerEntityManagerFactoryBean 的典型 bean 定义:spring-doc.cadn.net.cn

<beans>
	<bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="dataSource" ref="someDataSource"/>
		<property name="loadTimeWeaver">
			<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
		</property>
	</bean>
</beans>

以下示例显示了一个典型的 persistence.xml 文件:spring-doc.cadn.net.cn

<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
	<persistence-unit name="myUnit" transaction-type="RESOURCE_LOCAL">
		<mapping-file>META-INF/orm.xml</mapping-file>
		<exclude-unlisted-classes/>
	</persistence-unit>
</persistence>
<exclude-unlisted-classes/> 快捷方式表示不进行带注解的实体类扫描。显式的 'true' 值(<exclude-unlisted-classes>true</exclude-unlisted-classes/>)也表示不进行扫描。 <exclude-unlisted-classes>false</exclude-unlisted-classes/> 会触发扫描。 然而,如果我们希望进行实体类扫描,建议省略 exclude-unlisted-classes 元素。

使用 LocalContainerEntityManagerFactoryBean 是最强大的 JPA 设置选项,允许在应用程序内部进行灵活的本地配置。它支持链接到现有的 JDBC DataSource,支持本地和全局事务等。然而,它也对运行时环境提出了要求,例如如果持久化提供程序需要字节码转换,则需要具有织入能力的类加载器。spring-doc.cadn.net.cn

此选项可能与 Jakarta EE 服务器内置的 JPA 功能冲突。在完整的 Jakarta EE 环境中,建议从 JNDI 获取你的 EntityManagerFactory。 或者,在你的 LocalContainerEntityManagerFactoryBean 定义中指定一个自定义的 persistenceXmlLocation(例如 META-INF/my-persistence.xml),并在应用程序 jar 文件中仅包含该名称的描述符。 由于 Jakarta EE 服务器仅查找默认的 META-INF/persistence.xml 文件,它会忽略此类自定义持久化单元,从而避免与 Spring 驱动的 JPA 设置发生冲突(例如,这适用于 Resin 3.1)。spring-doc.cadn.net.cn

何时需要使用加载时织入?

并非所有JPA提供程序都需要JVM代理。Hibernate是一个不需要的示例。 如果您的提供程序不需要代理,或者您有其他替代方法,例如通过自定义编译器或Ant任务在构建时应用增强,则不应使用加载时编织器。spring-doc.cadn.net.cn

LoadTimeWeaver 接口是 Spring 提供的类,它允许根据环境是 Web 容器还是应用服务器,以特定方式插入 JPA ClassTransformer 实例。通过 代理 连接 ClassTransformers 通常效率不高。代理会针对整个虚拟机工作,并检查所有加载的类,这在生产服务器环境中通常是不希望的。spring-doc.cadn.net.cn

Spring 为各种环境提供了多个 LoadTimeWeaver 实现, 允许每个类加载器仅应用 ClassTransformer 个实例,而不是每个虚拟机。spring-doc.cadn.net.cn

查看AOP章节中的Spring配置,以获得更多关于LoadTimeWeaver实现及其设置的见解,无论是通用的还是针对各种平台(如Tomcat、JBoss和WebSphere)的定制版本。spring-doc.cadn.net.cn

LoadTimeWeaver中所述,可以通过使用@EnableLoadTimeWeaving注解或context:load-time-weaver XML元素来配置一个上下文范围的LoadTimeWeaver。这种全局编织器会被所有JPA LocalContainerEntityManagerFactoryBean实例自动识别。下面的例子展示了设置运行时编织器的首选方法,该方法可自动检测平台(例如Tomcat的具有编织功能的类加载器或Spring的JVM代理),并自动将编织器传播到所有具有编织感知的Bean:spring-doc.cadn.net.cn

<context:load-time-weaver/>

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	...
</bean>

但是,如果需要,您可以通过loadTimeWeaver属性手动指定一个专用的weaver,如下例所示:spring-doc.cadn.net.cn

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	<property name="loadTimeWeaver">
		<bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/>
	</property>
</bean>

无论LTW如何配置,通过此技术,依赖于instrumentation的JPA应用程序可以在目标平台(例如Tomcat)上运行,而无需使用代理。当托管的应用程序依赖于不同的JPA实现时,这一点尤为重要,因为JPA转换器仅在类加载器级别应用,因此彼此之间是隔离的。spring-doc.cadn.net.cn

处理多个持久化单元

对于依赖多个持久化单元位置(例如存储在类路径中的不同JAR中)的应用程序,Spring提供了PersistenceUnitManager作为中心仓库,以避免耗时的持久化单元发现过程。默认实现允许指定多个位置。这些位置会被解析,并通过持久化单元名称 later 检索。(默认情况下,会搜索类路径中的META-INF/persistence.xml文件。)以下示例配置了多个位置:spring-doc.cadn.net.cn

<bean id="pum" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
	<property name="persistenceXmlLocations">
		<list>
			<value>org/springframework/orm/jpa/domain/persistence-multi.xml</value>
			<value>classpath:/my/package/**/custom-persistence.xml</value>
			<value>classpath*:META-INF/persistence.xml</value>
		</list>
	</property>
	<property name="dataSources">
		<map>
			<entry key="localDataSource" value-ref="local-db"/>
			<entry key="remoteDataSource" value-ref="remote-db"/>
		</map>
	</property>
	<!-- if no datasource is specified, use this one -->
	<property name="defaultDataSource" ref="remoteDataSource"/>
</bean>

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	<property name="persistenceUnitManager" ref="pum"/>
	<property name="persistenceUnitName" value="myCustomUnit"/>
</bean>

默认实现允许在将PersistenceUnitInfo实例提供给JPA提供程序之前进行自定义,可以通过声明方式(通过其属性,这些属性会影响所有托管单元)或编程方式(通过PersistenceUnitPostProcessor,这允许选择持久化单元)进行自定义。如果没有指定PersistenceUnitManager,则会创建一个并在LocalContainerEntityManagerFactoryBean内部使用。spring-doc.cadn.net.cn

背景引导

LocalContainerEntityManagerFactoryBean 通过 bootstrapExecutor 属性支持后台引导,如下例所示:spring-doc.cadn.net.cn

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	<property name="bootstrapExecutor">
		<bean class="org.springframework.core.task.SimpleAsyncTaskExecutor"/>
	</property>
</bean>

实际的JPA提供程序引导由指定的执行器处理,然后,以并行方式,由应用程序引导线程处理。公开的<code>0</code> 代理可以注入到其他应用程序组件中,并且甚至能够响应<code>1</code>配置检查。但是,一旦实际的JPA提供程序被其他组件访问(例如,调用<code>2</code>),这些调用将阻塞,直到后台引导完成。特别是,当您使用Spring Data JPA时,请确保为其仓库也设置延迟引导。spring-doc.cadn.net.cn

基于JPA实现DAO:EntityManagerFactoryEntityManager

虽然 EntityManagerFactory 实例是线程安全的,但 EntityManager 实例不是。注入的 JPA EntityManager 的行为类似于从应用服务器的 JNDI 环境中获取的 EntityManager,如 JPA 规范所定义。它会将所有调用委托给当前事务的 EntityManager,如果有的话。否则,它会回退到每个操作中创建一个新的 EntityManager,从而使其使用线程安全。

可以在不使用任何Spring依赖项的情况下针对普通JPA编写代码,通过使用注入的EntityManagerFactoryEntityManager。如果启用了PersistenceAnnotationBeanPostProcessor,Spring可以在字段级别和方法级别都理解@PersistenceUnit@PersistenceContext注解。下面的示例显示了一个使用@PersistenceUnit注解的普通JPA DAO实现:spring-doc.cadn.net.cn

public class ProductDaoImpl implements ProductDao {

	private EntityManagerFactory emf;

	@PersistenceUnit
	public void setEntityManagerFactory(EntityManagerFactory emf) {
		this.emf = emf;
	}

	public Collection loadProductsByCategory(String category) {
		EntityManager em = this.emf.createEntityManager();
		try {
			Query query = em.createQuery("from Product as p where p.category = ?1");
			query.setParameter(1, category);
			return query.getResultList();
		}
		finally {
			if (em != null) {
				em.close();
			}
		}
	}
}
class ProductDaoImpl : ProductDao {

	private lateinit var emf: EntityManagerFactory

	@PersistenceUnit
	fun setEntityManagerFactory(emf: EntityManagerFactory) {
		this.emf = emf
	}

	fun loadProductsByCategory(category: String): Collection<*> {
		val em = this.emf.createEntityManager()
		val query = em.createQuery("from Product as p where p.category = ?1");
		query.setParameter(1, category);
		return query.resultList;
	}
}

前面的DAO不依赖于Spring,但仍可以很好地融入Spring应用程序上下文中。此外,DAO利用注解来要求注入默认的EntityManagerFactory,如下面的bean定义所示:spring-doc.cadn.net.cn

<beans>

	<!-- bean post-processor for JPA annotations -->
	<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>

	<bean id="myProductDao" class="product.ProductDaoImpl"/>

</beans>

作为显式定义 PersistenceAnnotationBeanPostProcessor 的替代方法, 请考虑在应用程序上下文配置中使用 Spring context:annotation-config XML 元素。 这样会自动注册所有 Spring 标准的后处理器, 用于基于注解的配置,包括 CommonAnnotationBeanPostProcessor 等。spring-doc.cadn.net.cn

请考虑以下示例:spring-doc.cadn.net.cn

<beans>

	<!-- post-processors for all standard config annotations -->
	<context:annotation-config/>

	<bean id="myProductDao" class="product.ProductDaoImpl"/>

</beans>

这种DAO的主要问题是它总是通过工厂创建一个新的 EntityManager。你可以通过请求一个事务性的 EntityManager(也称为“共享 EntityManager”,因为它是一个共享的、线程安全的代理,用于实际的事务性 EntityManager)来避免这种情况。下面的例子展示了如何操作:spring-doc.cadn.net.cn

public class ProductDaoImpl implements ProductDao {

	@PersistenceContext
	private EntityManager em;

	public Collection loadProductsByCategory(String category) {
		Query query = em.createQuery("from Product as p where p.category = :category");
		query.setParameter("category", category);
		return query.getResultList();
	}
}
class ProductDaoImpl : ProductDao {

	@PersistenceContext
	private lateinit var em: EntityManager

	fun loadProductsByCategory(category: String): Collection<*> {
		val query = em.createQuery("from Product as p where p.category = :category")
		query.setParameter("category", category)
		return query.resultList
	}
}

@PersistenceContext 注解有一个可选属性称为 type,其默认值为 PersistenceContextType.TRANSACTION。您可以使用此默认值来接收一个共享的 EntityManager 代理。另一种方式是 PersistenceContextType.EXTENDED,这完全是另一回事。这会导致所谓的扩展 EntityManager,它不是线程安全的,因此不能在被并发访问的组件中使用,例如 Spring 管理的单例 bean。扩展的 EntityManager 实例只能在状态型组件中使用,例如位于会话中的组件,其 EntityManager 的生命周期不与当前事务相关,而是完全由应用程序决定。spring-doc.cadn.net.cn

方法和字段级别的注入

您可以将指示依赖注入的注解(如 @PersistenceUnit@PersistenceContext)应用在类中的字段或方法上 — 因此有了“方法级别注入”和“字段级别注入”的说法。字段级别的注解简洁且更易于使用,而方法级别的注解允许对注入的依赖项进行进一步处理。在两种情况下,成员的可见性(public、protected 或 private)都不重要。spring-doc.cadn.net.cn

类级别的注解又如何处理呢?spring-doc.cadn.net.cn

在Jakarta EE平台上,它们用于依赖声明,而非用于资源 注入。spring-doc.cadn.net.cn

注入的 EntityManager 是由Spring管理的(能够感知到当前事务)。 尽管新的DAO实现使用了 EntityManager 的方法级别注入, 而不是 EntityManagerFactory,但由于注解的使用, bean定义中无需进行任何更改。spring-doc.cadn.net.cn

这种DAO风格的主要优点是它仅依赖于Java持久化API。 不需要导入任何Spring类。此外,由于JPA注解被理解, Spring容器会自动应用注入。从非侵入性的角度来看,这很有吸引力,并且对JPA开发者来说可能感觉更自然。spring-doc.cadn.net.cn

基于@Autowired实现DAO(通常使用基于构造函数的注入)

@PersistenceUnit@PersistenceContext 只能在方法和字段上声明。 那么如何通过构造函数和其他 @Autowired 注入点来提供 JPA 资源呢?spring-doc.cadn.net.cn

EntityManagerFactory可以通过构造函数和@Autowired字段/方法轻松注入,只要目标被定义为bean(例如通过LocalContainerEntityManagerFactoryBean)。注入点会按原始EntityManagerFactory定义的类型进行匹配。spring-doc.cadn.net.cn

然而,一个@PersistenceContext样式的共享EntityManager引用无法直接通过常规依赖注入开箱即用。为了使其支持@Autowired所要求的基于类型匹配,请考虑为您的EntityManagerFactory定义配置一个SharedEntityManagerBean作为伴随:spring-doc.cadn.net.cn

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	...
</bean>

<bean id="em" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
	<property name="entityManagerFactory" ref="emf"/>
</bean>

或者,你可以基于SharedEntityManagerCreator定义一个@Bean方法:spring-doc.cadn.net.cn

@Bean("em")
public static EntityManager sharedEntityManager(EntityManagerFactory emf) {
	return SharedEntityManagerCreator.createSharedEntityManager(emf);
}

如果存在多个持久化单元,每个EntityManagerFactory定义都需要一个对应的EntityManagerbean定义,理想情况下,这些限定符应与不同的EntityManagerFactory定义相匹配,以便通过@Autowired @Qualifier("…​")区分持久化单元。spring-doc.cadn.net.cn

Spring驱动的JPA事务

我们强烈建议您阅读 声明式事务管理,如果您尚未这样做的话,以获得有关 Spring 声明式事务支持的更详细内容。

对于JPA的推荐策略是通过JPA的原生事务支持进行本地事务。Spring的JpaTransactionManager在任何常规JDBC连接池上提供了许多从本地JDBC事务中熟知的功能(例如事务特定的隔离级别和资源级别的只读优化)(无需XA要求)。spring-doc.cadn.net.cn

Spring JPA 还允许配置的 JpaTransactionManager 将 JPA 事务暴露给访问相同 DataSource 的 JDBC 访问代码,前提是注册的 JpaDialect 支持检索底层 JDBC Connection。 Spring 为 EclipseLink 和 Hibernate JPA 实现提供了方言。 有关 JpaDialect 机制的详细信息,请参阅下一节。spring-doc.cadn.net.cn

理解 JpaDialectJpaVendorAdapter

作为一项高级功能,JpaTransactionManagerAbstractEntityManagerFactoryBean 的子类允许将自定义的 JpaDialect 传递到 jpaDialect bean 属性中。一个 JpaDialect 实现可以以提供商特定的方式启用 Spring 支持的以下高级功能:spring-doc.cadn.net.cn

这在具有特殊事务语义和异常的高级转换中尤其有价值。默认实现(DefaultJpaDialect)不提供任何特殊功能,如果需要前面列出的功能,则必须指定适当的语言。spring-doc.cadn.net.cn

作为Spring完整功能的LocalContainerEntityManagerFactoryBean设置的主要提供者适应设施,JpaVendorAdapter结合了JpaDialect与其他特定于提供者的默认值的功能。指定HibernateJpaVendorAdapterEclipseLinkJpaVendorAdapter是为Hibernate或EclipseLink分别自动配置EntityManagerFactory设置的最便捷方式。请注意,这些提供者适配器主要是为与Spring驱动的事务管理(即,用于与JpaTransactionManager一起使用)而设计的。

查看 JpaDialectJpaVendorAdapter 的 javadoc 以了解其操作的更多详细信息以及它们在 Spring 的 JPA 支持中的使用方法。spring-doc.cadn.net.cn

使用JTA事务管理设置JPA

作为JpaTransactionManager的替代方案,Spring 还支持通过 JTA 实现多资源事务协调,无论是在雅加达 EE 环境中还是使用独立事务协调器(如 Atomikos)。除了选择 Spring 的 JtaTransactionManager 而非 JpaTransactionManager 之外,您只需执行以下几个额外步骤:spring-doc.cadn.net.cn

  • 底层JDBC连接池需要支持XA,并与您的事务协调器集成。在Jakarta EE环境中,这通常很直接,通过JNDI暴露一种不同的DataSource。有关详细信息,请参阅您的应用程序服务器文档。类似地,独立的事务协调器通常提供特殊的XA集成DataSource变体。再次,请检查其文档。spring-doc.cadn.net.cn

  • JPA EntityManagerFactory 设置需要为 JTA 进行配置。这取决于提供者,通常通过作为 jpaProperties 指定的特殊属性来设置在 LocalContainerEntityManagerFactoryBean 上。在 Hibernate 的情况下,这些属性甚至是版本特定的。请参阅你的 Hibernate 文档以获取详细信息。spring-doc.cadn.net.cn

  • Spring的HibernateJpaVendorAdapter强制执行某些与Spring相关的默认值,例如连接释放模式on-close,这与Hibernate 5.0中的自身默认值匹配,但在Hibernate 5.1+中不再如此。对于JTA设置,请确保将您的持久化单元事务类型声明为“JTA”。或者,将Hibernate 5.2的hibernate.connection.handling_mode属性设置为DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT以恢复Hibernate自身的默认值。 有关相关说明,请参见使用Hibernate时出现的误报应用服务器警告spring-doc.cadn.net.cn

  • 或者,考虑直接从您的应用服务器获取 EntityManagerFactory(即通过 JNDI 查找而不是本地声明的 LocalContainerEntityManagerFactoryBean)。服务器提供的 EntityManagerFactory 可能需要在您的服务器配置中进行特殊定义(这会使部署的可移植性降低),但已为服务器的 JTA 环境进行了设置。spring-doc.cadn.net.cn

原生Hibernate设置及用于JPA交互的原生Hibernate事务

原生的 LocalSessionFactoryBean 配置与 HibernateTransactionManager 结合使用,可以与 @PersistenceContext 及其他 JPA 访问代码进行交互。Hibernate SessionFactory 现在原生实现了 JPA 的 EntityManagerFactory 接口,而 Hibernate Session 句柄原生地是一个 JPA EntityManager。 Spring 的 JPA 支持功能会自动检测原生的 Hibernate 会话。spring-doc.cadn.net.cn

因此,这种原生的Hibernate配置可以在许多情况下作为标准JPA LocalContainerEntityManagerFactoryBeanJpaTransactionManager组合的替代方案, 允许在同一个本地事务中与SessionFactory.getCurrentSession() (以及HibernateTemplate)一起使用@PersistenceContext EntityManager。这种配置还提供了更强的Hibernate集成 和更多的配置灵活性,因为它不受JPA启动契约的限制。spring-doc.cadn.net.cn

在这种情况下,您不需要HibernateJpaVendorAdapter配置, 因为Spring原生的Hibernate设置提供了更多功能 (例如,自定义Hibernate Integrator配置,Hibernate 5.3 bean容器集成, 以及对只读事务的更强优化)。最后但同样重要的是,您也可以通过LocalSessionFactoryBuilder表达原生的Hibernate配置, 与@Bean样式配置无缝集成(不涉及FactoryBean)。spring-doc.cadn.net.cn

LocalSessionFactoryBeanLocalSessionFactoryBuilder 支持背景引导,就像 JPA LocalContainerEntityManagerFactoryBean 一样。 有关介绍,请参见 背景引导spring-doc.cadn.net.cn

LocalSessionFactoryBean 上,可通过 bootstrapExecutor 属性获得。在编程的 LocalSessionFactoryBuilder 上,一个重载的 buildSessionFactory 方法接受一个引导执行器参数。spring-doc.cadn.net.cn