how to Inject dependency in static method with spring? [duplicate] - java

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to make spring inject value into a static field
I have below code
public class CustomerService {
private static CustomerDAO customerDao;
public static void getAllCustomers()
{
customerDao.getAllCustomers();// here i want
}
public static CustomerDAO getCustomerDao() {
return customerDao;
}
public static void setCustomerDao(CustomerDAO customerDao) {
CustomerService.customerDao = customerDao;
}
}
now i am calling CustomerService.getAllCustomers() from my Action object where getAllCustomers
is class level method. I want customerDao to be injected by spring in class CustomerService
so that when i call getAllCustomers dependency is available ?
I am using spring decalarative dependency injection

Your design collides head-on with the basic premise of Spring IoC. A static method is nothing more than a singleton method, and the core point of the IoC container is to manage your singletons. You must redesign to use instance methods and fields.
The only way static methods get into the picture is as factory methods, when some complex logic is needed to contribute a singleton to the container.

Do not declare the customerDao field static. Then wire the customer dao into your service class like:
<bean id="customerDao" class="com.example.CustomerDao">
<!-- whatever config you may need here -->
</bean>
<bean id="customerService" class="com.example.CustomerSerivce">
<property name="" ref="customerDao"/>
</bean>

Related

Autowiring conflict in spring core with the xml configuration

