Spring 引导自定义 Bean 加载器
Spring Boot Custom Bean Loader
我将 JDBI 与 Spring Boot 结合使用。我按照这个 guide 结果必须创建一个 class: JdbiConfig
其中,对于应用程序上下文中想要的每个 dao,您必须添加:
@Bean
public SomeDao someDao(Jdbi jdbi) {
return jdbi.onDemand(SomeDao.class);
}
我想知道 Spring Boot 中是否有某种方法可以创建自定义处理器来创建 bean 并将它们放入应用程序上下文中。我有两个关于它如何工作的想法:
- 使用自定义注解
@JdbiDao
对 DAO 进行注解,然后写一些东西来挑选它们。我试过手动将它们注入应用程序启动,但问题是它们可能无法及时加载以注入,因为它们在 class 扫描期间无法识别。
- 创建每个存储库接口都可以扩展的 class
JdbiDao
。然后使用标准 @Repository
注释接口并创建自定义处理器以通过 Jdbi#onDemand
加载它们
这是我的两个想法,但我不知道有什么办法可以实现。我坚持手动创建一个 bean?这个以前解决过吗?
策略是扫描你的类路径寻找 dao 接口,然后将它们注册为 bean。
我们需要:BeanDefinitionRegistryPostProcessor to register additional bean definition and a FactoryBean 创建 jdbi dao bean 实例。
- 用
@JdbiDao
标记你的dao接口
@JdbiDao
public interface SomeDao {
}
- 定义一个
FactoryBean
来创建jdbi dao
public class JdbiDaoBeanFactory implements FactoryBean<Object>, InitializingBean {
private final Jdbi jdbi;
private final Class<?> jdbiDaoClass;
private volatile Object jdbiDaoBean;
public JdbiDaoBeanFactory(Jdbi jdbi, Class<?> jdbiDaoClass) {
this.jdbi = jdbi;
this.jdbiDaoClass = jdbiDaoClass;
}
@Override
public Object getObject() throws Exception {
return jdbiDaoBean;
}
@Override
public Class<?> getObjectType() {
return jdbiDaoClass;
}
@Override
public void afterPropertiesSet() throws Exception {
jdbiDaoBean = jdbi.onDemand(jdbiDaoClass);
}
}
- 扫描
@JdbiDao
注释接口的类路径:
public class JdbiBeanFactoryPostProcessor
implements BeanDefinitionRegistryPostProcessor, ResourceLoaderAware, EnvironmentAware, BeanClassLoaderAware, BeanFactoryAware {
private BeanFactory beanFactory;
private ResourceLoader resourceLoader;
private Environment environment;
private ClassLoader classLoader;
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false) {
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
// By default, scanner does not accept regular interface without @Lookup method, bypass this
return true;
}
};
scanner.setEnvironment(environment);
scanner.setResourceLoader(resourceLoader);
scanner.addIncludeFilter(new AnnotationTypeFilter(JdbiDao.class));
List<String> basePackages = AutoConfigurationPackages.get(beanFactory);
basePackages.stream()
.map(scanner::findCandidateComponents)
.flatMap(Collection::stream)
.forEach(bd -> registerJdbiDaoBeanFactory(registry, bd));
}
private void registerJdbiDaoBeanFactory(BeanDefinitionRegistry registry, BeanDefinition bd) {
GenericBeanDefinition beanDefinition = (GenericBeanDefinition) bd;
Class<?> jdbiDaoClass;
try {
jdbiDaoClass = beanDefinition.resolveBeanClass(classLoader);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
beanDefinition.setBeanClass(JdbiDaoBeanFactory.class);
// Add dependency to your `Jdbi` bean by name
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference("jdbi"));
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(Objects.requireNonNull(jdbiDaoClass));
registry.registerBeanDefinition(jdbiDaoClass.getName(), beanDefinition);
}
}
- 导入我们的
JdbiBeanFactoryPostProcessor
@SpringBootApplication
@Import(JdbiBeanFactoryPostProcessor.class)
public class Application {
}
我将 JDBI 与 Spring Boot 结合使用。我按照这个 guide 结果必须创建一个 class: JdbiConfig
其中,对于应用程序上下文中想要的每个 dao,您必须添加:
@Bean
public SomeDao someDao(Jdbi jdbi) {
return jdbi.onDemand(SomeDao.class);
}
我想知道 Spring Boot 中是否有某种方法可以创建自定义处理器来创建 bean 并将它们放入应用程序上下文中。我有两个关于它如何工作的想法:
- 使用自定义注解
@JdbiDao
对 DAO 进行注解,然后写一些东西来挑选它们。我试过手动将它们注入应用程序启动,但问题是它们可能无法及时加载以注入,因为它们在 class 扫描期间无法识别。 - 创建每个存储库接口都可以扩展的 class
JdbiDao
。然后使用标准@Repository
注释接口并创建自定义处理器以通过Jdbi#onDemand
加载它们
这是我的两个想法,但我不知道有什么办法可以实现。我坚持手动创建一个 bean?这个以前解决过吗?
策略是扫描你的类路径寻找 dao 接口,然后将它们注册为 bean。
我们需要:BeanDefinitionRegistryPostProcessor to register additional bean definition and a FactoryBean 创建 jdbi dao bean 实例。
- 用
@JdbiDao
标记你的dao接口
@JdbiDao
public interface SomeDao {
}
- 定义一个
FactoryBean
来创建jdbi dao
public class JdbiDaoBeanFactory implements FactoryBean<Object>, InitializingBean {
private final Jdbi jdbi;
private final Class<?> jdbiDaoClass;
private volatile Object jdbiDaoBean;
public JdbiDaoBeanFactory(Jdbi jdbi, Class<?> jdbiDaoClass) {
this.jdbi = jdbi;
this.jdbiDaoClass = jdbiDaoClass;
}
@Override
public Object getObject() throws Exception {
return jdbiDaoBean;
}
@Override
public Class<?> getObjectType() {
return jdbiDaoClass;
}
@Override
public void afterPropertiesSet() throws Exception {
jdbiDaoBean = jdbi.onDemand(jdbiDaoClass);
}
}
- 扫描
@JdbiDao
注释接口的类路径:
public class JdbiBeanFactoryPostProcessor
implements BeanDefinitionRegistryPostProcessor, ResourceLoaderAware, EnvironmentAware, BeanClassLoaderAware, BeanFactoryAware {
private BeanFactory beanFactory;
private ResourceLoader resourceLoader;
private Environment environment;
private ClassLoader classLoader;
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false) {
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
// By default, scanner does not accept regular interface without @Lookup method, bypass this
return true;
}
};
scanner.setEnvironment(environment);
scanner.setResourceLoader(resourceLoader);
scanner.addIncludeFilter(new AnnotationTypeFilter(JdbiDao.class));
List<String> basePackages = AutoConfigurationPackages.get(beanFactory);
basePackages.stream()
.map(scanner::findCandidateComponents)
.flatMap(Collection::stream)
.forEach(bd -> registerJdbiDaoBeanFactory(registry, bd));
}
private void registerJdbiDaoBeanFactory(BeanDefinitionRegistry registry, BeanDefinition bd) {
GenericBeanDefinition beanDefinition = (GenericBeanDefinition) bd;
Class<?> jdbiDaoClass;
try {
jdbiDaoClass = beanDefinition.resolveBeanClass(classLoader);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
beanDefinition.setBeanClass(JdbiDaoBeanFactory.class);
// Add dependency to your `Jdbi` bean by name
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference("jdbi"));
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(Objects.requireNonNull(jdbiDaoClass));
registry.registerBeanDefinition(jdbiDaoClass.getName(), beanDefinition);
}
}
- 导入我们的
JdbiBeanFactoryPostProcessor
@SpringBootApplication
@Import(JdbiBeanFactoryPostProcessor.class)
public class Application {
}