我想在基于Spring的Web应用程序中搜索一些注释,例如@Entity
。因此,我需要像Spring在服务器启动时所涉及的功能,并查找所有使用@Component
注释的类。在我的情况下,我不创建单例,对我来说收集所有用@Entity
注释的类非常重要。
是否有可能使用现有的Spring工具?我想完全搜索与Spring对@Component
注释相同的命名空间。
答案 0 :(得分:5)
当然,请查看parse()
中的org.springframework.context.annotation.ComponentScanBeanDefinitionParser
方法。当Spring在XML配置中遇到<context:component-scan/>
时,会调用此方法。可能你可以剥掉它以更好地满足你的需求,但它应该作为一个全面的例子。
你应该特别感兴趣的课程是org.springframework.context.annotation.ClassPathBeanDefinitionScanner
。来自JavaDoc:
通过可配置的类型过滤器检测候选类。默认过滤器包括使用Spring的@Component,@ Repository,@ Service或@Controller构造型注释的类。
顺便说一句,如果您需要较少的通用解决方案,也许您的持久性提供程序有一些API来获取所有实体类?
答案 1 :(得分:4)
Spring的内置类路径扫描基础结构(ClassPathBeanDefinitionScanner / ComponentScanBeanDefinitionParser)已经准备就绪,可以在Spring appcontext中将类注册为BeanDefinition。
如果您只是想获取一个使用给定注释注释的类列表(而不是在Spring中将它们实际注册为bean定义),请查看Google Reflections库。
Reflections允许您使用各种过滤器扫描类路径,包括注释过滤器。
Reflections reflections = new Reflections("my.project.prefix");
Set<Class<? extends SomeClassOrInterface>> subTypes = reflections.getSubTypesOf(SomeClassOrInterface.class);
Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(SomeAnnotation.class);
答案 2 :(得分:1)
基于Spring的解决方案
<强>使用强>
AnnotatedClassFinder entityScanner = new AnnotatedClassFinder(Entity.class);
entityScanner.setPackages(Arrays.asList("org.myapp.domain"));
Collection<Class<?>> entities = entityScanner.findMarkedClassOfType();
public class AnnotatedClassFinder {
private static final String CLASS_RESOURCE_PATTERN = "**/*.class";
private List<String> packages;
private final ResourceLoader resourceLoader = new DefaultResourceLoader();
private final ResourcePatternResolver resourcePatternResolver = ResourcePatternUtils
.getResourcePatternResolver(resourceLoader);
private final MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
private final TypeFilter annotationFilter;
public AnnotatedClassFinder(final Class<? extends Annotation> annotationToScanFor) {
annotationFilter = new AnnotationTypeFilter(annotationToScanFor);
}
public Set<Class<?>> findMarkedClassOfType() {
if (packages == null) {
return new HashSet<Class<?>>();
}
final Set<Class<?>> annotatedClasses = new HashSet<Class<?>>();
try {
for (final String p : packages) {
final String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
+ ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(p)) + "/"
+ CLASS_RESOURCE_PATTERN;
final Resource[] resources = resourcePatternResolver.getResources(packageSearchPath);
for (final Resource resource : resources) {
if (resource.isReadable()) {
final MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
if (annotationFilter.match(metadataReader, metadataReaderFactory)) {
annotatedClasses.add(Class.forName(metadataReader.getAnnotationMetadata().getClassName()));
}
}
}
}
return annotatedClasses;
} catch (final IOException ex) {
throw new RuntimeException("I/O failure during classpath scanning", ex);
} catch (final ClassNotFoundException ex) {
throw new RuntimeException("Class loading failure during classpath scanning", ex);
}
}
public void setPackages(final List<String> packages) {
this.packages = packages;
}
}