Provide single #Bean that can be used to inject in multiple interfaces - java

Consider the following piece of code
public interface Iface1 { }
public interface Iface2 { }
public class A implements Iface1, Iface2 {
}
#Configuration
public class AutoConfig {
#Bean
Iface1 provideIface1Impl() {
return new A(); // instance no 1234
}
#Bean
#ConditionalOnBean(A.class)
#Autowired
Iface2 provideIface2Impl(A aImpl) {
return aImpl;
}
}
I would like the second #Bean method to be autowired with the instance from the first one (1234) and I'd like the second #Bean method to return the same instance, so that I can use the same instance for clients of Iface1 and Iface2.
Current problem is that spring doesn't run the second #Bean because there is no #Bean of type A.class - the created bean is considered as Iface1 even though it is of type A.

Just define bean A. When injecting IFace1 and Iface2 they will automatically resolve to A (if A is the only implementation of course).
#Bean
public A a() {
return new A();
}

I think you should try to define only one #Bean. It will create a singleton:
#Bean
public A a() {
return new A();
}
Then just use the name of this bean in #Qualifier annotation:
#Autowired
#Qualifier("a")
private Iface1 iface1;
#Autowired
#Qualifier("a")
private Iface2 iface2;

Additionally to what others have answered, I'd like to cover that part of the question that touches bean's dependencies.
To inject a dependency to a #Bean-annotated method, there are two ways:
Call another #Bean-method directly
Add parameter to the method
Examples of both:
#Configuration
public class AppConfig {
#Bean
public Foo foo() {
return new Foo();
}
#Bean
public Bar bar() {
return new Bar(foo());
}
#Bean
public Baz baz(Foo foo) {
return new Baz(foo);
}
}
So your provideIface2Impl could look like this:
#Bean
Iface2 provideIface2Impl(A aImpl) {
return aImpl;
}
// or...
#Bean
Iface2 provideIface2Impl() {
return (Iface2)provideIface1Impl();
}
But don't use it this way, it will lead to subtle bugs like double-proxying or "No unique bean of type" error, etc. Prefer what Gorazd suggested.

Related

Spring beans initialization through method

I have a little question about bean creation that bothers me a lot.
For example I have classes
public class A {
B b;
public A(B b) {
this.b = b;
}
}
public class B {}
And I want to make beans for them like this:
#Configuration
public class Config {
#Bean
public B beanB() {
return new B();
}
//version 1
#Bean
public A beanA() {
return new A(beanB())
}
//version 2
#Bean
public A beanA(B beanB) {
return new A(beanB)
}
}
So, my question is what is the right way to create bean A?
I think that the right one is version 2, because in the version 1 I think beanB can be invoked 2 times: on the creation of beanA and when spring will create it for it's context. But I can't find anything that will prove my opinion.
The "right" way is to do it the way the documentation, i.e. the javadoc of #Bean, shows it:
#Bean Methods in #Configuration Classes
Typically, #Bean methods are declared within #Configuration classes. In this case, bean methods may reference other #Bean methods in the same class by calling them directly. This ensures that references between beans are strongly typed and navigable. Such so-called 'inter-bean references' are guaranteed to respect scoping and AOP semantics, just like getBean() lookups would. These are the semantics known from the original 'Spring JavaConfig' project which require CGLIB subclassing of each such configuration class at runtime. As a consequence, #Configuration classes and their factory methods must not be marked as final or private in this mode. For example:
#Configuration
public class AppConfig {
#Bean
public FooService fooService() {
return new FooService(fooRepository());
}
#Bean
public FooRepository fooRepository() {
return new JdbcFooRepository(dataSource());
}
// ...
}
That means version 1 in the question code.
Spring dynamically subclasses AppConfig, so only one instance is created no matter how many times the method is called, e.g. functionally something like this:
public class $dynamic$ extends AppConfig {
private FooRepository cachedFooRepository;
#Override
public FooRepository fooRepository() {
if (this.cachedFooRepository == null)
this.cachedFooRepository = super.fooRepository();
return cachedFooRepository;
}
}

Spring inject a bean into another bean

I am trying to inject a bean into another bean that uses it. How can I do this?
public class MySpringConfig{
#Bean
public MyObject getMyObject() {
//.....
return MyObjectInstance;
}
#Bean
public SomeObject getSomeObject(MyObject myObject) {
//.....
return SomeObjectInstance;
}
}
I think you can do this with this way, this is working in my project.
#Configuration
public class AppConfig {
#Bean
public Bean1 foo(#Qualifier("bean2") Bean2 bean2) {
return new Bean1(bean2);
}
}
i think that might work!
#Configuration
public class AppConfig {
#Bean
public Bean2 bean2() {
return new Bean2();
}
#Bean
#DependsOn({"bean2"})
public Bean1 foo(#Autowired Bean2 bean2) {
return new Bean1(bean2); // or your can write new Bean1(bean2());
}
}
Parameters don't work exactly in the same way in #Bean and #Component.
For a class annotated with #Component, specifying them is required for the autowired constructor but in a #Bean declaration you don't need to provide a parameter to specify the MyObject dependency to use (while it will work) if that is accessible in the current class, which is your case.
So you want to inject directly the bean by invoking getMyObject() in the #Bean definition.
For example to pass it a constructor arg :
#Bean
public SomeObject getSomeObject() {
//....
// you injected MyObject in the current bean to create
SomeObject object = new SomeObject(getMyObject());
//...
return SomeObjectInstance;
}
And don't forget to annotate the class with #Configuration to make it considered by Spring.

