我熟悉基于Springs Java的配置选项,包括使用@Component
和@Configuration
以及@Bean
注释来注册Spring bean。
但是,在将一个体面的项目转换为Spring时,系统地触摸项目中的所有类并使用@Configuration
@Bean
进行更新或使用{{1注释每个类}}。我们有一个很大的Groovy项目要转换,我想简化这个过程。
我的问题: Spring中是否提供了一个工具,允许您告诉Spring在特定包中自动配置所有有效的bean候选类?
如果没有,还有哪些其他选择?
答案 0 :(得分:8)
ClassPathBeanDefinitionScanner
就是你所需要的。
public class Main {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context, false);
scanner.addIncludeFilter((metadataReader, metadataReaderFactory) -> true);
scanner.scan("net.company.name");
context.refresh();
A a = context.getBean(A.class);
System.out.println(a.toString());
}
}
如果需要,您可以在包含过滤器中传递自定义逻辑。在当前版本中,提供的包中的每个类都将作为bean包含。
但是不可能在类上自动构建正确的依赖结构,它实际上取决于你想要的范围。你需要亲自动手。
答案 1 :(得分:7)
我做的几乎和Roman一样,只是我在构建时,而不是在运行时,使用代码生成。这里的基本原理是,我非常喜欢魔法在构建时发生在部署时发生的魔法。
在最简单的版本中,编写一个扫描包的main方法(而不是反射api,我正在使用Guava的ClassPath扫描程序)并为它找到的每个类创建一个@Bean
方法
对于代码生成,我使用JCodeModel:
public class PackageBeanGenerator {
public static void main(String[] args) throws Exception {
String packageName = args[0];
JCodeModel codeModel = new JCodeModel();
// create class definition
JDefinedClass springConfig = codeModel._package(packageName)._class("SpringConfig");
springConfig.annotate(Configuration.class);
for (ClassPath.ClassInfo classInfo : ClassPath.from(
PackageBeanGenerator.class.getClassLoader()
).getTopLevelClasses(packageName)) {
Class<?> type = classInfo.load();
String beanName = CaseFormat.UPPER_CAMEL.to(
CaseFormat.LOWER_CAMEL,
type.getSimpleName());
JMethod beanMethod = springConfig.method(JMod.PUBLIC, type, beanName);
beanMethod.annotate(Bean.class);
beanMethod.body()._return(JExpr._new(codeModel._ref(type)));
}
// write class to file
codeModel.build(new File("/path/to/output/folder"));
}
}
答案 2 :(得分:4)
您可以尝试使用自己的BeanDefinitionRegistryPostProcessor
@Component
public class CustomBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
Reflections reflections = new Reflections("my.package.prefix", new SubTypesScanner(false));
Set<Class<? extends Object>> allClasses = reflections.getSubTypesOf(Object.class);
for (Class clazz : allClasses) {
GenericBeanDefinition gbd = new GenericBeanDefinition();
gbd.setBeanClass(clazz);
gbd.setAttribute("attributeName", "attributeValue");
registry.registerBeanDefinition(clazz.getSimpleName() + "_Bean", gbd);
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// Custom post process the existing bean definitions
}
}
上的示例项目
答案 3 :(得分:1)
冒着听起来很原始的风险,为什么不在你的IDE中做一个简单的查找和替换(例如在一个包中搜索&#34;公共类&#34;用&#34替换; @Component公共类&# 34;)?这应该比以编程方式做任何事情要快得多。