Issue
Suppose I have a component such as:
@Component
public class MyComponent {
...
}
Now, I want to instantiate this component manually and make it a singleton, so in my main function, I create a new context and then create a new MyComponent
and register it as a singleton:
var context = new AnnotationConfigApplicationContext(AppConfig.class);
context.getBeanFactory().registerSingleton(MyComponent.class.getCanonicalName() + ".ORIGINAL", new MyComponent());
context.refresh();
The problem I am finding is that MyComponent
is still being created by Spring
, so I don't end up with a single instance of the class, but two.
How can I make this work?
Full example:
Main class:
package my.spring;
import static org.springframework.beans.factory.config.AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class SpringTest extends Application {
@Override
public void start(Stage primaryStage) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
context.getBeanFactory()
.registerSingleton(MyComponent.class.getCanonicalName() + ORIGINAL_INSTANCE_SUFFIX,
new MyComponent());
MyComponent singleton = context.getBean(MyComponent.class); // This fails because there are now two such types
primaryStage.setScene(new Scene(new VBox(20,
new TextArea("Hello Spring"),
new TextArea(singleton.myName))));
primaryStage.setOnCloseRequest(w -> context.close());
primaryStage.show();
}
}
AppConfig.java
package my.spring;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan
public class AppConfig {
}
MyComponent.java
package my.spring;
import org.springframework.stereotype.Component;
@Component
public class MyComponent {
public final String myName = getClass().getCanonicalName();
}
The solution I am looking for should not involve filtering
out MyComponent
in the AppConfig
component scan. I am looking for a dynamic solution that will allow me to tell spring not to create certain singletons when they already exist in the dependency graph.
Is this possible or not?
Solution
Here are different solutions for this:
1) Remove annotation @Component
form your class ``MyComponent`.
2) Define interface and inject it where you need as interface. In your code create and implementation of the interface like '... registerSingleton(..., new MyComponentImpl())'.
Following approaches do not fit all your requirements, but I'd suggest that you consider them, too.
3) If your goal is just to register a component with a particular name, consider using @Component("MyName")
.
4) Use configuration class (annotated with @Configuration
). In the method that provides the bean of type MyComponent
manually create your bean. Here you don't register the bean manually, but still you have a control over creation of the bean. For instance you can initialize it differently depending on some configuration parameters, or you can even create instances of different subclasses.
5) Implement a factory that will create this bean. Again, you will not inject it directly. But you will have full control over creation of your bean.
If you tell us what you are actually trying to achieve, there can be also other solutions.
Answered By - mentallurg
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.