是否可以使用反射通过限定符注释获取类?

时间:2014-05-30 11:26:25

标签: java reflection annotations

我有一个包含许多可能实现的接口。应在运行时选择正确的实现。所以反射听起来就是解决方案。

我通过一个限定符来注释这些类,该限定符具有枚举作为参数。

那么,是否可以通过将正确的枚举传递给注释来使用反射在运行时获得正确的实现?

但是,如果有另一种方式,反思不是强制性的。

首先,这是枚举:

public enum CATEGORY {
 A,B,C;
}

然后,这里是界面:

public interface GenericI{
   void method1(CATEGORY arg);
   // some other methods
}

现在,这里有注释的实现:

@MyAnnotation(CATEGORY.A)
public class impl1 implements GenericI{
    void method1(CATEGORY arg){
       // some work here
    }
}

@MyAnnotation(CATEGORY.B)
public class impl2 implements GenericI{
    void method1(CATEGORY arg){
       // some work here
    }    
}

最后,代理在某种程度上,使用注释和枚举选择动态正确的实现(可能它不应该实现GenericI ??):

public class MyProxy implements GenericI {

  // Here we must be able to select the right implementation
}

1 个答案:

答案 0 :(得分:1)

Reflexion是一个答案,但您需要从类路径中获取所有类,并检查它以找到您的界面的实现。

你可以使用this reflection库并获得这样的所有实现(如果你的接口名是MyInterface):

Reflections reflections = new Reflections("your.base.package", new SubTypesScanner(), new TypeAnnotationsScanner());
Set<Class<T extends MyInterface>> classes = reflections.getSubTypesOf(MyInterface.class);

for (Class<T extends MyInterface> c : classes) {

     check if c is the rigth implementation!.
}

如果您不想使用外部库,可以使用Java Reflection API,并扫描所有包,例如(请参阅this answers使用检测):

Instrumentation inst = InstrumentHook.getInstrumentation();
for (Class<?> c: inst.getAllLoadedClasses()) {
    if (MyInterface.class.isAssignableFrom(c)) {
         check if c is the rigth implementation!.
    }
}

第一个选项允许您将Reflections对象保存为xml,因此保存组件扫描并且只执行一次。

要检查clazz是否有Qualifier您可以使用:

if (c.isAnnotationPresent(Qualifier.class)) {
     bingo!.
}

或是注释的属性:

if (c.isAnnotationPresent(Qualifier.class)) {
     Qualifier q = c.getAnnotation(Qualifier.class);
     if (q.theRight()) {
         bingo!
     }
}

我建议您查看FactoryProblem是否适用于您的问题,请始终选择Factory而不是Reflection

示例“代理”:

public class MyProxy implements GenericI {

    Map<Category, GenericI> generics;

    public MyProxy() {
        Reflections reflections = new Reflections("your.base.package", new SubTypesScanner(), new TypeAnnotationsScanner());
        Set<Class<T extends MyInterface>> classes = reflections.getSubTypesOf(MyInterface.class);
        generics = new HashMap<Category, GenericI>();
        for (Class<T extends MyInterface> c : classes) {

            map.put(c.getAnnotation(MyAnnotation.class).value(), c.newInstance());
        }       
    }

    void method1(CATEGORY arg){

        map.get(arg).method1(arg);
    }   

}

这非常繁重且过于复杂,如果您使用此功能,请添加大量测试,并使MyProxy成为单身人士。

如果您使用IOC框架:

@Component
public class MyProxy implements GenericI {

    @Autoriwed // If spring
    List<GenericI> generics; 

    @Inject @Any // If CDI
    private Instance<GenericI> services;

    Map<Category, GenericI> generics;

    @PostConstruct
    void makeMap() {
        generics = new HashMap<>();
        for (GenericI component : generics) {
            generics.put(
                component.getClass().getAnnotation(MyAnnotation.class).value(),
                component);
        }
    }

    void method1(CATEGORY arg){

        map.get(arg).method1(arg);
    }   

}

我假设你不知道可能的子类。