Taking as reference the post Spring #Autowired and #Qualifier
We have this example to fix the autowiring conflict :
public interface Vehicle {
public void start();
public void stop();
}
There are two beans, Car and Bike implements Vehicle interface.
#Component(value="car")
public class Car implements Vehicle {
#Override
public void start() {
System.out.println("Car started");
}
#Override
public void stop() {
System.out.println("Car stopped");
}
}
#Component(value="bike")
public class Bike implements Vehicle {
#Override
public void start() {
System.out.println("Bike started");
}
#Override
public void stop() {
System.out.println("Bike stopped");
}
}
#Component
public class VehicleService {
#Autowired
#Qualifier("bike")
private Vehicle vehicle;
public void service() {
vehicle.start();
vehicle.stop();
}
}
That's a very good example to fix this problem.
But when I have the same problem but without those balises in the application context:
<context:component-scan></context:component-scan>
<context:annotation-config></context:annotation-config>
All the issues are solved by using the #Qualifier annotation, but in my case we don't use the balise that permit to use annotation.
The question is :
How can I fix this issue just using the configuration in application context, that's it, without using annotations?
I searched a lot and I found people talking about autowire attribute in the bean declaration <bean id="dao" class="package.IDao" autowire="byName"></bean> and I need more explanation about it.
How can I fix this issue just using the configuration in application
context?
You could use the qualifier tag like below (see https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/beans.html#beans-autowired-annotation-qualifiers)
<context:annotation-config/>
<beans>
<bean class="your_pkg_route.Vehicle">
<qualifier value="bike"/>
</bean>
</beans>
</context:annotation-config>
I found people talking about autowire attribute in the bean
declaration and I need more explanation about it
Using Annotation
#Autowired used on a bean declaration method injects the defined dependencies by (another) declared beans. Now, if your dependencies are in the same context of your application, you don't need to use the #Autowired annotation at all because Spring is able to figure them out by itself. So, if your dependencies are outside your applicatoin context then you can use it.
For example, take as reference the below code:
#Autowired
#Bean
public MyBean getMybean(Dependency1 depdency1, Dependency2 depdency2) {
return new MyBean(depdency1.getSomeStuff(), depdency2.getSomeOtherStuff());
}
Here, #Autowired will find an instance of Dependency1 and Dependency2 and will provide them for the creation of an instance of MyBean.
Using xml configuration
From Pro Spring 5... Spring supports five modes for autowiring.
byName: When using byName autowiring, Spring attempts to wire each property to a bean of the same name. So, if the target bean has a property named foo and a foo bean is defined in ApplicationContext, the foo bean is assigned to the foo property of the target.
byType: When using byType autowiring, Spring attempts to wire each of the
properties on the target bean by automatically using a bean of the same type in
ApplicationContext.
constructor: This functions just like byType wiring, except that it uses constructors rather than setters to perform the injection. Spring attempts to match the greatest numbers of arguments it can in the constructor. So, if your bean has two constructors, one that accepts a String and one that accepts String and an Integer, and you have both a String and an Integer bean in your ApplicationContext, Spring uses the two-argument constructor.
default: Spring will choose between the constructor and byType modes
automatically. If your bean has a default (no-arguments) constructor, Spring uses
byType; otherwise, it uses constructor.
no: This is the default
So, in your case you would need to do something like this (BUT, I would NOT recommend it. Why?, you would need to declare Vehicle class as a bean and a component which is not correct, see Spring: #Component versus #Bean. On the other hand I'm not sure if you could use it just declaring it as a bean):
// xml config
<context:annotation-config/>
<beans>
// use the primary tag here too! in order to say this the primary bean
// this only works when there are only two implementations of the same interface
<bean id="bike" primary="true" class="your_pkg_route.Bike"/>
<bean id="car" class="your_pkg_route.Car"/>
<bean autowire="byName" class="your_pkg_route.VehicleService"/>
<beans>
</context:annotation-config>
// VehicleService
#Component
public class VehicleService {
private Vehicle bike; // call attribute 'bike' so it is autowired by its name
public void service() {
//...
}
}
As you can see there is a lot of complications trying to do this using xml config, so I would recommend you to use the annotation option if possible.
Related posts:
Why do I not need #Autowired on #Bean methods in a Spring configuration class?
Difference between #Bean and #Autowired
PS: I have not tested any of the posted codes.
You can use #Primary instead of #Qualifier
#Primary
#Component(value="bike")
public class Bike implements Vehicle {
we use #Primary to give higher preference to a bean when there are multiple beans of the same type.
We can use #Primary directly on the beans
You can also set primary attribute in XML:
property has primary attribute:
<bean primary="true|false"/>
If a #Primary-annotated class is declared via XML, #Primary annotation metadata is ignored, and is respected instead.

How to create bean using #Bean in spring boot for abstract class

I have requirement to migrate old style spring project to Spring boot.
Assume below code snippet I have to migrate to Spring boot style.
Here my ask , how to convert below abstract bean to #Bean ?
<bean id="sample" class="com.test.core.common.AbstractClass" abstract="true">
<property name="sample1" ref="sample1" />
<property name="sample2" ref="sample2" />
</bean>
Write your abstract base class in plain Java (without any Spring coupling) :
public abstract class AbstractClass{
private Sample1 sample1;
private Sample2 sample2;
public AbstractClass(Sample1 sample1, Sample1 sample2){
this.sample1 = sample1;
this.sample2 = sample2;
}
...
}
Note that adding a constructor with parameters (both for the abstract class and the concrete class) makes injection easier and dependencies clearer.
Then you have two ways :
1) Annotate the concrete class(es) with #Component.
Such as :
#Component
public class MyClass extends AbstractClass{
public MyClass (Sample1 sample1, Sample1 sample2){
super(sample1, sample2);
}
}
This first way has the advantage to be short : just an annotation to add.
But it makes de facto the subclass as a bean that may potentially be loaded by the Spring context.
2) Alternatively, declare the bean in a Configuration class.
Such as :
#Configuration
public class MyConfig{
#Bean
public MyClass myClass(Sample1 sample1, Sample1 sample2){
return new MyClass(sample1, sample1);
}
}
This second way is more verbose but has the advantage to not modify the subclass code and also let clients of the class to decide whether the class should be a bean.
Each approach has its advantages and its drawbacks.
So to use according to the concrete requirement.
There is no need in converting this code. You only need to make the classes that extend com.test.core.common.AbstractClass declared as spring managed beans by either annotating them with #Component or #Service or declaring a method annotated with #Bean in your configuration class.
Generally "abstract bean" is not needed in Java Configuration, there is even no equivalent. It was needed in xml configuration for parameter inheritance which is now achievable with plain java methods. Find example from Stephane Nicoll who is Spring Core developer.
Since Java has it's own mechanism of abstract classes and inheritance in place, you don't need to do the coupling of following code in your spring coupling.
<bean id="sample" class="com.test.core.common.AbstractClass" abstract="true">
<property name="sample1" ref="sample1" />
<property name="sample2" ref="sample2" />
</bean>
In XML config, you needed to do this to specify the template for inheritance of child beans. But since Springboot uses Java configuration, this part is handled directly with Java inheritance.
What it means is that you can declare this abstract class as a normal Java abstract class and treat only the child classes as beans without worrying about the abstract parent class.
When we want to instantiate an abstract class or an interface as a #Bean (with spring-java-config), we can generally:
Instantiate an anonymous inner class.
Override all abstract methods! ;(
So for a Method injection, it would look like:
#Configuration
class FreakyConfig {
#Bean
#RequestScope // !! (stateful)
public MyFooBarDelegate delegate() {
return MyFooBarDelegate.of(...);
}
#Bean // singleton, stateless, abstract (no spring deps.)! ;)
public MyFooBarAbstractSingletonBean() {
return new MyFooBarAbstractSingletonBean() { // anonymous inner class!
#Override
protected MyFooBarDelegate fooBarDelegate() { // ...and override the (injected)/prescribed methods.
return delegate();
}
};
}
} // (stress) tested ;)
Another good(?) question: Where is that latest ("current") "spring-javaconfig/docs"???
see also:
1.4.6. Method Injection
Method Injection Article
1.5.3. Singleton Beans with Prototype-bean Dependencies

Spring - autowire a class that have a constructor [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Anyway to #Autowire a bean that requires constructor arguments?
In my controller I want to use #Autowired to inject a class using the method / constructor autowiring. for example using:
#Autowired
private InjectedClass injectedClass;
My problem is that the injected class injectedClass have a constructor, and I need to pass a variable to the constructor from the controller. How can I pass values to the constructors?
If you are using annotations you can apply #Autowired annotation to MyClass's constructor, which will auto wire beans you are passing to MyClass's special constructor. Consider following e.g.
public class MovieRecommender {
#Autowired
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
#Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
You can either mark private data members with #Resource(name = "x") annotation OR wire them using constructor injection in the application context XML.
Annotations and XML configuration can be mixed in Spring. It need not be all or nothing.
<bean id="myClass" class="foo.bar.MyClass">
<constructor-arg ref="yourArgRefHere"/>
</bean>

Application context bean

I am trying to extract the bean from application context.
so I defined class:
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public void setApplicationContext(ApplicationContext _applicationContext) throws BeansException {
applicationContext = _applicationContext;
}
}
and in my applicationContext.xml
<bean id="workflowService" class="com.mycompany.util.WorkflowService">
<bean id="applicationContextProvider" class="com.mycompany.util.ApplicationContextProvider"></bean>
<context:annotation-config />
However in my code when I try:
WorkflowService service = (WorkflowService) ApplicationContextProvider.getApplicationContext().getBean("workflowService");
I get:
java.lang.ClassCastException: $Proxy40 cannot be cast to com.mycompany.util.WorkflowService
EDITED:
WorkflowService code:
public class WorkflowService implements Serializable {
...
#PostConstruct
public void init() {
}
...
#Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public Collection<lData> findData(Integer contractId) {
}
}
I guess WorkflowService is a class implementing at least one interface (you haven't provided enough code). You are trying to lookup the exact class from Spring, while you should ask for one of the interfaces.
This is because Spring most of the time wraps beans in several proxies (e.g. transactional ones). If the class implements at least one interface, resulting proxy implements all of them, but cannot be cast into original class. If the class does not implement any interfaces (commonly considered a bad practice for heavyweight services, questionable though), Spring will use CGLIB subclassing from original class. In this case you code would be valid.
Your problem is this bit:
WorkflowService implements Serializable
Any proxies that Spring generates will implement all of the interfaces that your class does - in this case, Serializable, which is almost certainly not what you want.
What you should do is extract a new interface from WorkflowService, which includes the findData method (let's call it WorkflowOperations). By implementing that interface, you'll then be able to cast to that interface, e.g.
public interface WorkflowOperations {
Collection<lData> findData(Integer contractId);
}
public class WorkflowService implements WorkflowOperations {
...
#PostConstruct
public void init() {
}
...
#Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public Collection<lData> findData(Integer contractId) {
}
}
and then:
WorkflowOperations service = (WorkflowOperations) ApplicationContextProvider.getApplicationContext().getBean("workflowService");
You should probably also remove Serializable from WorkflowService. You almost certainly don't need this, it makes no sense to serialize Spring beans like this. If you just added Serializable out of habit, then remove it (and get out of that particular habit).
You are annotating your service with #Transactional, so Spring is wrapping your service bean with a transactional JDK dynamic proxy that implements the same interfaces as your bean, but is not a WorkflowService. That is why you get a ClassCastException when you try to assign it to a WorkflowService variable. I see two possible solutions:
Specify an interface WorkflowService with your business methods and implement it in a WorkflowServiceImpl class. Then in the Spring context change the bean definition from WorkflowService to WorkflowServiceImpl. This is what I recommend, both as a general design principle and specially to work in a Spring environment: Spring likes interfaces.
In your Spring context, add proxy-target-class="true" to your <tx:annotation-driven/> element in order to force Spring to implement proxies by subclassing, so that proxy instanceof WorkFlowService is true. I find this solution dirtier. Also note that you add a dependency on CGLIB this way.

Anonymous Spring bean

How is an anonymous Spring bean useful?
There are two uses that i can think of straight of.
As an inner bean
<bean id="outer" class="foo.bar.A">
<property name="myProperty">
<bean class="foo.bar.B"/>
</property>
</bean>
As a configurer of static properties
public class ServiceUtils {
private static Service service;
private ServiceUtils() {}
...
public static void setService(Service service) {
this.service = service;
}
}
public class ServiceConfigurer {
private static Service service;
private ServiceUtils() {}
...
public void setService(Service service) {
ServiceUtils.setService(service);
}
}
Now that class can be configured like this.
<bean class="foo.bar.ServiceConfigurer">
<property name="service" ref="myService"/>
</bean>
In addition if there is a bean that is not depended upon by any other bean eg RmiServiceExporter or MessageListenerContainer then there is no need other than code clarity to give this bean a name.
There is several uses:
a bean injected inline as dependency in other bean
a bean that implements InitializingBean and DisposableBean, so his methods are called by IoC container
a bean implementing BeanClassLoaderAware, BeanFactoryPostProcessor and other call-back interfaces
On top of already provided answers (inner bean, life-managing interfaces, configurer of static properties) I would another one, which we use a lot. That is...
in combination with autowiring (by type). When you configure multiple objects of given type and you don't really care how they are called in XML.

Categories