实现在Android的春天般的包扫描 [英] Implementing Spring-like package scanning in Android
问题描述
我试图实施一揽子扫描功能,类似于Spring的组件扫描
,对于Android框架我开发。基本上,我希望能够指定一个基础包,如 com.foo.bar
和检索所有类
实例具有特定注释。我不希望有注册每个组件与我的框架,因为这会破坏自动扫描的目的。
根据我的研究,它似乎是不可能的Java获取给定的资源使用反射包名。不过,我简要地看着进入思考框架,如果我想知道有是一款Android兼容等同。如果没有,也许是一个稍微不太明显的方式来完成我想做的事情。
我朝春源了一下,看看他们是如何做到了这一点,但我不认为他们在做什么会在Dalvik运行时内工作。
更新
目前,以下code一直是最好的,我可以做些什么来检索包含特定注释的所有类,但坦率地说这是一个pretty的可怜的解决方案。这使得一些关于的ClassLoader
真的不安全的假设,再加上它会扫描(并加载)的所有应用程序类。
公共设置<类<>> getClassesWithAnnotation(类和LT ;?延伸注释>注释){
设置<类<>>类=新的HashSet<类<>>();
现场dexField = PathClassLoader.class.getDeclaredField(mDexs);
dexField.setAccessible(真正的);
PathClassLoader类加载器=(PathClassLoader)Thread.currentThread()getContextClassLoader()。
DexFile [] dexs =(DexFile [])dexField.get器(classloader);
对于(DexFile DEX:dexs){
枚举<字符串>条目= dex.entries();
而(entries.hasMoreElements()){
字符串项= entries.nextElement();
类<> entryClass = dex.loadClass(入门,类加载器);
如果(entryClass = NULL和放大器;!&安培; entryClass.isAnnotation present(注释)){
classes.add(entryClass);
}
}
}
返回班;
}
我分享乔普埃根的意见,并找到他的做法是好的。在Android中我尽量避免了通常的Web应用程序的特点,导致长期持久的应用程序启动。我不使用反射或包扫描。
但是,如果你想....如果我理解正确你想有一个注解的一类。而不是使用注解,你也可以使用标记接口(只是有更多的possibilites)。
1)看
- 注释: Java自定义注释和动态加载
先后在刚刚回答您的问题这个问题的实现。 - 注释:扫描Java注释在运行时
- 接口:找到Java类实现一个接口
- 接口:<一href="http://stackoverflow.com/questions/251336/is-something-similar-to-serviceloader-in-java-1-5">Is类似的ServiceLoader东西在Java 1.5中?
- 接口:<一href="http://stackoverflow.com/questions/347248/how-can-i-get-a-list-of-all-the-implementations-of-an-interface-programmatically">How我可以以编程方式在Java接口的所有实现的列表?
- 接口:由于该方法是昂贵的,也许的ServiceLoader 是执行时间和舒适性之间的平衡,因为它加载只有在服务文件中给出的类。在另一方面,如果只有类具有一定的界面在你的包那么的ServiceLoader是不是快。
2)AndroidAnnotations
我会preFER的方式 AndroidAnnotations 工作(也许是在AndroidAnnotations一体化是preferable方式):它会自动添加一个额外的编译步骤,生成源$ C $ C,使用标准的Java注释处理工具。而不是运行时扫描所以您根据在编译时产生的注释执行code。
我觉得豆/ EBean注释可以为你工作(仅限于单个类)的 https://github.com/excilys/androidannotations/wiki/Enhance%20custom%20classes
一个扫描功能不可用,请参阅此线程
3)编写自己的注解处理器
- 查看 APT(注释处理工具)。这个想法是产生一个静态函数返回的这些注解类的列表,这样就没有一流的扫描需要。
- 在一个非常好的的ressource是 http://javadude.com/articles/annotations/index.html
I'm attempting to implement a package-scanning feature, similar to Spring's component-scan
, for the Android framework I'm developing. Basically, I would like to be able to specify a base package, e.g. com.foo.bar
and retrieve all Class
instances that have a particular annotation. I don't want to have to register every component with my framework as that would defeat the purpose of the auto scanning.
Based on my research, it seems that it's not possible with Java to retrieve resources given a package name using reflection. However, I briefly looked into the Reflections framework, and I'm wondering if there is an Android-compatible equivalent. If not, perhaps there is a slightly less obvious way to accomplish what I want to do.
I looked into the Spring source a bit to see how they achieved this, but I don't think what they are doing would work within the Dalvik runtime.
Update
Currently, the below code has been the best I can do to retrieve all classes that contain a specific annotation, but frankly it's a pretty poor solution. It makes some really unsafe assumptions about the ClassLoader
plus it scans (and loads) all application classes.
public Set<Class<?>> getClassesWithAnnotation(Class<? extends Annotation> annotation) {
Set<Class<?>> classes = new HashSet<Class<?>>();
Field dexField = PathClassLoader.class.getDeclaredField("mDexs");
dexField.setAccessible(true);
PathClassLoader classLoader = (PathClassLoader) Thread.currentThread().getContextClassLoader();
DexFile[] dexs = (DexFile[]) dexField.get(classLoader);
for (DexFile dex : dexs) {
Enumeration<String> entries = dex.entries();
while (entries.hasMoreElements()) {
String entry = entries.nextElement();
Class<?> entryClass = dex.loadClass(entry, classLoader);
if (entryClass != null && entryClass.isAnnotationPresent(annotation)) {
classes.add(entryClass);
}
}
}
return classes;
}
I share the opinion of Joop Eggen and find his approach a good one. In Android I try to avoid the usual web app features which lead to a long lasting application start. I do not use reflection or package scanning.
But if you want to .... if I understand it correctly you want to have an annotation for a class. Instead of using annotations you could also use marker interfaces (to just have more possibilites).
1) Look at
- Annotation: Java custom annotation and dynamic loading
Has an implementation in the question which just answers your question. - Annotation: Scanning Java annotations at runtime
- Interface: Find Java classes implementing an interface
- Interface: Is something similar to ServiceLoader in Java 1.5?
- Interface: How can I get a list of all the implementations of an interface programmatically in Java?
- Interface: Since the approach is expensive, maybe the ServiceLoader is a compromise between execution time and comfort, since it loads only the classes given in the services file. On the other hand if only classes with a certain interface are in your package then the ServiceLoader isn't that faster.
2) AndroidAnnotations
I would prefer the way AndroidAnnotations work (maybe an integration in AndroidAnnotations is the preferable way): It automatically adds an extra compilation step that generates source code, using the standard Java Annotation Processing Tool. So instead of runtime scanning you execute code based on the annotations generated during compile time.
I think the Bean/EBean annotation could work for you (only single class): https://github.com/excilys/androidannotations/wiki/Enhance%20custom%20classes
A scan-feature is not available, see this thread
3) Writing your own annotation processor
- See apt(annotation processing tool). The idea would be to generate a static function which returns a list of classes which are annotated, so that no class scanning is needed.
- A very good ressource is http://javadude.com/articles/annotations/index.html
这篇关于实现在Android的春天般的包扫描的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!