CDI中自动注入同版本包下RequestDataProvider至VersionInfo的方法
Yes, absolutely! In Java EE, you can leverage CDI (Contexts and Dependency Injection) features to make this work seamlessly. Below are two practical approaches tailored to your package structure:
Approach 1: Use Qualifiers to Group Cohesive Service/Provider Pairs
This is the most idiomatic Java EE solution, as it explicitly marks which RequestDataProvider belongs to which MainService set, keeping your code type-safe and maintainable.
Step 1: Define Custom Qualifier Annotations
Create qualifiers to distinguish between V1 and V2 component groups:
// com/common/qualifiers/V1.java @Qualifier @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER}) public @interface V1 {}
// com/common/qualifiers/V2.java @Qualifier @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER}) public @interface V2 {}
Step 2: Annotate Your Components
Apply the qualifiers to your MainService and RequestDataProvider classes in each package:
// com/V1/MainService.java @V1 @Stateless // Or @ApplicationScoped, based on your scope needs public class MainService { @Inject @V1 private RequestDataProvider dataProvider; @Inject private VersionInfo versionInfo; // Your service business logic here }
// com/V1/RequestDataProvider.java @V1 @ApplicationScoped public class RequestDataProvider { // Provider-specific logic here }
Repeat this pattern for the V2 package, replacing @V1 with @V2.
Step 3: Inject the Matching Provider in VersionInfo
In VersionInfo, use Instance<RequestDataProvider> to dynamically select the provider that matches the qualifier of the active MainService:
// com/common/VersionInfo.java @ApplicationScoped public class VersionInfo { @Inject private Instance<RequestDataProvider> dataProviderInstance; @Inject private BeanManager beanManager; public RequestDataProvider getMatchingProvider(MainService mainService) { // Get the qualifiers attached to the calling MainService Set<Annotation> serviceQualifiers = beanManager.getBeans(mainService.getClass()) .iterator().next().getQualifiers(); // Find the RequestDataProvider with identical qualifiers for (RequestDataProvider provider : dataProviderInstance) { Set<Annotation> providerQualifiers = beanManager.getBeans(provider.getClass()) .iterator().next().getQualifiers(); if (providerQualifiers.equals(serviceQualifiers)) { return provider; } } throw new IllegalStateException("No matching RequestDataProvider found for this MainService"); } }
Then in your MainService, call versionInfo.getMatchingProvider(this) to retrieve the correct provider.
Approach 2: Programmatic Lookup by Package Using BeanManager
If you prefer to avoid qualifiers, you can directly look up the RequestDataProvider by constructing its fully qualified class name from the MainService's package:
// com/common/VersionInfo.java @ApplicationScoped public class VersionInfo { @Inject private BeanManager beanManager; public RequestDataProvider getPackageMatchingProvider(MainService mainService) { String servicePackage = mainService.getClass().getPackageName(); String providerClassName = servicePackage + ".RequestDataProvider"; try { Class<?> providerClass = Class.forName(providerClassName); Bean<?> providerBean = beanManager.getBeans(providerClass).iterator().next(); CreationalContext<?> ctx = beanManager.createCreationalContext(providerBean); return (RequestDataProvider) beanManager.getReference(providerBean, providerClass, ctx); } catch (ClassNotFoundException e) { throw new IllegalStateException("RequestDataProvider not found in package: " + servicePackage, e); } } }
This method relies on consistent naming conventions between your MainService and RequestDataProvider packages, which works well if your structure is stable.
Both approaches are valid, but Approach 1 is recommended because it follows CDI best practices, avoids hardcoded package names, and makes component relationships explicit.
内容的提问来源于stack exchange,提问作者carbolymer

