क्या मैं इसे प्रतिबिंब या ऐसा कुछ कर सकता हूं?
क्या मैं इसे प्रतिबिंब या ऐसा कुछ कर सकता हूं?
जवाबों:
मैं कुछ समय से खोज रहा हूं और लगता है कि अलग-अलग दृष्टिकोण हैं, यहां एक सारांश है:
यदि आप निर्भरता को जोड़ने में कोई आपत्ति नहीं करते हैं तो प्रतिबिंब पुस्तकालय बहुत लोकप्रिय है यह इस तरह दिखेगा:
Reflections reflections = new Reflections("firstdeveloper.examples.reflections");
Set<Class<? extends Pet>> classes = reflections.getSubTypesOf(Pet.class);
ServiceLoader (erickson जवाब के अनुसार) और यह इस तरह दिखेगा:
ServiceLoader<Pet> loader = ServiceLoader.load(Pet.class);
for (Pet implClass : loader) {
System.out.println(implClass.getClass().getSimpleName()); // prints Dog, Cat
}
ध्यान दें कि इस काम के लिए आपको Pet
एक ServiceProviderInterface (SPI) के रूप में परिभाषित करने और इसके कार्यान्वयन की घोषणा करने की आवश्यकता है। आप resources/META-INF/services
नाम के साथ एक फ़ाइल बनाकर examples.reflections.Pet
और Pet
उसमें सभी कार्यान्वयन घोषित करते हैं
examples.reflections.Dog
examples.reflections.Cat
पैकेज स्तर के एनोटेशन । यहाँ एक उदाहरण है:
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 पर आधारित अन्य दृष्टिकोण हैं जो हमेशा उन कक्षाओं तक सीमित रहेंगे जो पहले से लोड किए गए हैं, जब तक कि आप निर्देशिका-आधारित खोज नहीं करते हैं।
एरिकसन ने क्या कहा, लेकिन अगर आप अभी भी इसे करना चाहते हैं तो रिफ्लेक्शन पर एक नज़र डालें । उनके पेज से:
उन प्रतिबिंबों का उपयोग करना जिनके लिए आप अपनी मेटाडेटा को क्वेरी कर सकते हैं:
- सभी प्रकार के सभी उपप्रकार प्राप्त करें
- कुछ एनोटेशन के साथ सभी प्रकार के एनोटेट प्राप्त करें
- कुछ प्रकार के एनोटेशन के साथ एनोटेशन प्राप्त करें, जिसमें एनोटेशन मापदंडों का मिलान शामिल है
- सभी तरीकों को कुछ के साथ एनोटेट करें
new Reflections("my.package").getSubTypesOf(MyInterface.class)
सामान्य तौर पर, ऐसा करना महंगा है। प्रतिबिंब का उपयोग करने के लिए, कक्षा को लोड करना होगा। यदि आप क्लासपैथ पर उपलब्ध हर क्लास को लोड करना चाहते हैं, तो यह समय और मेमोरी लेगा, और अनुशंसित नहीं है।
यदि आप इससे बचना चाहते हैं, तो आपको प्रतिबिंब के बजाय अपने स्वयं के क्लास फाइल पार्सर को लागू करना होगा जो अधिक कुशलता से संचालित हो। एक बाइट कोड इंजीनियरिंग लाइब्रेरी इस दृष्टिकोण के साथ मदद कर सकती है।
सेवा प्रदाता तंत्र एक प्लगेबल सेवा के कार्यान्वयन की गणना करने में पारंपरिक साधन है, और जावा 9. उपयोग में परियोजना Jigsaw (मॉड्यूल) की शुरूआत के साथ और अधिक स्थापित हो गया है ServiceLoader
जावा में 6, या पुराने संस्करणों में अपने स्वयं के लागू। मैंने एक और उत्तर में एक उदाहरण प्रदान किया ।
META-INF/services/java.sql.Driver
वसंत के पास इसे हासिल करने का एक बहुत ही सरल तरीका है:
public interface ITask {
void doStuff();
}
@Component
public class MyTask implements ITask {
public void doStuff(){}
}
तब आप प्रकार की एक सूची को स्वतः प्राप्त कर सकते हैं ITask
और स्प्रिंग इसे सभी कार्यान्वयनों के साथ आबाद करेगा:
@Service
public class TaskService {
@Autowired
private List<ITask> tasks;
}
किसी दिए गए इंटरफ़ेस को लागू करने वाले सभी वर्गों को सूचीबद्ध करने के लिए सबसे मजबूत तंत्र वर्तमान में क्लासग्राफ है , क्योंकि यह नए जेपीएमएस मॉड्यूल सिस्टम सहित क्लासपैथ विनिर्देश तंत्र के सबसे व्यापक संभावित सरणी को संभालता है। (मैं लेखक हूँ)
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
}
}
एरिकसन ने जो कहा वह सबसे अच्छा है। यहाँ एक संबंधित प्रश्न और उत्तर धागा है - http://www.velocityreviews.com/forums/t137693-find-all-implementing-classes-in-classpath.html
Apache BCEL लाइब्रेरी आपको कक्षाओं को लोड किए बिना पढ़ने की अनुमति देती है। मेरा मानना है कि यह तेज़ होगा क्योंकि आपको सत्यापन चरण को छोड़ना चाहिए। क्लास लोडर का उपयोग करके सभी वर्गों को लोड करने के साथ अन्य समस्या यह है कि आप एक विशाल मेमोरी प्रभाव के साथ-साथ अनजाने में किसी भी स्थिर कोड ब्लॉक को चलाएंगे जो आप शायद नहीं करना चाहते हैं।
अपाचे BCEL लाइब्रेरी लिंक - http://jakarta.apache.org/bcel/
ClassGraph के साथ यह बहुत आसान है:
के कार्यान्वयन को खोजने के लिए Groovy कोड 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
}
scan().withCloseable { ... }
Groovy में कॉल करने की आवश्यकता है , या जावा में try-with-resource का उपयोग करने की आवश्यकता है : github.com/classgraph/classgraph/wiki/… इसके अलावा, अंतिम भाग होना चाहिए .name
, नहीं .className
, क्योंकि .getName()
क्लास का नाम लेने के लिए सही तरीका है किसी ClassInfo
वस्तु से।
हां, पहला चरण उन सभी वर्गों की पहचान करना है जिनकी आपने परवाह की है। यदि आपके पास पहले से यह जानकारी है, तो आप उनमें से प्रत्येक के माध्यम से गणना कर सकते हैं और संबंध को मान्य करने के लिए इंस्टाफॉ का उपयोग कर सकते हैं। एक संबंधित लेख यहां है: https://web.archive.org/web/20100226233915/www.javaworld.com/javaworld/javatips/jw-javatip113.html
@ Kaybee99 के उत्तर का एक नया संस्करण, लेकिन अब वह वापस आ रहा है जो उपयोगकर्ता पूछता है: कार्यान्वयन ...
वसंत के पास इसे हासिल करने का एक बहुत ही सरल तरीका है:
public interface ITask {
void doStuff();
default ITask getImplementation() {
return this;
}
}
@Component
public class MyTask implements ITask {
public void doStuff(){}
}
तब आप प्रकार की एक सूची को स्वतः प्राप्त कर सकते हैं ITask
और स्प्रिंग इसे सभी कार्यान्वयनों के साथ आबाद करेगा:
@Service
public class TaskService {
@Autowired(required = false)
private List<ITask> tasks;
if ( tasks != null)
for (ITask<?> taskImpl: tasks) {
taskImpl.doStuff();
}
}
मैं उसी मुद्दे में भाग गया। मेरा समाधान ऑब्जेक्टफैक्टिव वर्ग में सभी तरीकों की जांच करने के लिए प्रतिबिंब का उपयोग करना था, जो कि मेरे बाध्य पीओजेओ में से एक की वापसी के तरीके को बनाने वाले एक्सएक्सएक्सएक्सएक्सएक्स () तरीके नहीं थे। खोजे गए प्रत्येक वर्ग को एक कक्षा [] सरणी में जोड़ा जाता है, जिसे तब JAXBContext तात्कालिकता कॉल में पास किया गया था। यह अच्छी तरह से निष्पादित करता है, केवल ऑब्जेक्टफैक्टरी वर्ग को लोड करने की आवश्यकता होती है, जो कि वैसे भी आवश्यक होने वाली थी। मुझे केवल ऑब्जेक्टफैक्ट क्लास को बनाए रखने की आवश्यकता है, एक कार्य या तो हाथ से किया जाता है (मेरे मामले में, क्योंकि मैंने पीओजेओ के साथ शुरू किया और योजनाबद्ध उपयोग किया), या xjc द्वारा आवश्यकतानुसार उत्पन्न किया जा सकता है। किसी भी तरह से, यह सरल, और प्रभावी है।