Multiple beans with the same implementation in Spring boot

I have a situation where I'm using one possible implementation for a particular bean, and it looks like this:
#Configuration
public class MyConfig {
#Autowired
private ApplicationContext context;
#Bean
public SomeInterface someInterface() {
if (this.context.getEnvironment().getProperty("implementation") != null) {
return new ImplementationOne();
} else {
return new ImplementationTwo();
}
}
}
This worked great so far, until a new requirement came in, to use an additional interface which for the moment only ImplementationTwo provides implementation, and it wouldn't make sense to use it with ImplementationOne:
#Bean
public SomeOtherInterface someOtherInterface() {
return new ImplementationTwo();
}
I guess this would work, but I'm wondering if this really make sense because in one scenario I could have both beans basically instantiating the same object. Does that make sense ? Is there maybe a better way to achieve the same thing?
I believe, if you have multiple implementations of a single interface, then you should go about specific bean names as below.
Here implementation1 will be the primary bean created and injected where ever we have the Interface1 dependency.
#Primary
#Bean
public Interface1 implementation1() {
return new Implementation2();
}
#Bean
public Interface1 implementation2() {
return new Implementation2();
}
If we need implementation2 injected we need #Resource annotation as below.
#Resource(name="implementation2")
Interface1 implementation2;
You can always define in each place where you're using particular bean a qualifier:
#Bean
public SomeInterface beanName1(){ //impl }
#Bean
public SomeInterface beanName2(){ //impl }
Usage:
#Qualifier("beanName1") SomeInterface interface;
Also 'd need to allow multiple beans in your application.yml/properties file:
spring.main.allow-bean-definition-overriding=true

Set common variable in Spring Configuration

I have a Java Spring Configuration class like this. I want to set a variable that several of my beans depend on, turn it into a bean, and use it as a dependency. How can I make the setVariable() method happen first? I'm converting my code from Guice, where this variable was being set in the overridden 'Configuration' method. Does Spring have something like that?
#Configuration
class SpringConfiguration{
String variable;
public void setVariable(){
variable = System.getenv("whatever")
}
#Bean
public void variable(){
return variable;
}
#Bean
public void myService(){
return new MyService(variable);
}
#Bean
public void myService2(){
return new MyService2(variable);
}
You can do something like this :
#Configuration
class SpringConfiguration {
#Bean(name="variable")
public String geVariable() {
return System.getenv("whatever");
}
#Bean
#DependsOn("variable")
public MyService getMyService() {
return new MyService(geVariable());
}
#Bean
#DependsOn("variable")
public MyService2 getMyService2() {
return new MyService2(geVariable());
}
}
Like that you can insure that variable will be initialized before service1 and service2, note that DependsOn in this case is just for clarification purposes.

Using prototype beans defined in a different java-based Spring config file

Assume we have two spring config files: ConfigA.java and ConfigB.java.
Here's how ConfigA.java may look like:
#Configuration
class ConfigA {
#Scope("prototype")
#Bean public Foo fooPrototype() {
return new Foo(params);
}
}
And now I want to inject a few instances of Foo to a number of singleton-scoped beans declared in ConfigB.java:
#Configuration
#Import(ConfigA.class)
class ConfigB {
#Bean public Bar bar() {
return new Bar(*** how to inject Foo instance here? ***);
}
#Bean public Buzz buzz() {
return new Buzz(*** how to inject Foo instance here? ***);
}
}
If I had a single configuration file, I would simply replace the blocks enclosed in asterisks with fooPrototype().
But, how to inject different Foo instances to bar() and buzz() beans provided fooPrototype() is declared in a different configuration file?
This looks similar to the example in the Spring documentation ยง5.12.5 Composing Java-based configurations.
This same page gives a solution: You can autowire the configuration beans.
#Configuration
#Import(ConfigA.class)
class ConfigB {
#Autowired ConfigA configA;
#Bean public Bar bar() {
return new Bar(configA.fooPrototype());
}
#Bean public Buzz buzz() {
return new Buzz(configA.fooPrototype());
}
}
Can't you just pass fooPrototype as a method arg? E.g.:
#Bean public Bar bar(Foo fooPrototype) {
return new Bar(fooPrototype);
}
#Bean public Buzz buzz(Foo fooPrototype) {
return new Buzz(fooPrototype);
}

Categories