Programing

Java에서 프로그래밍 방식으로 인터페이스의 모든 구현 목록을 얻으려면 어떻게해야합니까?

lottogame 2020. 11. 5. 07:37
반응형

Java에서 프로그래밍 방식으로 인터페이스의 모든 구현 목록을 얻으려면 어떻게해야합니까?


반사 나 그런 식으로 할 수 있습니까?


나는 잠시 동안 찾고 있었고 다른 접근 방식이있는 것 같습니다. 여기 요약이 있습니다.

  1. 리플렉션 라이브러리는 종속성을 추가해도 괜찮다면 꽤 인기가 있습니다. 다음과 같이 표시됩니다.

    Reflections reflections = new Reflections("firstdeveloper.examples.reflections");
    Set<Class<? extends Pet>> classes = reflections.getSubTypesOf(Pet.class);
    
  2. ServiceLoader (erickson 답변에 따라) 그리고 다음과 같습니다.

    ServiceLoader<Pet> loader = ServiceLoader.load(Pet.class);
    for (Pet implClass : loader) {
        System.out.println(implClass.getClass().getSimpleName()); // prints Dog, Cat
    }
    

    이 작업을 수행하려면 PetSPI (ServiceProviderInterface) 로 정의 하고 해당 구현을 선언해야합니다. resources/META-INF/services이름 으로 파일을 만들고 그 안에 examples.reflections.Pet모든 구현을 선언 Pet하면됩니다.

    examples.reflections.Dog
    examples.reflections.Cat
    
  3. 패키지 수준 주석 . 다음은 예입니다.

    Package[] packages = Package.getPackages();
    for (Package p : packages) {
        MyPackageAnnotation annotation = p.getAnnotation(MyPackageAnnotation.class);
        if (annotation != null) {
            Class<?>[]  implementations = annotation.implementationsOfPet();
            for (Class<?> impl : implementations) {
                System.out.println(impl.getSimpleName());
            }
        }
    }
    

    및 주석 정의 :

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.PACKAGE)
    public @interface MyPackageAnnotation {
        Class<?>[] implementationsOfPet() default {};
    }
    

    패키지 package-info.java내부의 이름이 지정된 파일에서 패키지 수준 주석을 선언해야합니다 . 다음은 샘플 내용입니다.

    @MyPackageAnnotation(implementationsOfPet = {Dog.class, Cat.class})
    package examples.reflections;
    

    그 당시 ClassLoader에 알려진 패키지 만를 호출하여로드됩니다 Package.getPackages().

또한 디렉토리 기반 검색을 수행하지 않는 한 항상 이미로드 된 클래스로 제한되는 URLClassLoader 기반의 다른 접근 방식이 있습니다.


erickson이 말한 것,하지만 여전히하고 싶다면 Reflections를 살펴보십시오 . 페이지에서 :

Reflections를 사용하여 메타 데이터를 쿼리 할 수 ​​있습니다.

  • 특정 유형의 모든 하위 유형 가져 오기
  • 일부 주석으로 주석이 달린 모든 유형 가져 오기
  • 주석 매개 변수 일치를 포함하여 일부 주석으로 주석이 달린 모든 유형을 가져옵니다.
  • 모든 메소드에 일부 주석을 달다

일반적으로이 작업은 비용이 많이 듭니다. 리플렉션을 사용하려면 클래스를로드해야합니다. 클래스 경로에서 사용 가능한 모든 클래스를로드하려면 시간과 메모리가 필요하므로 권장되지 않습니다.

이것을 피하려면 리플렉션 대신 더 효율적으로 작동하는 자체 클래스 파일 파서를 구현해야합니다. 바이트 코드 엔지니어링 라이브러리가이 접근 방식에 도움이 될 수 있습니다.

서비스 제공자기구 플러그 서비스의 구현을 열거 종래의 수단이다. 를 사용하여 ServiceLoader자바 6, 또는 이전 버전에서 자신을 구현합니다. 다른 답변에 제공 했습니다 .


Spring에는 이것을 달성하는 매우 간단한 방법이 있습니다.

public interface ITask {
    void doStuff();
}

@Component
public class MyTask implements ITask {
   public void doStuff(){}
}

그런 다음 유형 목록을 자동 연결 ITask하면 Spring이 모든 구현으로 채울 것입니다.

@Service
public class TaskService {

    @Autowired
    private List<ITask> tasks;
}

Yes, the first step is to identify "all" the classes that you cared about. If you already have this information, you can enumerate through each of them and use instanceof to validate the relationship. A related article is here: http://www.javaworld.com/javaworld/javatips/jw-javatip113.html


What erikson said is best. Here's a related question and answer thread - http://www.velocityreviews.com/forums/t137693-find-all-implementing-classes-in-classpath.html

The Apache BCEL library allows you to read classes without loading them. I believe it will be faster because you should be able to skip the verification step. The other problem with loading all classes using the classloader is that you will suffer a huge memory impact as well as inadvertently run any static code blocks which you probably do not want to do.

The Apache BCEL library link - http://jakarta.apache.org/bcel/


With ClassGraph it's pretty simple:

Groovy code to find implementations of my.package.MyInterface:

@Grab('io.github.classgraph:classgraph:4.6.18')
import io.github.classgraph.*
new ClassGraph().enableClassInfo().scan().withCloseable { scanResult ->
    scanResult.getClassesImplementing('my.package.MyInterface').findAll{!it.abstract}*.name
}

Also, if you are writing an IDE plugin (where what you are trying to do is relatively common), then the IDE typically offers you more efficient ways to access the class hierarchy of the current state of the user code.


I ran into the same issue. My solution was to use reflection to examine all of the methods in an ObjectFactory class, eliminating those that were not createXXX() methods returning an instance of one of my bound POJOs. Each class so discovered is added to a Class[] array, which was then passed to the JAXBContext instantiation call. This performs well, needing only to load the ObjectFactory class, which was about to be needed anyway. I only need to maintain the ObjectFactory class, a task either performed by hand (in my case, because I started with POJOs and used schemagen), or can be generated as needed by xjc. Either way, it is performant, simple, and effective.


A new version of @kaybee99's answer, but now returning what the user asks: the implementations...

Spring has a pretty simple way to acheive this:

public interface ITask {
    void doStuff();
    default ITask getImplementation() {
       return this;
    }

}

@Component
public class MyTask implements ITask {
   public void doStuff(){}
}

Then you can autowire a list of type ITask and Spring will populate it with all implementations:

@Service
public class TaskService {

    @Autowired(required = false)
    private List<ITask> tasks;

    if ( tasks != null)
    for (ITask<?> taskImpl: tasks) {
        taskImpl.doStuff();
    }   
}

The most robust mechanism for listing all classes that implement a given interface is currently ClassGraph, because it handles the widest possible array of classpath specification mechanisms, including the new JPMS module system. (I am the author.)

try (ScanResult scanResult = new ClassGraph().whitelistPackages("x.y.z")
        .enableClassInfo().scan()) {
    for (ClassInfo ci : scanResult.getClassesImplementing("x.y.z.SomeInterface")) {
        foundImplementingClass(ci);  // Do something with the ClassInfo object
    }
}

참고URL : https://stackoverflow.com/questions/347248/how-can-i-get-a-list-of-all-the-implementations-of-an-interface-programmatically

반응형