Refer a spring bean from the inherited context in Java config - spring

I am using the Java spring configuration using annotations.
If I have a configuration class A which is like
#Configuration
public class A{
#Bean(name="hello")
public hello(){
return new Hello();
}
#Bean(name="greeting")
public greeting(){
return new Greeting(hello());
}
So here the greeting bean gets hello as a dependency.
How would I do this if I were to declare the greeting bean in a different configuration class say B and them import the configuration from A
#Configuration
public class A{
#Bean(name="hello")
public hello(){
return new Hello();
}
}
#Configuration
#Import(A.class)
public class B{
#Bean(name="greeting")
public greeting(){
// what do i write here ?
// so that it is equivalent to
// return new Greeting(hello());
}

Below should be all you need.
Notice that I have injected your Hello bean as a method parameter. Spring DI shall take care of the rest.
#Configuration
#Import(A.class)
public class B{
#Bean(name="greeting")
public greeting(Hello hello){
return new Greeting(hello);
}

Answering my own question:
Should be able to make use of #Autowired annotation in B.
#Configuration
#Import(A.class)
public class B{
#Autowired
Hello hello;
#Bean(name="greeting")
public greeting(){
return new Greeting(hello);
}

Related

Spring #Bean - creation of Spring Bean depends on service class name

I use Spring 4.2.8 and I do have the service class below. If this class has the name ScheduleEmailCreateAndSendServiceImpl than everything works fine (method generalEmailMessage is invoked at start time in order to create the Spring Bean)
If I rename this class to EmailCreateAndSendServiceImpl than method generalEmailMessage will not be invoked at start time - does anyone know why?
#Service("emailCreateAndSendService")
public class ScheduleEmailCreateAndSendServiceImpl extends AbstractService
implements EmailService {
protected EmailMessage generalMessage;
#Override
public void createAndSendMessage(String receiver, boolean emailActive, Object[] values) throws BusinessException {
// create and send email
}
#Bean
public EmailMessage generalEmailMessage() {
this.generalMessage = new GeneralEmailInformationMessage();
return generalMessage;
}
}
[EDIT]
with this code it is the same
#Configuration
public #Data class ScheduleGeneralEmailConfiguration {
protected EmailMessage generalMessage;
public ScheduleGeneralEmailConfiguration() {
System.out.println("asdf");
}
#Bean
public EmailMessage generalEmailMessage() {
this.generalMessage = new GeneralEmailInformationMessage();
return generalMessage;
}
}
#Bean annotated methods should be in #Configuration annotated class.
You can also put the #Bean annotated methods in the main class of the Spring Boot application annotated with #SpringBootApplication which encapsulates #Configuration, #EnableAutoConfiguration, and #ComponentScan annotations.
Make sure your #Configuration annotated class is placed in the same package or sub package of the Spring Boot Application class

#Bean and optional #Autowire

My #Configuration defines a couple of beans - A & B
#Configuration
public class MyConfiguration {
#Bean
public A supplyA() {
return new A(...);
}
#Bean
public B supplyB() {
return new B(...);
}
}
I was expecting that I should #Autowire A and B where they are needed, like so:
#Controller
public MyController {
#Autowire
public MyController(A a, B b) {
}
}
But it does work fine without the #Autowire on the constructor. What gives? (I'm on Spring 5 if that matters)
I think what you're trying is constructor injection, check https://docs.spring.io/spring/docs/4.3.26.RELEASE/spring-framework-reference/htmlsingle/#beans-constructor-injection
#Autowire, normally used for set injection.
Please understand the difference, before you make a change

Spring boot defining configuration beans per user

I am using Spring boot. I have some question regarding the spring boot beans.
But I have doubt
I use bean which are default scope that is singleton. So they will have only one instance per application.
#Configuration
public class ...{
#Bean
public void method() {}
}
And
Now i use bean which scope is prototype. So they will have each instance per request.
#Configuration
public class ...{
#Bean
#Scope("prototype")
public void method() {}
}
But
I want single instance per user..? all request use single instance per user.
#Configuration
class Abc {
#Bean
#Scope("session")
public YourBean getYourBean() {
return new YourBean();
}
}
You will need to define one singleton bean with a property using prototype bean:(xml example)
With #bean definition:
#Component
#Scope("singleton")
public class SingletonBean {
// ..
#Autowired
private PrototypeBean prototypeBean;
//..
}
#Component
#Scope("prototype")
public class PrototypeBean {
//.......
}
Example: https://www.baeldung.com/spring-inject-prototype-bean-into-singleton

how to avoid using context.getbean in spring

There have been several arguments around not using ApplicationContext.getBean() to get a bean reference, of which most are based on logic that it violates the principles of Inversion of control.
Is there a way to get reference to prototype scoped bean without calling context.getBean() ?
Consider to use Spring Boot!
Than you can do something like this...
Runner:
#SpringBootApplication
public class Runner{
public static void main(String[] args) {
SpringApplication.run(Runner.class, args);
}
}
Some Controller:
#Controller
public class MyController {
// Spring Boot injecting beans through #Autowired annotation
#Autowired
#Qualifier("CoolFeature") // Use Qualifier annotation to mark a class, if for example
// you have more than one concreate class with differant implementations of some interface.
private CoolFeature myFeature;
public void testFeature(){
myFeature.doStuff();
}
}
Some cool feature:
#Component("CoolFeature") // To identify with Qualifier
public class CoolFeature{
#Autowired
private SomeOtherBean utilityBean;
public void doStuff(){
// use utilityBean in some way
}
}
No XML files to handle.
We can still access context for manual configurations if needed.
Suggested reading:
Spring Boot Reference
Pro Spring Boot
This type of problem can be solved using method injection, which is described in more detail here: https://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-factory-method-injection
This is the most common approach to create prototype bean:
abstract class MyService {
void doSome() {
OtherService otherService = getOtherService();
}
abstract OtherService getOtherService();
}
#Configuration
class Config {
#Bean
public MyService myService() {
return new MyService() {
OtherService getOtherService() {
return otherService();
}
}
}
#Bean
#Scope("prototype")
public OtherService otherService() {
return new OtherService();
}
}

Inject a list of classes that extends an abstract class with Spring

Hy,
I have the next code:
public abstract class MyClass{
protected abstract void method1();
}
Classes that extend the first one:
#Component
public class MyClass1 extends MyClass{
.....
}
#Component
public class MyClass2 extends MyClass{
.....
}
My class where I try to inject list of classes that extends an abstract class
#Component
public class SpringClass{
#Autowired **//It doesnt work, nothing is inyected!**
List<MyClass> classes
}
My problem is it doesnt work, it doesnt inject the list of classes that extend MyClass in property classes. Why?
Thanks
You can remove #Autowired annotation for the instance variable and add it to the setter method. After doing this your spring class would be
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class SpringClass {
List<MyClass> classes;
#Autowired
public void setClasses(List<MyClass> classes) {
this.classes = classes;
}
}
Hope this helps.
#Component
public class SpringClass {
#Autowired
private Map<String, YourInterface> map;
}
String in map will be contain all classes name that implements the YourInterface as String.
if you want to get all instances - use map.values()
if you want to get specific instance - get it by class name.
in additional, you can customize the key by another recognize such as Enum.
in this case - you need to configure this as #Bean
as bellow :
#Configuration
public class CalculationHandlerConfig {
#Bean
public HashMap<OperatorTypeEnum, CalculatorService> CalculationHandlers(Map<String, CalculatorService> beansMap) {
HashMap<OperatorTypeEnum, CalculatorService> map = new HashMap<>();
for (CalculatorService bean : beansMap.values()) {
map.put(bean.getOperatorType(), bean);
}
return map;
}
}
It looks like it could be dependent on the version of Spring being used, however, you may also want to try using an interface that all the desired classes implement, and injecting the list referencing the interface.
In other words, instead of this..
List<AbstractOrConcreteBaseClass>
use...
List<Interface>

Resources