Is it possible to determine which class wants do inject my bean using Spring Context? I'm using the Java only configuration for my beans.
Let's say I've got this bean:
#Bean
#Scope("prototype")
public Helper helper() {
return new Helper();
}
Now I want to know in which class this instance will be injected in to inject a special instance meant for this class.
I want to do something like this, example pseudo code:
#Bean
#Scope("prototype")
public Helper helper(Class injectInto) {
if (injectInto == SomeClass.class) {
return new Helper("Only for SomeClass!");
}
return new Helper();
}
The beans should be injected as always, for example:
#Autowired
private Helper helper;
Use the #Qualifier and #Bean(name="") annotations for this purpose. There are many online resources for how to use it.
#Bean(name="normal")
#Scope("prototype")
public Helper helper(Class injectInto) {
return new Helper();
}
#Bean(name="special")
#Scope("prototype")
public Helper helper(Class injectInto) {
return new Helper("Only for SomeClass!");
}
Autowire in SomeClass:
#Autowired
#Qualifier(value = "special")
private Helper helper;
Related
I am new to spring framework. I have to use spring boot and have a rest controller as below :-
#RestController
public class StatisticsController {
private TransactionCache transactionCache;
public StatisticsController(TransactionCache transactionCache) {
this.transactionCache = transactionCache;
}
#PostMapping("/tick")
public ResponseEntity<Object> addInstrumentTransaction(#Valid #RequestBody InstrumentTransaction instrumentTransaction) {
transactionCache.addTransaction(instrumentTransaction);
return new ResponseEntity<>(HttpStatus.CREATED);
}
and I have a class which needs to be singleton :-
#Component
public class TransactionStatisticsCacheImpl implements TransactionCache {
private static TransactionStatisticsCacheImpl instance;
public static TransactionStatisticsCacheImpl getInstance(){
if(Objects.isNull(instance)){
synchronized (TransactionStatisticsCacheImpl.class) {
if(Objects.isNull(instance)){
instance = new TransactionStatisticsCacheImpl();
}
}
}
return instance;
}
private TransactionStatisticsCacheImpl() {}
I want to know the correct way to call this singleton class in my rest controller. I know that by default the scope of a bean in spring is singleton. Is this the correct way to call the singleton class in rest controller?
#RestController
public class StatisticsController {
private TransactionCache transactionCache;
public StatisticsController(TransactionCache transactionCache) {
this.transactionCache = transactionCache;
}
#PostMapping("/tick")
public ResponseEntity<Object> addInstrumentTransaction(#Valid #RequestBody InstrumentTransaction instrumentTransaction) {
transactionCache.addTransaction(instrumentTransaction);
return new ResponseEntity<>(HttpStatus.CREATED);
}
or
We need to call it using the getInstance() method? Also do we need to explicitly have the getInstance method in the TransactionStatisticsCacheImpl class?
One of the major advantages of container injection is that you can get the benefits of singleton semantics without all the serious problems of "hard" singletons (such as difficulty testing). Get rid of the getInstance manual business and let Spring take care of ensuring that a single instance is created and used for the context.
Just for clarification: By default, the spring IOC container will create only one instance per bean definition, unless if you specified otherwise using the #Scope stereotype. But if you create an instance using getInstance() the bean pre-processors and post-processors will not work correctly on that bean definition. And also you can use the #Autowired stereotype to inject a bean definition as needed and if you have different implementations for the same definition you can use the #Qualifier stereotype to specify the implementation that you need to inject, alternatively, you can use the constructor injection to inject your bean definition as needed without auto wiring as mentioned here Spring #Autowire on Properties vs Constructor
I would stick to the answers above. However, if you want to preserve further instantiation of the class in your code (or you want to keep your specific implementation of singleton), you can do it with getInstance().
Firstly, get rid of #Component annotation in your class:
// #Component
public class TransactionStatisticsCacheImpl implements TransactionCache {
private static TransactionStatisticsCacheImpl instance;
public static TransactionStatisticsCacheImpl getInstance(){
if(Objects.isNull(instance)){
synchronized (TransactionStatisticsCacheImpl.class) {
if(Objects.isNull(instance)){
instance = new TransactionStatisticsCacheImpl();
}
}
}
return instance;
}
private TransactionStatisticsCacheImpl() {}
}
Then, you may instantiate your singleton #Bean by defining #Configuration class - this way your bean would get managed by spring container.
#Configuration
public class SingletonConfiguration {
#Bean
public TransactionCache transactionCache() {
return TransactionCacheImpl.getInstance();
}
}
Eventually, you can have your singleton injected in your RestController using #Autowired.
#RestController
public class StatisticsController {
private TransactionCache transactionCache;
#Autowired
public StatisticsController(TransactionCache transactionCache) {
this.transactionCache = transactionCache;
}
#PostMapping("/tick")
public ResponseEntity<Object> addInstrumentTransaction(#Valid #RequestBody InstrumentTransaction instrumentTransaction) {
transactionCache.addTransaction(instrumentTransaction);
return new ResponseEntity<>(HttpStatus.CREATED);
}
}
Why can't I use #Autowired in this case?
#SpringBootApplication
public class Application {
#Autowired
BookingService bookingService;
public static void main(String[] args) {
bookingService.book("Alice", "Bob", "Carol");
}
}
but can use #Bean
#SpringBootApplication
public class Application {
#Bean
BookingService bookingService() {
return new BookingService();
}
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
BookingService bookingService = ctx.getBean(BookingService.class);
bookingService.book("Alice", "Bob", "Carol");
}
}
Aren't the two ways to generate BookingService the same thing?
#Bean and #Autowired do two very different things. The other answers here explain in a little more detail, but at a simpler level:
#Bean tells Spring 'here is an instance of this class, please keep hold of it and give it back to me when I ask'.
#Autowired says 'please give me an instance of this class, for example, one that I created with an #Bean annotation earlier'.
Does that make sense? In your first example, you're asking Spring to give you an instance of BookingService, but you're never creating one, so Spring has nothing to give you. In your second example, you're creating a new instance of BookingService, telling Spring about it, and then, in the main() method, asking for it back.
If you wanted, you could remove the two additional lines from the second main() method, and combine your two examples as below:
#SpringBootApplication
public class Application {
#Autowired
BookingService bookingService;
#Bean
BookingService bookingService() {
return new BookingService();
}
public static void main(String[] args) {
bookingService.book("Alice", "Bob", "Carol");
}
}
In this case, the #Bean annotation gives Spring the BookingService, and the #Autowired makes use of it.
This would be a slightly pointless example, as you're using it all in the same class, but it becomes useful if you have the #Bean defined in one class, and the #Autowired in a different one.
#Bean
BookingService bookingService() {
return new BookingService();
}
Annotating #Bean only registers the service as a bean(kind of an Object) in the spring application context. In simple words, it is just registration and nothing else.
#Autowired
BookingService bookingService;
Annotating a variable with #Autowired injects a BookingService bean(i.e Object) from Spring Application Context.
(i.e) The registered object with #Bean annotation will be injected to the variable annotated with #Autowired.
Hope this clears your doubt!
great answer by #DaveyDaveDave
In the example instead of
#Bean
BookingService bookingService() {
return new BookingService();
}
You can use #Service annotation on BookingService class
Contrary to what the highest voted answer here claims, they are NOT two very different things. #Bean and #Autowired and interchangeable in most cases.
Suppose you have a #Bean method that returns an instance of a Car. You can literally get rid of that bean method and add #Component on the Car class and then autowire it.
And vice versa. Whatever class you have instantiated using #Autowired, you can instantiate it inside a class with #Configuration annotation using #Bean on the method.
Places where you will use #Bean instead of #Autowired
1>You do not have access to change the class to add #Component annotation, hence you cannot autowire it.
2>You want to customize the instantiation of the class.
For example if you are instantiating a Resilience4J Circuit breaker class, if you do it inside a method with #Bean, you have the option of setting all the config using code like this
#Bean
public CircuitBreaker fooCircuitBreaker() {
CircuitBreakerConfig.Builder builder = CircuitBreakerConfig.custom().
slidingWindowSize(xxx).
failureRateThreshold(xxx).
waitDurationInOpenState(xxx)).
ignoreException(e -> {
if (e instanceof HttpStatusCodeException) {
HttpStatusCodeException httpStatusCodeException = (HttpStatusCodeException) e;
if (httpStatusCodeException.getStatusCode().is4xxClientError()) {
return true;
}
}
return false;
});
circuitBreakerRegistry.addConfiguration(xxx, builder.build());
return circuitBreakerRegistry.circuitBreaker(xxx, xxx);
}
Here's good article about #Autowired annotation: http://www.baeldung.com/spring-autowire
The #Autowired annotation can instantiate your injectables by defining #ComponentScan("namespace.with.your.components.for.inject") on config class
#Configuration
#ComponentScan("com.baeldung.autowire.sample")
public class AppConfig {}
All components must be marked by #Component annotation. It replaces the #Bean annotation.
#Bean is just for the metadata definition to create the bean(equivalent to tag). #Autowired is to inject the dependancy into a bean(equivalent to ref XML tag/attribute).
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
I have a java interface say ITest implemented by two classes Class1 and Class2. Now I have a factory class which I use to decide which implementation to return. like
if(something)
return new Class1()
else
return new Class2()
Problem is that I have autowired field in Class1 which doesn't get instantiated,, but the same autowiring works in other classes which were instantiated via autowiring.
Here is code for Class1
#Componene
public Class1 implements ITest{
#Autowired
private SomeClass obj;
}
Not sure how to get around this problem. As autowiring for SomeClass works fine in Other classes.
Inject applicationContext in your factory class and use it for bean creation:
#Autowired private ApplicationContext applicationContext;
......
......
if(something){
return applicationContext.getBean("com.xyz.Class1");
}
......
......
OR you can use #Configurable on top of Class1 and Class2. This needs AspectJ weaving to be enabled. Spring will then magically create beans when you use new.
It strongly depends of what exactly do you need, but you can:
Define the object returned by factory as prototype-scope and inject it to singleton, for more details look at: https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-scopes-sing-prot-interaction
Then whole magic is done by Spring
If you just want to switch between two different stateless implementations you can inject both of them to factory and return an existing bean
#Compoment class Factory {
#Autowired
Class1 class1Instance;
#Autowired
Class2 classInstance;
...
if(something)
return class1Instance;
else
return class2Instance;
...
}
}
But please make sure that both injected classes have no state.
Make factory managed by Spring, both classes not-managed by Spring and inject dependencies manually:
public Class1 implements ITest{
private SomeClass obj;
public Class1(SomeClass obj) {
this.obj=obj;}
}
and in factory:
#Autowired
private SomeClass obj;
...
if(something)
return new Class1(obj);
else
return new Class2(obj);
At first glance looks strange, by that way you can e.g. separate domain and application/infrastructure parts.
You could use your Main Configuration class which is annotated with #SpringBootApplication or #Configuration.
Example:
#SpringBootApplication
public class YourApp {
public static void main(String[] args) {
SpringApplication.run(YourApp.class, args);
}
#Autowired
private CsvBeanRepository repo;
#Bean
public InterfaceSome some() {
if(something) {
return new Some(repo);
} else {
return new Some2(repo);
}
}
}
inside a #SpringBootApplication class or a #Configuration class you can #Autowire your classes normally and use them as parameters for your factory.
I would suggest to use #value annotation for this scenario.
Example
MyClass{
Object getObjectFromFactory()
{
if(something)
return new Class1()
else
return new Class2()
}
}
then you can use it like below
#Value("#{MyClass.getObjectFromFactory}")
private Object myObject;
As far as I know spring provides some ways to inject beans into non-managed classes.
It can be done explicitly with AutowireCapableBeanFactory. (How to inject dependencies into a self-instantiated object in Spring?)
But I've faced strange (IMHO) behavior, when spring performs such injection automatically.
Here is an example with spring batch,
Configuration:
#SpringBootConfiguration
public class ProcessorJobConfig {
//.....
#Bean(name = "pullRestTemplate")
public RestTemplate createPullRestTemplate() {
RestTemplate restTemplate = restTemplateBuilder.build();
return restTemplate;
}
#Bean(name = "step")
public Step step(#Autowired ItemReader<Measurement> itemReader,
#Autowired ItemProcessor<Measurement, Event> itemProcessor,
#Autowired ItemWriter<Event> itemWriter) {
return stepBuilderFactory.get("step")
.<Measurement, Event>chunk(Integer.MAX_VALUE)
.reader(itemReader)
.processor(itemProcessor)
.writer(itemWriter)
.build();
}
#Bean(name = "restProcessorJob")
public Job job(#Qualifier("step") Step step) throws Exception {
return jobBuilderFactory.get("restProcessorJob")
.start(step)
.build();
}
#Bean
public ItemReader<Measurement> itemReader() {
RestMeasureReader restMeasureReader = new RestMeasureReader(); // Use new() explicitly
return restMeasureReader;
}
//.....
}
Reader:
public class RestMeasureReader implements ItemReader<Measurement> {
private static final Logger LOGGER = LoggerFactory.getLogger(RestMeasureReader.class);
/**
* NOTE: This field will be injected automatically by spring, even we are using new() to create instance of this class.
*/
#Autowired
#Qualifier("pullRestTemplate")
private RestTemplate restTemplate;
#Override
public Measurement read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
// do some stuff
}
}
And application itself
#EnableBatchProcessing
#EnableTask
#SpringBootApplication
public class TestAutowiredTaskApplication {
public static void main(String[] args) {
SpringApplication.run(TestAutowiredTaskApplication.class, args);
}
}
Even I use explicit new() to instantiate RestMeasureReader, its RestTemplate field will be injected afterwards.
Is it normal behavior? I do not expect spring to automatically inject fields when creating object with new().
If you are talking about using new inside of your #Configuration class, then yes it is normal behavior. This is you Spring java configs. So it's is Spring managed context. You are not going to call itemReader() in your code explicitly.
So, when you are going to do this:
#Autowired
private ItemReader<Measurement> iterReader;
you will get instance of your RestMeasureReader from Spring's IoC.
But if you will try to do explicitly call new RestMesureReader() inside of your code, you will get a new instance of RestMesureReader not a Spring Proxy with injected #Autowired fields.
Try to remove #Bean from your itemReader() method declaration and won't event be able to autowire RestMesureReader.
So basically #Configuration classes are just a Spring configuration, not a real java code. Even though you call new Spring will still return you a proxy class.
For more information check this guide.
Spring processes beans returned by methods that are annotated with #Bean
This allows you to use autowiring or livecycle callbacks when using Java configuration.
A more minimalistic example:
#Configuration
public class MyConfiguration {
#Bean
public A a() {
return new A();
}
static class A {
#Autowired
private B b;
#PostConstruct
public void onPostConstruct() {
System.out.println("postConstruct: " + b);
}
}
#Component
static class B {
}
}
Here, even if the bean named a is created manually, Spring will inject dependencies (b) and call #PostConstruct callbacks.