在Spring Java Config类中定义EntityManager时,我可以通过调用相应构建器上的方法来添加基础包以扫描Entity类:
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder) {
// Some other configuration here
builder.packages("org.foo.bar", "org.foo.baz");
return builder.build();
}
我需要类似Spring寻找存储库接口的地方。通常的方法是使用@EnableJpaRepositories
注释:
@EnableJpaRepositories(basePackages = {"org.foo.barbaz"})
但是我希望有一种动态的方法来定义这些包,类似于上面对Entity位置的方式。像这样:
public SomeJpaRepositoryFactoryBean entityManagerFactory(JpaRepositoryFactoryBuilder builder) {
// Some other configuration here
builder.packages("org.foo.barbaz");
return builder.build();
}
有没有办法用当前的Spring Data JPA版本执行此操作,这是不是意味着这样做?
答案 0 :(得分:8)
您可以使用@AutoConfigurationPackage
注释将子模块的包添加到scan-packages。
@EnableJpaRepositories
将@AutoConfigurationPackage
类添加到子模块的顶级目录(类似于@SpringBootApplication
,您必须将此类放到最顶层的目录中进行扫描所有子包装:
@AutoConfigurationPackage
public class ChildConfiguration {
}
在您的子模块的 spring.factories
下创建/resources/META-INF/spring.factories
文件并添加配置类:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.child.package.ChildConfiguration
现在,您可以从核心项目中@Autowired
存储库。 (经过测试和工作)
答案 1 :(得分:6)
@EnableJpaRepositories
可以用于多个@Configuration
类。也就是说,每个模块都可以通过拥有自己的配置类来声明自己的存储库:
@Configuration
@EnableJpaRepositories(basePackages = "package1")
public class ConfigClass1 { /* ... */ }
@Configuration
@EnableJpaRepositories(basePackages = "package2")
public class ConfigClass2 { /* ... */ }
Spring Data JPA然后将它们全部计入(package1
和package2
)。
尽管这仍然不是编程方式,但可以解决我的问题。
答案 2 :(得分:1)
这个问题也困扰了我近一个星期。我逐行调试“ spring application context refresh”代码和org.springframework.data.jpa.repository.config.JpaRepositoriesRegistrar
,然后解决了这个问题。
我自定义了EnableJpaRepository
注释和JpaRepositoriesRegistrar
,然后可以在AbdJpaRepositoriesRegistrar
中做任何事情(“ abd”是自定义类的前缀)。
这个问题也困扰了我近一个星期。我逐行调试“ spring application context refresh”代码和org.springframework.data.jpa.repository.config.JpaRepositoriesRegistrar
,然后解决了这个问题。
AbdEnableJpaRepositories.java
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Import;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.repository.config.DefaultRepositoryBaseClass;
import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
import org.springframework.transaction.PlatformTransactionManager;
import javax.persistence.EntityManagerFactory;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* basePackages
* 复制EnableJpaRepositories,Import自定义的AbdJpaRepositoriesRegistrar.
* Copy from EnableJpaRepositories,Import customized AbdJpaRepositoriesRegistrar.
*
* @author Oliver Gierke
* @author Thomas Darimont
* @author ghj
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AbdJpaRepositoriesRegistrar.class)
public @interface AbdEnableJpaRepositories {
/**
* Alias for the {@link #basePackages()} attribute. Allows for more concise annotation declarations e.g.:
* {@code @EnableJpaRepositories("org.my.pkg")} instead of {@code @EnableJpaRepositories(basePackages="org.my.pkg")}.
*/
String value() default "";
/**
* Base packages to scan for annotated components. {@link #value()} is an alias for (and mutually exclusive with) this
* attribute. Use {@link #basePackageClasses()} for a type-safe alternative to String-based package names.
*/
String basePackages() default "";
/**
* Type-safe alternative to {@link #basePackages()} for specifying the packages to scan for annotated components. The
* package of each class specified will be scanned. Consider creating a special no-op marker class or interface in
* each package that serves no purpose other than being referenced by this attribute.
*/
Class<?>[] basePackageClasses() default {};
/**
* Specifies which types are eligible for component scanning. Further narrows the set of candidate components from
* everything in {@link #basePackages()} to everything in the base packages that matches the given filter or filters.
*/
Filter[] includeFilters() default {};
/**
* Specifies which types are not eligible for component scanning.
*/
Filter[] excludeFilters() default {};
/**
* Returns the postfix to be used when looking up custom repository implementations. Defaults to {@literal Impl}. So
* for a repository named {@code PersonRepository} the corresponding implementation class will be looked up scanning
* for {@code PersonRepositoryImpl}.
*
* @return
*/
String repositoryImplementationPostfix() default "Impl";
/**
* Configures the location of where to find the Spring Data named queries properties file. Will default to
* {@code META-INF/jpa-named-queries.properties}.
*
* @return
*/
String namedQueriesLocation() default "";
/**
* Returns the key of the {@link QueryLookupStrategy} to be used for lookup queries for query methods. Defaults to
* {@link Key#CREATE_IF_NOT_FOUND}.
*
* @return
*/
Key queryLookupStrategy() default Key.CREATE_IF_NOT_FOUND;
/**
* Returns the {@link FactoryBean} class to be used for each repository instance. Defaults to
* {@link JpaRepositoryFactoryBean}.
*
* @return
*/
Class<?> repositoryFactoryBeanClass() default JpaRepositoryFactoryBean.class;
/**
* Configure the repository base class to be used to create repository proxies for this particular configuration.
*
* @return
* @since 1.9
*/
Class<?> repositoryBaseClass() default DefaultRepositoryBaseClass.class;
// JPA specific configuration
/**
* Configures the name of the {@link EntityManagerFactory} bean definition to be used to create repositories
* discovered through this annotation. Defaults to {@code entityManagerFactory}.
*
* @return
*/
String entityManagerFactoryRef() default "entityManagerFactory";
/**
* Configures the name of the {@link PlatformTransactionManager} bean definition to be used to create repositories
* discovered through this annotation. Defaults to {@code transactionManager}.
*
* @return
*/
String transactionManagerRef() default "transactionManager";
/**
* Configures whether nested repository-interfaces (e.g. defined as inner classes) should be discovered by the
* repositories infrastructure.
*/
boolean considerNestedRepositories() default false;
/**
* Configures whether to enable default transactions for Spring Data JPA repositories. Defaults to {@literal true}. If
* disabled, repositories must be used behind a facade that's configuring transactions (e.g. using Spring's annotation
* driven transaction facilities) or repository methods have to be used to demarcate transactions.
*
* @return whether to enable default transactions, defaults to {@literal true}.
*/
boolean enableDefaultTransactions() default true;
}
AbdJpaRepositoriesRegistrar.java
import org.springframework.data.jpa.repository.config.JpaRepositoryConfigExtension;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
import java.lang.annotation.Annotation;
class AbdJpaRepositoriesRegistrar extends AbdRepositoryBeanDefinitionRegistrarSupport {
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport#getAnnotation()
*/
@Override
protected Class<? extends Annotation> getAnnotation() {
return AbdEnableJpaRepositories.class;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport#getExtension()
*/
@Override
protected RepositoryConfigurationExtension getExtension() {
return new JpaRepositoryConfigExtension();
}
}
AbdRepositoryBeanDefinitionRegistrarSupport.java
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport;
import org.springframework.data.repository.config.RepositoryConfigurationDelegate;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
import org.springframework.data.repository.config.RepositoryConfigurationUtils;
import org.springframework.util.Assert;
/**
*
* @author ghj
*/
abstract class AbdRepositoryBeanDefinitionRegistrarSupport extends RepositoryBeanDefinitionRegistrarSupport implements ImportBeanDefinitionRegistrar,
ResourceLoaderAware, EnvironmentAware {
private ResourceLoader resourceLoader;
private Environment environment;
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
Assert.notNull(resourceLoader, "ResourceLoader must not be null!");
Assert.notNull(annotationMetadata, "AnnotationMetadata must not be null!");
Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");
// Guard against calls for sub-classes
if (annotationMetadata.getAnnotationAttributes(getAnnotation().getName()) == null) {
return;
}
// 使用自定义的AbdAnnotationRepositoryConfigurationSource
AbdAnnotationRepositoryConfigurationSource configurationSource = new AbdAnnotationRepositoryConfigurationSource(
annotationMetadata, getAnnotation(), resourceLoader, environment);
RepositoryConfigurationExtension extension = getExtension();
RepositoryConfigurationUtils.exposeRegistration(extension, registry, configurationSource);
RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(configurationSource, resourceLoader,
environment);
delegate.registerRepositoriesIn(registry, extension);
}
}
AbdAnnotationRepositoryConfigurationSource.java。您可以覆盖getBasePackages
,然后可以返回所需的任何软件包。
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
*
* @author ghj
*/
class AbdAnnotationRepositoryConfigurationSource extends AnnotationRepositoryConfigurationSource {
private static final String BASE_PACKAGES = "basePackages";
private static final String BASE_PACKAGE_CLASSES = "basePackageClasses";
private final AnnotationMetadata configMetadata;
private final AnnotationAttributes attributes;
private final Environment environment;
AbdAnnotationRepositoryConfigurationSource(AnnotationMetadata metadata, Class<? extends Annotation> annotation, ResourceLoader resourceLoader, Environment environment) {
super(metadata, annotation, resourceLoader, environment);
this.attributes = new AnnotationAttributes(metadata.getAnnotationAttributes(annotation.getName()));
this.configMetadata = metadata;
this.environment = environment;
}
@Override
public Iterable<String> getBasePackages() {
String value = attributes.getStringArray("value")[0];
String basePackages = attributes.getStringArray(BASE_PACKAGES)[0];
Class<?>[] basePackageClasses = attributes.getClassArray(BASE_PACKAGE_CLASSES);
// Default configuration - return package of annotated class
if (StringUtils.isEmpty(value) && StringUtils.isEmpty(basePackages) && basePackageClasses.length == 0) {
String className = configMetadata.getClassName();
return Collections.singleton(ClassUtils.getPackageName(className));
}
String[] packagesFromValue = parsePackagesSpel(value);
String[] packagesFromBasePackages = parsePackagesSpel(basePackages);
Set<String> packages = new HashSet<>();
packages.addAll(Arrays.asList(packagesFromValue));
packages.addAll(Arrays.asList(packagesFromBasePackages));
for (Class<?> typeName : basePackageClasses) {
packages.add(ClassUtils.getPackageName(typeName));
}
return packages;
}
private String[] parsePackagesSpel(String raw) {
if (!raw.trim().startsWith("$")) {
if (StringUtils.isEmpty(raw)) {
return new String[]{};
}
return raw.split(",");
} else {
raw = raw.trim();
String packages = this.environment.getProperty(raw.substring("${".length(), raw.length() - "}".length()));
return packages.split(",");
}
}
}
如何使用?这是配置文件。 PrimaryJpaConfiguration.java
import com.shinow.abd.springjpa2.annotation.AbdEnableJpaRepositories;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import java.util.Map;
@Configuration
@AbdEnableJpaRepositories(
basePackages = "${spring.jpa.base-packages}",
entityManagerFactoryRef = "entityManagerFactory",
transactionManagerRef = "transactionManager"
)
@EnableAutoConfiguration(exclude = HibernateJpaAutoConfiguration.class)
public class PrimaryJpaConfiguration implements EnvironmentAware {
private Environment env;
@Bean
@ConditionalOnMissingBean(name = "entityManager")
@Primary
public EntityManager entityManager(@Qualifier("entityManagerFactory") LocalContainerEntityManagerFactoryBean entityManagerFactory) {
return entityManagerFactory.getObject().createEntityManager();
}
@Bean
@ConditionalOnMissingBean(name = "entityManagerFactory")
@Primary
public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier("dataSource") DataSource dataSource) {
Map<String, Object> properties = JpaProperties.get("", env);
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource);
entityManagerFactoryBean.setJpaPropertyMap(properties);
entityManagerFactoryBean.setPackagesToScan(env.getProperty("spring.jpa.base-packages").split(","));
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
return entityManagerFactoryBean;
}
@Bean
@ConditionalOnMissingBean(name = "dataSource")
@Primary
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConditionalOnMissingBean(name = "transactionManager")
@Primary
public PlatformTransactionManager transactionManager(@Qualifier("entityManagerFactory") LocalContainerEntityManagerFactoryBean entityManagerFactory) {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
entityManagerFactory.getObject());
return transactionManager;
}
@Override
public void setEnvironment(Environment environment) {
this.env = environment;
}
}
您可以将spring.jpa.base-packages
配置添加到application.properties。
例如:spring.jpa.base-packages=com.foo.a,com.bar.b
,并将这些包“ com.foo.a”和“ com.bar.b”下的存储库和实体添加到spring Ioc容器中。
答案 3 :(得分:1)
我只引用了这篇文章,并在github中为mysql创建了一个模块感知的多数据库感知的Spring数据库(与spring boot兼容)。需要添加一些应用程序属性才能完成。
文档和其他详细信息可以在以下位置找到:-
https://github.com/yatharthamishra0419/spring-boot-data-multimodule-mysql
答案 4 :(得分:0)
您所寻找的是@EntityScan
,但它仅在Spring Boot中可用。您可以在此处记录Spring Data JPA中可以注释的配置https://docs.spring.io/spring-data/jpa/docs/2.0.8.RELEASE/reference/html/#jpa.java-config
@Configuration
@EnableJpaRepositories
@EnableTransactionManagement
class ApplicationConfig {
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.acme.domain");
factory.setDataSource(dataSource());
return factory;
}
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory);
return txManager;
}
}
答案 5 :(得分:0)
高慧觉Spring Data JPA - How to programmatically set JpaRepository base packages的答案对我有用,但是我想出了一个更简单,更可靠的AnnotationRepositoryConfigurationSource
实现:只允许Spring Data以其方式收集软件包,然后发布-处理它们,并将属性占位符扩展为程序包名称。
class AbdAnnotationRepositoryConfigurationSource extends AnnotationRepositoryConfigurationSource {
private final Environment environment;
ExpressionsSupportingAnnotationRepositoryConfigurationSource(AnnotationMetadata metadata, Class<? extends Annotation> annotation,
ResourceLoader resourceLoader, Environment environment, BeanDefinitionRegistry registry) {
super(metadata, annotation, resourceLoader, environment, registry);
this.environment = environment;
}
@Override
public Streamable<String> getBasePackages() {
Streamable<String> rawPackages = super.getBasePackages();
return Streamable.of(() -> rawPackages.stream()
.flatMap(raw -> parsePackagesSpel(raw).stream())
);
}
private List<String> parsePackagesSpel(@Nullable String rawPackage) {
Objects.requireNonNull(rawPackage, "Package specification cannot be null");
if (!rawPackage.trim().startsWith("$")) {
return Collections.singletonList(rawPackage);
}
rawPackage = rawPackage.trim();
String propertyName = rawPackage.substring("${".length(), rawPackage.length() - "}".length());
String packages = this.environment.getProperty(propertyName);
if (!StringUtils.hasText(packages)) {
throw new IllegalStateException(
String.format("Could not resolve the following packages definition: %s", rawPackage));
}
return Arrays.stream(packages.split(","))
.map(String::trim)
.filter(StringUtils::hasText)
.collect(Collectors.toList());
}
}
答案 6 :(得分:0)
我已经实现了一种纯粹以编程方式调用@EnableJpaRepositories
的方法。为此,我创建了一个类,该类模拟传递到使用@EnableJpaRepositories
批注进行批注的配置类的批注数据。我叫班EnableJpaRepositoriesData
。确认可以在Spring 5.1.5,SpringBoot 2.1.3中使用。我想它必须与早期和更高版本都兼容,最多没有任何变化或只有很少的变化。
下面是类代码和示例用法代码。
EnableJpaRepositoriesData.java:
package org.patladj.jpa.config.multijpa;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.AnnotationMetadataReadingVisitor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Indexed;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurationSelector;
import java.lang.reflect.Method;
import java.util.*;
public class EnableJpaRepositoriesData extends AnnotationMetadataReadingVisitor implements AnnotationMetadata {
private Map<String, ?> data;
private void initIt() throws NoSuchMethodException, ClassNotFoundException {
//################## protected final Set<String> annotationSet = new LinkedHashSet<>(4);
annotationSet.add(Configuration.class.getCanonicalName());
annotationSet.add(EnableTransactionManagement.class.getCanonicalName());
annotationSet.add(EnableJpaRepositories.class.getCanonicalName());
//################## protected final Map<String, Set<String>> metaAnnotationMap = new LinkedHashMap<>(4);
metaAnnotationMap.put(Configuration.class.getCanonicalName(),
new LinkedHashSet<>(Arrays.asList(
Component.class.getCanonicalName(),
Indexed.class.getCanonicalName()
)));
metaAnnotationMap.put(EnableTransactionManagement.class.getCanonicalName(),
new LinkedHashSet<>(Arrays.asList(
Import.class.getCanonicalName()
)));
metaAnnotationMap.put(EnableJpaRepositories.class.getCanonicalName(),
new LinkedHashSet<>(Arrays.asList(
Import.class.getCanonicalName()
)));
//################## protected final LinkedMultiValueMap<String, AnnotationAttributes> attributesMap = new LinkedMultiValueMap<>(4);
attributesMap.put(Configuration.class.getCanonicalName(),
new LinkedList<AnnotationAttributes>() {{
add(new AnnotationAttributes(new LinkedHashMap<String, Object>() {{
put("value", defaultFor(Configuration.class, "value"));
}}));
}});
attributesMap.put(Component.class.getCanonicalName(),
new LinkedList<AnnotationAttributes>() {{
add(new AnnotationAttributes(new LinkedHashMap<String, Object>() {{
put("value", defaultFor(Component.class, "value"));
}}));
}});
attributesMap.put(Indexed.class.getCanonicalName(),
new LinkedList<AnnotationAttributes>() {{
add(new AnnotationAttributes(new LinkedHashMap<String, Object>() {{
}}));
}});
attributesMap.put(EnableTransactionManagement.class.getCanonicalName(),
new LinkedList<AnnotationAttributes>() {{
add(new AnnotationAttributes(new LinkedHashMap<String, Object>() {{
put("order", defaultFor(EnableTransactionManagement.class, "order"));
put("mode", defaultFor(EnableTransactionManagement.class, "mode"));
put("proxyTargetClass", defaultFor(EnableTransactionManagement.class, "proxyTargetClass"));
}}));
}});
attributesMap.put(Import.class.getCanonicalName(),
new LinkedList<AnnotationAttributes>() {{
add(new AnnotationAttributes(new LinkedHashMap<String, Object>() {{
put("value", new Class<?>[]{TransactionManagementConfigurationSelector.class});
}}));
add(new AnnotationAttributes(new LinkedHashMap<String, Object>() {{
put("value", new Class<?>[]{Class.forName("org.springframework.data.jpa.repository.config.JpaRepositoriesRegistrar")});
}}));
}});
attributesMap.put(EnableJpaRepositories.class.getCanonicalName(),
new LinkedList<AnnotationAttributes>() {{
add(new AnnotationAttributes(new LinkedHashMap<String, Object>() {{
put("repositoryBaseClass", data.get("repositoryBaseClass"));
put("basePackages", data.get("basePackages"));
put("value", defaultFor(EnableJpaRepositories.class, "value"));
put("excludeFilters", new AnnotationAttributes[]{});
put("includeFilters", new AnnotationAttributes[]{});
put("basePackageClasses", defaultFor(EnableJpaRepositories.class, "basePackageClasses"));
put("bootstrapMode", defaultFor(EnableJpaRepositories.class, "bootstrapMode"));
put("transactionManagerRef", data.get("transactionManagerRef"));
put("considerNestedRepositories", defaultFor(EnableJpaRepositories.class, "considerNestedRepositories"));
put("namedQueriesLocation", defaultFor(EnableJpaRepositories.class, "namedQueriesLocation"));
put("queryLookupStrategy", defaultFor(EnableJpaRepositories.class, "queryLookupStrategy"));
put("entityManagerFactoryRef", data.get("entityManagerFactoryRef"));
put("enableDefaultTransactions", defaultFor(EnableJpaRepositories.class, "enableDefaultTransactions"));
put("repositoryImplementationPostfix", defaultFor(EnableJpaRepositories.class, "repositoryImplementationPostfix"));
put("repositoryFactoryBeanClass", defaultFor(EnableJpaRepositories.class, "repositoryFactoryBeanClass"));
}}));
}});
//##################
}
public EnableJpaRepositoriesData(@Nullable ClassLoader classLoader, Map<String, ?> data) throws NoSuchMethodException, ClassNotFoundException {
super(classLoader);
this.data = data;
this.initIt();
}
private Object defaultFor(Class<?> clazz, String methodName) throws NoSuchMethodException {
Method method = clazz.getDeclaredMethod(methodName);
return method.getDefaultValue();
}
}
实际使用类来调用enableJpaRepositories的示例 以编程方式:
AnnotationMetadata enableJpaRepositoriesData = null;
try {
enableJpaRepositoriesData = new EnableJpaRepositoriesData(this.getClass().getClassLoader(), new HashMap<String, Object>() {{
put("repositoryBaseClass", MyJPAConnectorImpl.class);
put("basePackages", new String[] {
//This is where you set the repositories base packages to scan.
//... Having your best programmatic convenience
"org.patladj.connector.multijpa.common",
"org.patladj.connector.multijpa.anotherrepositoriespackage",
"org.patladj.connector.multijpa.morepackagestoscanforrepositories..."
});
//Ofcourse you need to create by yourself the custom transactionManagerFactory,
// ... entityManagerFactory, JPAVendorAdapter and Datasource beans for your
// ... custom persistence contexts using unique bean names (different than
// ... the default Spring data names: 'entityManagerFactory', etc...)
// ... Then "send" these bean names as references to each and every ...
// and as many as you want persistence contexts programmatically here
put("transactionManagerRef", myCustomPersistanceContextName + "_transactionManager");
put("entityManagerFactoryRef", myCustomPersistanceContextName + "_entityManagerFactory");
}});
} catch (NoSuchMethodException e) {
throw new ExceptionInInitializerError(e);
} catch (ClassNotFoundException e) {
throw new ExceptionInInitializerError(e);
}
AnnotationRepositoryConfigurationSource configurationSource = new AnnotationRepositoryConfigurationSource(
enableJpaRepositoriesData, EnableJpaRepositories.class, applicationContext, environment, registry
);
RepositoryConfigurationExtension extension = new JpaRepositoryConfigExtension();
RepositoryConfigurationUtils.exposeRegistration(extension, registry, configurationSource);
RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(configurationSource, applicationContext, environment);
delegate.registerRepositoriesIn(registry, extension);
最后,如果您不知道,则可以使用以下@Configuration类
public class MultiJPABeanDefinitionRegistrar implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware
...覆盖其2种方法,以使后处理bean registry
和applicationContext
可以动态注册bean定义。
覆盖的方法:
- public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
- public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException