Annotating field/constructor is providing only one instance of the class even if the bean is configured as a prototype. But I want new instances for a particular class in a loop.
Below is my Component class:
#Component
class Link{
#Autowired
private RandomClass rcobj;
public void getFiveInstancesOfRandomClass(){
//here I want to create five new instances for RandomClass but I get only one by auto-wiring
}
}
Config.class
#Configuration
class ApplicationConfig{
#Bean
public Link link(){ return new Link();}
#Bean
#scope ("prototype")
public RandomClass randomClass(){ return new RandomClass();}
}
I looked at few examples which mostly use xml based configuration. One of the solutions is by invoking ApplicationContext but I want to solve this with lookup-method.
To inject prototype to singleton via java config I'm using following technique:
Singleton class:
public abstract class Single
{
abstract Proto newInstance();
public void useBean()
{
System.out.println( newInstance() );
}
}
Prototype class:
public class Proto
{
}
Context:
public class Context
{
#Bean
public Single single()
{
return new Single() {
#Override
Proto newInstance()
{
return proto();
}
};
}
#Bean
#Scope("prototype")
public Proto proto()
{
return new Proto();
}
}
Class for testing:
public static void main( String[] args )
{
ApplicationContext context = new AnnotationConfigApplicationContext( Context.class );
Single single = context.getBean( Single.class );
single.useBean();
single.useBean();
}
From output we can see that each call used different object:
test.Proto#b51256
test.Proto#1906517
p.s.
I totally agree with you, we should not bind beans with applicationContext. It creates additional coupling and I believe this is not a good practice.
Related
I have a service that uses some object as a generic
#Component
#RequiredArgsConstructor
public class SomeGenericService<T extends Base> {
private final T base;
public void someWork(String info) {
base.someAction(info);
}
}
I also have 3 Base implementations marked with #Component(Base1, Base2, Base3)
I want spring itself to create a service with the generic it needs, for the following example
#Component
#RequiredArgsConstructor
public class Runner implements CommandLineRunner {
private final SomeGenericService<Base1> s1;
private final SomeGenericService<Base2> s2;
private final SomeGenericService<Base3> s3;
#Override
public void run(String... args) throws Exception {
String someString = "text";
s1.someWork(someString);
s2.someWork(someString);
s3.someWork(someString);
}
}
But after the launch, the spring does not understand what I want from it.
Parameter 0 of constructor in SomeGenericService required a single bean, but 3 were found:
- base1: defined in file [Base1.class]
- base2: defined in file [Base2.class]
- base3: defined in file [Base3.class]
Is it possible to set this to automatic, without manually configuring it via the #Bean annotation for each service?
You need to define how those beans should be injected. It's a good practice to have some #Configurations for this purpose. Something like:
#Configuration
#Import({
Base1.class,
Base2.class,
Base3.class
})
public class SomeConfig {
#Bean
SomeGenericService<Base1> someGenericService1() {
return new SomeGenericService(new Base1());
}
#Bean
SomeGenericService<Base2> someGenericService2() {
return new SomeGenericService(new Base2());
}
#Bean
SomeGenericService<Base3> someGenericService3() {
return new SomeGenericService(new Base3());
}
}
I am totally confused about mixing of "wiring in JavaConfig" and "wiring using #Autowired". I will tell you my problems in 4 scenarios:
(I am ok with mixing of #Autowired and stereotype annotations and I don't have any question about that. my problem is Javaconfig and #autowired)
Scenario 1:
My CDPlayer Class:
public class CDPlayer implements MediaPlayer {
private CompactDisc cd;
public CDPlayer() {
cd = new CompactDisc() {
#Override
public void play() {
System.out.println("123456");
}
};
}
#Autowired
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
public void play() {
cd.play();
}
}
My JavaConfig File:
#Configuration
public class CDPlayerConfig {
#Bean
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}
#Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer();
}
}
For Example in this scenario, I see that #Autowired is effectless and cannot make Spring to invoke and use the parameterized constructor and no-arg constructor will be executed (because it is invoked in the #Bean method) and the output is the text "123456".
=================================================================
SCENARIO 2:
My JavaConfig File:
#Configuration
public class CDPlayerConfig {
#Bean
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}
#Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer(compactDisc);
}
}
My CDPlayer Class:
public class CDPlayer implements MediaPlayer {
private CompactDisc cd;
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
public void play() {
cd.play();
}
}
we wired those two beans in the config file. and I know that we do not need #Autowired at all.
=================================================================
SCENARIO 3:
My JavaConfig File:
#Configuration
public class CDPlayerConfig {
#Bean()
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}
#Bean
public CDPlayer cdPlayer() {
return new CDPlayer();
}
}
My CDPlayer Class:
public class CDPlayer implements MediaPlayer {
private CompactDisc cd;
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
public void play() {
cd.play();
}
#Autowired
public void setCd(CompactDisc cd) {
this.cd = cd;
}
}
I know that if #Autowired is above of parameterized constructor, that constructor will not be executed but now that is above of setCd(), this method will be executed.
=================================================================
SCENARIO 4:
My JavaConfig File:
#Configuration
public class CDPlayerConfig {
#Bean
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}
#Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer(compactDisc);
}
}
My CDPlayer Class:
public class CDPlayer implements MediaPlayer {
private CompactDisc cd;
public CDPlayer() {
}
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
public void play() {
cd.play();
}
#Autowired
public void doSomething(CompactDisc cd) {
this.cd = new CompactDisc() {
#Override
public void play() {
System.out.println("AAAAA");
}
};
}
}
and in this scenario, Although that we wired those two beans together, but #Autowired makes spring to execute the doSomething()method.
What is happening?! I can't see the Big Picture. I can't understand the pattern that is going on.
sometimes #Autowired works and sometimes doesn't work. what is the general pattern? do we need #Autowired at all when we wire beans together in JavaConfig file?
An autowired constructor is invoked if spring invokes the constructor by reflection, typically because you declare the bean using component scanning or XML config. If you manually invoke a constructor in a #Bean method, that constructor executes, and #Autowired has no effect.
An autowired method is invoked after the bean has been created, irrespective of how the bean was created.
The reason is that, in Java, each constructor call creates a new object, making it impossible to call two constructors for the same object. That's why Spring can't call a second constructor if you have already called a different one. In contrast, it is possible to call many methods on the same object, so Spring does support method autowiring just fine.
To conclude, you can use autowiring with JavaConfig, but you should autowire fields or methods rather than constructors. Or you can do without autowiring, and pass everything explicitly in your #Bean method. Or any mixture of the two.
The Spring Context contains all the beans you need in your program, and Spring do the rest of the job for you. But something to understand is that your beans comes from many parts of your application :
Internal beans (POJO from your domain).
External beans (POJO from other libraries or third partie classes).
Reading this from the spring documentation, you can find all the differents sources of beans :
#SpringBootApplication is a convenience annotation that adds all of
the following:
#Configuration: Tags the class as a source of bean definitions for the
application context.
#EnableAutoConfiguration: Tells Spring Boot to start adding beans
based on classpath settings, other beans, and various property
settings. For example, if spring-webmvc is on the classpath, this
annotation flags the application as a web application and activates
key behaviors, such as setting up a DispatcherServlet.
#ComponentScan: Tells Spring to look for other components,
configurations, and services in the com/example package, letting it
find the controllers.
Follow these rules :
In your domain classes (Controller, Service) : use #Autowired in your constructor. It is the recommanded way to inject your dependencies.
You want to use external classes : implements a Java Configuration with #Configuration annotation, to instanciate your external classes as beans.
You want to create custom utilities classes : decorate it with #Component.
When you have more than on implementation, use #Qualifier and define your beans in a #Configuration class.
I am trying to learn autowire with Qualifier in spring and the autowired class constructor is called twice .
I have the following class:
MainApp:
public class MainApp {
public static void main(String[] args) {
// ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
ApplicationContext ctx =
new AnnotationConfigApplicationContext(HelloWorldConfig.class);
// TextEditor obj = (TextEditor) ctx.getBean("helloWorld");
TextEditor obj = (TextEditor)ctx.getBean(TextEditor.class);
obj.spellCheck();
}
SpellChecker:
public class SpellChecker {
public SpellChecker() {
System.out.println("Inside SpellChecker constructor.");
}
public void checkSpelling() {
System.out.println("Inside checkSpelling.");
}
TextEditor
public class TextEditor {
#Qualifier("a")
#Autowired
private SpellChecker spellChecker;
public SpellChecker getSpellChecker( ) {
return spellChecker;
}
public void spellCheck() {
spellChecker.checkSpelling();
}
}
I have the java based configuration which has multiple bean with same Type and want to select a single bean with Qualifier but the output shows the constructor is called twice.\
HelloWorldConfig
#Component
public class HelloWorldConfig {
#Bean
public HelloWorld helloWorld(){
return new HelloWorld();
}
#Bean
public TextEditor textEditor(){
return new TextEditor();
}
#Bean(name="a")
public SpellChecker spellChecker(){
return new SpellChecker();
}
#Bean(name="b")
public SpellChecker spellChecker1(){
return new SpellChecker();
}
}
OUTPUT:
Inside SpellChecker constructor.
Inside SpellChecker constructor.
Inside checkSpelling.
I was expecting a single SpellChecker constructor call since i used Qualifier("a") to specify the bean, however the constructor is called twice even if I used Qualifier to select a sinlge bean. Why is it called twice??
Check Out HelloWorldConfig file. You've declared 2 beans of type SpellChecker:
#Bean(name="a")
public SpellChecker spellChecker(){
return new SpellChecker();
}
#Bean(name="b")
public SpellChecker spellChecker1(){
return new SpellChecker();
}
Both beans are created by spring, although only one bean is injected into the TextEditor.
In spring its perfectly fine to have more than one bean of the same type or beans that implement the same interface (think about listeners - there can be many of them) - so spring container will create them all during the application start.
If you want to inject one of those beans however into another bean (like TextEditor in your case), spring won't have a clue which one to inject, that's why you they've added a "qualifier" feature.
Another note, you've by mistake put a #Component annotation on the configuration class, instead you should use #Configuration annotation to specify that this class contains a series of beans definitions (that you indeed declare with #Bean annotation). Although the "configuration" is also a component (managed by spring) - spring still treats it in a significantly different way than regular beans.
And yet another note: although its not directly related to your question, it seems like you're mixing 2 styles of configurations in the code snippet you've provided: the style with #Qualifier/#Autowired (this way was added in spring 2.5 if I'm not mistaken) and the style of java configurations: #Configuration class with #Bean-s in it.
You can avoid using autowire altogether and inject the dependencies via constructor called from java config like this:
#Configuration
public class HelloWorldConfig {
#Bean
public HelloWorld helloWorld(){
return new HelloWorld();
}
#Bean
public TextEditor textEditor(#Qualifier("a") SpellChecker spellChecker){ // note the dependency here
return new TextEditor(spellChecker);
}
#Bean(name="a")
public SpellChecker spellChecker(){
return new SpellChecker();
}
#Bean(name="b")
public SpellChecker spellChecker1(){
return new SpellChecker();
}
}
// the TextEditor Class should have a constructor with one argument:
public class TextEditor {
private final SpellChecker spellChecker;
public TextEditor(SpellChecker spellChecker) {
this.spellChecker = spellChecker;
}
...
}
// or if you use lombok library:
#AllArgsConstructor
public class TextEditor {
private final SpellChecker spellChecker;
...
}
Now note, that your "business classes" are not even aware of spring all the "resolution" (usage of qualifier and injection rules) is done in spring configuration which is a special class anyway.
I have a certain type of class that can provide data and a registry where the different data providers are registered. I am looking for an elegant way to implement this in spring boot.
My current implementation looks like this (code is shortened for brevity):
public interface DataProvider{
Data getSomeData();
}
public class Registry{
public register(DataProvider provider){
//add to internal list
};
public List<DataProvider> getProviders(){
//return providers
}
public Data someAggregatedOperation(){ ... }
}
public class Provider1 implements DataProvider { ... }
public class Provider2 implements DataProvider { ... }
Now for the wiring part, and this is the part I want to change to something more elegant:
#Configuration
public class MyAppConfiguration{
#Bean
public Registry providerRegistry(){
Registry reg = new Registry();
reg.register(new Provider1());
reg.register(new Provider2());
return reg;
}
}
Then I can inject the registry into other classes that need to operate on the services.
I know that DI is for providing different implementation for a single type but one at a time. So DI most probably is not the right tool, my question is more about spring if there's a good way I don't know to achieve this.
As example Annotate them with a Qualifier and then resolve all Beans with that qualifier in the registry.
The way I would not want to take is using a custom Annotation and then resolving all the classes via reflection, instantiate them and put them in the registry. But at the moment it's the only way I can see so I don't have to modify the config and handwire the services.
If you want all of them to be autowired, you can just autowire a list of your interface implementations.
#Bean
public class Provider1 implements DataProvider { ... }
#Bean
public class Provider2 implements DataProvider { ... }
#Bean
public class Registry{
#Autowired
private List<DataProvider> providers;
public List<DataProvider> getProviders(){
//return providers
}
public Data someAggregatedOperation(){ ... }
}
In case you want to keep using a configuration class you could do something like:
#Bean
public class Provider1 implements DataProvider { ... }
#Bean
public class Provider2 implements DataProvider { ... }
public class Registry{
private List<DataProvider> providers;
public Registry(final List<DataProvider> providers) {
this.providers = providers;
}
public List<DataProvider> getProviders(){
//return providers
}
public Data someAggregatedOperation(){ ... }
}
#Configuration
public class MyAppConfiguration{
#Bean
#Autowired
public Registry providerRegistry(final List<DataProvider> providers){
return new Registry(providers);
}
}
I have one interface and two implementations for this interface
Interface definition:
public interface DoSomething {}
Two implementations:
public ImplementationOne implements DoSomething{}
public ImplementationTwo implements DoSomething{}
Then inside another class, I want to get a different implementaion (either ImplementationOne or ImplementationTwo) based on the condition, how can I do that using Spring?
Something like..
Public ServiceManager {
Private DoSomething doSomething = null;
Public void do() {
If (condition1) {
doSomething = new ImplementationOne();
} else {
doSomething = new ImplementationTwo();
}
}
}
You should definitely auto wire ApplicationContext type using #Autowire annotation. Then if you did it like this:
#Autowire
ApplicationContext context
Then you should get your desired bean like this:
context.getBean(yourDesiredType.class)
Like that you can get any bean you want to be placed under any matching type according to your example.
Another option to consider is have a configuration bean - for example -
#Configuration
public class EntityRepositoryConfiguration {
private Map<Entity, EntityRepository> entityEntityRepositoryMap = new HashMap<>();
protected EntityRepositoryConfiguration() {
entityEntityRepositoryMap.put(Entity.Book, new BookRepository());
}
#Bean
public EntityRepository getByEntityType(Entity entity) {
return entityEntityRepositoryMap.get(entity);
}
}
And then inject the configuration bean to your other beans and use the getEntityType method (for example) to get beans injected.