I've a Component as follows:
#Component
class A(){
private s;
public A(){}
public A(String s){this.s=s;}
}
Here is the other class Where I'm auto wiring the above class:
#Component
class B(){
#Autowire
private A a;
}
In the above autowiring, I need to use the parameterized constructor. How can I pass the constructor args?
You can't, at least not via #Autowired in B but there are other ways to do it:
Wire the parameter into A's constructor:
One constructor is annotated with #Autowired because:
As of Spring Framework 4.3, the #Autowired constructor is no longer
necessary if the target bean only defines one constructor. If several
constructors are available, at least one must be annotated to teach
the container which one it has to use.
#Component
class A(){
private s;
public A(){}
#Autowired
public A(#Value("${myval}") String s){this.s=s;}
}
Expose A as a #Bean
Straight from the docs:
#Configuration
public class AppConfig {
#Bean
public A a(#Value("${myval}") String s) {
return new A(s);
}
}
Construct A in B using an initialization callback
Docs
#Component
class B(){
private A a;
#Value("${myval}")
private String myval;
#PostConstruct
private void init()
{
a = new A(myval);
}
}
There is a concept of prototype bean which I think you require in your case. #Component will create a singleton bean and changing it in one place will change in all parent classes where this was injected.
You need to understand how to inject a prototype bean in singleton bean.
Follow this example
https://stackoverflow.com/a/25165971/949912
Just use setters instead of constructor.
If you want to create object by yourself with new keyword then this object will not be managed by container.
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);
}
}
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;
i am really confused with spring annotations.
where to use # Autowired, where class is # Bean or # Component,
i understand we cannot use
Example example=new Example("String");
in Spring
but how alone
#Autowired
Example example;
will solve the purpose?
what about Example Constructor ,how spring will provide String value to Example Constructor?
i went through one of the article but it does not make much sense to me.
it would be great if some one can give me just brief and simple explanation.
Spring doesn't say you can't do Example example = new Example("String"); That is still perfectly legal if Example does not need to be a singleton bean. Where #Autowired and #Bean come into play is when you want to instantiate a class as a singleton. In Spring, any bean you annotate with #Service, #Component or #Repository would get automatically registered as a singleton bean as long as your component scanning is setup correctly. The option of using #Bean allows you to define these singletons without annotating the classes explicitly. Instead you would create a class, annotate it with #Configuration and within that class, define one or more #Bean definitions.
So instead of
#Component
public class MyService {
public MyService() {}
}
You could have
public class MyService {
public MyService() {}
}
#Configuration
public class Application {
#Bean
public MyService myService() {
return new MyService();
}
#Autowired
#Bean
public MyOtherService myOtherService(MyService myService) {
return new MyOtherService();
}
}
The trade-off is having your beans defined in one place vs annotating individual classes. I typically use both depending on what I need.
You will first define a bean of type example:
<beans>
<bean name="example" class="Example">
<constructor-arg value="String">
</bean>
</beans>
or in Java code as:
#Bean
public Example example() {
return new Example("String");
}
Now when you use #Autowired the spring container will inject the bean created above into the parent bean.
Default constructor + #Component - Annotation is enough to get #Autowired work:
#Component
public class Example {
public Example(){
this.str = "string";
}
}
You should never instantiate a concrete implementation via #Bean declaration. Always do something like this:
public interface MyApiInterface{
void doSomeOperation();
}
#Component
public class MyApiV1 implements MyApiInterface {
public void doSomeOperation() {...}
}
And now you can use it in your code:
#Autowired
private MyApiInterface _api; // spring will AUTOmaticaly find the implementation
I have a scenario where autowired is null when called in the constructor of an abstract class like this :
public abstract class AbstractClass{
#Autowired
#Qualifier("proId")
protected Prop prop;
public AbstractClass(){
prop.getName();
The above throws NullException on deployment.
But the following works when the autowired property called after instantiating
public abstract class AbstractClass{
#Autowired
#Qualifier("proId")
protected Prop prop;
public void Init(){
prop.getName();
}
}
public class DefaultClass extends AbstractClass(){
...
#autowired
DefaultClass dc ;
...
dc.Init();
How can I get the first case to work ?
You can't. Injection can only happen after an object has been created (or during construction with constructor injection). In other words, when prop.getName() is called inside the abstract class constructor, the field is still null since Spring hasn't processed it.
Consider refactoring your code so that your abstract class has a constructor that accepts a Prop argument and use constructor injection
public AbstractClass(Prop prop) {
this.prop = prop;
prop.getName();
}
...
#Autowired
public DefaultClass(Prop prop) {
super(prop);
}
Do you know object creation life-cycle in Java?
Spring doesn't do any magic about that.
There are multiple phases when using Spring for creating beans
an object is instantiated using the constructor
dependencies are injected into bean (obviously except for constructor dependencies which are passed through the object in first phase)
objects #PostConstruct (or InitializingBean) methods are called.
Remember that before constructor there is no instance of your bean, so Spring can not wire anything in it!
I have an Interface with Component annotation and some classes that implemented it as follows:
#Component
public interface A {
}
public class B implements A {
}
public class C implements A {
}
Also, I have a class with an Autowired variable like this:
public class Collector {
#Autowired
private Collection<A> objects;
public Collection<A> getObjects() {
return objects;
}
}
My context file consists of these definitions:
<context:component-scan base-package="org.iust.ce.me"></context:component-scan>
<bean id="objectCollector" class="org.iust.ce.me.Collector" autowire="byType"/>
<bean id="b" class="org.iust.ce.me.B"></bean>
<bean id="c" class="org.iust.ce.me.C"></bean>
And in the main class, I have some codes as follows:
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
B b = (B) context.getBean("b");
C c = (C) context.getBean("c");
Collector objectCollector = (Collector) context.getBean("objectCollector");
for (A object : objectCollector.getObjects()) {
System.out.println(object);
}
Output:
org.iust.ce.me.B#1142196
org.iust.ce.me.C#a9255c
These codes work well, but for some reasons I’m not willing to use xml context file. Besides it, I prefer to create the objects with the new operator rather than using the getBean() method. Nevertheless, since the AutoWiring is really good idea in programming, I don’t want to lose it.
Now I have two questions!!
how can I AutoWire classes that implements the A Interface without using the xml context file?
Is it possible at all?
when I change the scope of a bean from singlton to
prototype as follows:
<bean id="b" class="org.iust.ce.me.B" scope="prototype"></bean>
and instantiate several beans of it, only the bean which was instantiated during creating context, is injected into AutoWired variable. Why?
Any help will be appreciated.
Not sure the version of Spring you are using. But currently you can use #Configuration to replace .xml. Take a look at #Configuration
Below is the code in documentation
#Configuration
public class ServiceConfig {
private #Autowired RepositoryConfig repositoryConfig;
public #Bean TransferService transferService() {
return new TransferServiceImpl(repositoryConfig.accountRepository());
}
}
#Configuration
public interface RepositoryConfig {
#Bean AccountRepository accountRepository();
}
#Configuration
public class DefaultRepositoryConfig implements RepositoryConfig {
public #Bean AccountRepository accountRepository() {
return new JdbcAccountRepository(...);
}
}
#Configuration
#Import({ServiceConfig.class, DefaultRepositoryConfig.class}) // import the concrete config!
public class SystemTestConfig {
public #Bean DataSource dataSource() { /* return DataSource */ }
}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
TransferService transferService = ctx.getBean(TransferService.class);
transferService.transfer(100.00, "A123", "C456");
}
Provided the classes to be managed have been correctly annotated, Spring can scan the application's files to get the information it needs without any xml or java configuration files at all.
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.scan("com.something.something.etc");
context.refresh();
...context.getBean("name_of_bean");
Note AnnotationConfigApplicationContext is instantiated without any arguments. context.scan("..."); takes a string that tells Spring where to look. i.e. packagescom.something.something.etc.one
com.comething.something.etc.twowill be scanned, and classes within those packages annotated with #Component, #Autowired, etc. will be instatiated and injected where needed.
This approach doesn't seem to be as well documented.
1- You need to write another class that will do the operation. write #Component to B and C class.
public static void main(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
InitClass initClass = (InitClass) context.getBean("initClass");
}
public class InitClass{
#Autowired
public B b;
#Autowired
public C c;
}
with this you will get B and C without using xml.
2- http://static.springsource.org/spring/docs/3.0.0.M3/reference/html/ch04s04.html Bean scopes are detailed mentioned here. If you want always a new object you should use prototype but creating a new one will be done in different classes. In the same class you should add a new reference.
like
public class InitClass{
#Autowired
public A a1;
#Autowired
public A a2;
}