Java 弹簧维修定位器,无需自动接线
有此代码:Java 弹簧维修定位器,无需自动接线,java,spring,spring-boot,dependency-injection,service-locator,Java,Spring,Spring Boot,Dependency Injection,Service Locator,有此代码: public class ClassA { private InterfaceB interfaceB; private int a private int b; public ClassA(int a, int b) { this.a = a; this.b = b; } } 在我的应用程序中可能有几个ClassA对象,它们是在运行时按需创建的。但它们都应该使用相同的InterfaceB类的具体实现(有几
public class ClassA {
private InterfaceB interfaceB;
private int a
private int b;
public ClassA(int a, int b) {
this.a = a;
this.b = b;
}
}
在我的应用程序中可能有几个ClassA
对象,它们是在运行时按需创建的。但它们都应该使用相同的InterfaceB
类的具体实现(有几种InterfaceB
实现,但根据使用的平台,在运行时只使用一种)。应用程序中应该只有一个InterfaceB
对象(singleton类)
当a
和b
构造函数参数已知时,我无法自动连接interfaceB
,因为ClassA
对象是在运行时创建的
我如何在这里使用Spring框架来实现服务定位器模式?我的计划是在
ClassA
中实例化服务定位器,并使用它获取InterfaceB
对象 您可以创建一个额外的类,该类将创建您的ClassA
,它将保存对接口b
的引用。例如:
@Component
public class ClassAFactory {
@Autowired
private InterfaceB interfaceB;
public ClassA create(int a, int b) {
return new ClassA(a, b, interfaceB);
}
}
在这种情况下,您必须扩展ClassA
以传递接口b
。
然后在代码中的某个地方,您可以:
@Autowired
private ClassAFactory factory ;
...
ClassA classA = factory.create(1,1);
我认为您不需要服务定位器模式,在现代spring驱动的应用程序中,它通常不再需要 我将尝试从Spring框架的集成角度阐述您的所有陈述: 在我的应用程序中可能有几个ClassA对象,它们是在运行时按需创建的 Spring是一个运行时框架,所以一切都是在运行时创建的。如果您需要许多由demand创建的对象,您可以将ClassA声明为具有范围原型的Springbean。 其他bean可以注入这个原型bean。如果您知道在应用程序启动期间将创建哪些实例,另一种可能的方法是定义许多相同类型的bean,并在注入期间使用spring的限定符特性来区分它们 但它们都应该使用相同的InterfaceB类的具体实现(InterfaceB有几种实现,但根据使用的平台,在运行时只使用一种) 这意味着
InterfaceB
可以是一个常规的单例,但是,给定不同的实现,您可以定义如下内容:
@Configuration
public class MyConfiguration {
@Bean
@ConditionalOnProperty(name="myprop", havingValue="true")
public InterfaceB interfaceBImpl1() {
return new InterfaceBImpl1();
}
@Bean
@ConditionalOnProperty(name="myprop", havingValue="false")
public InterfaceB interfaceBImpl2() {
return new InterfaceBImpl2();
}
}
public class SingletonWithPrototypesConfig {
@Bean
public ServiceA serviceA(Provider<ClassA> classAProvider) {
return new ServiceA(classAProvider);
}
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public ClassA classA(InterfaceB interfaceB) {
return new ClassA(interfaceB);
}
@Bean
public InterfaceB interfaceB() {
return new InterfaceB();
}
}
我不能自动连接interfaceB,因为当a和b构造函数参数已知时,ClassA对象是在运行时创建的
事实上你可以,没问题。将classA的bean定义为原型
如果您只想在第一次调用时初始化该classA的实例,请检查spring的@Lazy
注释
public class ClassA {
/// fields ///
public ClassA(InterfaceB intefaceB, int a, int b) {
this.intefaceB = intefaceB;
this.a = a;
this.b = b;
}
}
@Configuration
class MyConfig {
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public ClassA classA(InterfaceB bImpl, int a, int b) {
return new ClassA(bImpl, int a, int b);
}
}
更新1
根据OP的评论:
以下是工作示例:
在pom.xml中添加以下依赖项:
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
在最后一个打印说明中,ClassA实例不同,但interfaceB是相同的共享实例
旁注:提供程序已经与spring集成,它驻留在新jar的
javax.inject.Provider
中。如何使用此示例按需创建InterfaceB对象和ClassA对象?执行类似AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(MyConfig.class)然后执行context.getBean(“classA”)?请使用实际使用“classA”的对象的代码片段更新问题,以便我可以在您的案例中演示如何执行。基本上,您不应该在业务代码中直接使用应用程序上下文……您可以假设serviceX拥有类X对象的内存列表,并为它们执行CRUD。ClassX对象有一个属性是ClassA对象。在给定的时间内(例如,一些用户请求),服务被请求添加一个新的ClassX对象。ClassX对象如何获得工厂?ClassX对象的“新建”由ServiceX@MABC-请查看我答案的更新,我已经在我的机器上运行了此示例,它复制了您的案例并解决了问题。如果您需要其他信息,请告诉我。为什么不在ClassA构造函数中使用this.interfaceB=ctx.getBean(“interfaceB”)?如果不是由Spring自动连接,我将如何获得工厂?我的意思是,持有工厂引用的对象不是bean本身,所以你想在spring管理的代码之外创建ClassA
?你能举例说明你想如何创建ClassA
?你可以假设一个serviceX拥有一个ClassX对象的内存列表,并对它们执行CRUD。ClassX对象有一个属性是ClassA对象。在给定的时间内(例如,一些用户请求),服务被请求添加一个新的ClassX对象。ClassX对象如何获得工厂?ClassX对象的“新建”由ServiceXFactory执行,应该在serviceX中(例如使用@Autowired)。如果您想通过添加ClassA来更改ClassX,那么serviceX应该这样做:ClassX.ClassA=factory.create(1,1)代码>如果工厂位于serviceX中,为了将ClassA对象注入ClassB,它将serviceX与工厂和ClassA耦合,并不必要地公开ClassX的内部细节(违反信息隐藏原则)。我认为工厂应该在ClassA中,在ClassA的构造函数中,它使用工厂获取InterfaceB对象。如果我将工厂声明为带有@Component的Bean,那么我如何使用Spring获得它呢??
public class SingletonWithPrototypesConfig {
@Bean
public ServiceA serviceA(Provider<ClassA> classAProvider) {
return new ServiceA(classAProvider);
}
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public ClassA classA(InterfaceB interfaceB) {
return new ClassA(interfaceB);
}
@Bean
public InterfaceB interfaceB() {
return new InterfaceB();
}
}
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SingletonWithPrototypesConfig.class);
ServiceA serviceA = ctx.getBean(ServiceA.class);
serviceA.doWithAllElementsInList(); // won't print anything, 0 elements in the list
System.out.println("---------");
serviceA.addNewObject();
serviceA.addNewObject();
serviceA.doWithAllElementsInList();
}