I have some legacy code where the class is a Spring bean defined and initialized through xml. It is a singleton with a field member which is a class dependency. There is a setter method for it, so I am assuming its supposed to be set via Spring, although I didn't find any xml defining it. There is also a get() method for the dependency, it has a null check and if its null it manually creates it outside of Spring like so
Class Test{
Dependency d;
setD(Dependency d){this.d=d;}
getD(){
if(this.d==null){
this.d = new Dependency();
}return this.d
}
}
I am trying to understand why this Spring bean is initializing a dependency outside of Spring and what are the implications if any, is this just bad/old design? or Am I not understanding something with how Spring works.
I would say it's a bad design, probably author wanted to provide fall-back for the case when D was not injected in spring. Another idea is an attempt to make D a lazy dependency. You should explore what's inside D.
Generally you can use #Required to mark the members that always should be injected. Or just use simple and nice constructor injection. If you're concerned about lazy injection, that's how Spring works by default.
Related
I'm totally lost on this topic . I've researched Spring Autowiring on internet trying to figure out what it does and everything I find is mostly saying "Spring Autowiring helps you autowire collaborating Beans " and thats it . I would greatly appreciate if someone can explain to me from scratch what is Spring Bean, What is Autowiring and how these two work together with examples and explanations of this examples. Don't just say that "Spring Autowiring is autowiring two beans " because I don't get it what it means .
What I understand right now is that lets say if have a simple class :
Public class Car(){
public int numberOfWheels;
}
and we declare this class as a Bean, we than can create the instance of the object of this class without saying "new" keyword. So we can just declare it in a bean and insert value of this "numberOfWheels" property outside the java class . I might be super wrong here or using very bad example , because I've been trying to learn Spring Framework and it's just been very hard for me , so any help would be greatly appreciated.
Well, Spring is a Dependency Injection framework, so you should start learning about this.
DEPENDENCY INJECTION
This is a technique whereby one object supplies the dependencies of another object. Such as, for example: object a of type A need is dependent of an object b of type B. In a code example:
Customer it's dependent of Person:
public class Person {
private String name;
private String lastName;
}
public class Customer {
private Person person;
}
In this case, any Customer object will have a Person object dependency.
Now, in Spring scope, all objects are named beans, so this is a bean, an Object that it's injected into Spring Context.
Spring provides a Dependency Injection mechanism that it's very easy. For our example, you can put put some of the following annotation: #Component, #Bean, #Service on class Person, and Spring will create an object of type Person with calling default constructor. Afer that, in class Customer, you can put #Autowired annotation on top of the Person person attribute. This annotation, will tell Spring to search for a specific bean of type Person that was injected into the Spring Context, and Spring using Reflection(searching by name) will find a Person object type that was creating by using one of the #Component, #Bean, #Service annotations. After that, Spring will pass the reference of the Person object that was found to the Customer object that requires it.
Spring Bean is an object which is instantiated and maintained automatically by Spring Framework. They usually depend on each other in some way, and the dependencies therefore must be resolved.
Autowiring is one of the ways how to resolve these dependencies. You don't manually specify which concrete dependency should be provided to the class, you just choose the way how Spring should automatically find the correct dependency (by matching the class's property name and name of the desired bean, for instance).
Spring's documentation is very extensive and you can find a lot of useful information there. For more info about Spring Beans, you can read this, if you want to know more about autowiring, try this.
To basically, Spring has a bean pool which means Spring creates java objects and put them into a pool. Whenever you want to use an object, you fetch object from pool using #Autowired annotation.
Spring basically uses Reflection to create objects by its own, instead of passing objects from class to class. This is what basically Autowire is.
This concept is called Dependency Injection. Spring injects components, services, repositories whenever you want.
I have a class that would otherwise be a very generic POJO but I would like to inject a dependency in it because I would like to avoid passing that dependency as a (constructor) parameter:
//no managed context annotation because it's a simple POJO
public class QueuedBatch {
//however, I would like to inject the context managed bean below
#Autowired
AsyncActionQueue asyncActionQueue;
Currently, no exception is thrown at deploy time but asyncActionQueue is null at runtime so I get a NullPointer when I hit the POJO.
How can I annotate my POJO to add it to the Spring managed context so that I can inject dependencies into it? AsyncActionQueue is a singleton and I would rather not be passing it to QueuedBatch as a (constructor) parameter.
This post is similar, except that I want to add my POJO into the managed context.
As the comments suggested you have 2 ways of dealing with this
Pass the AsyncActionQueue as a parameter in the constructor of QueuedBatch. This doesnt require Spring to know anything about QueuedBatch, but enforces the dependency to be provided when an instance of QueuedBatch is created.
Annotate the QueuedBatch class with #Component. And ensure that the package which contains QueuedBatch is included in the component scan when initializing the spring context. In this way, it becomes a spring managed bean allowing AsyncActionQueue to be autowired into it. You may change the scope of QueuedBatch component based on your requirement.
I have a DAO that has method like this:
class AbcService
{
private AbcDAO isntance;
public void getStuff()
{
instance.getQueryResult();
}
}
Now if this method is called from anywhere it will give a NullPointerException where instance calls the query method.
Still this code is in use in the project from a long time and i would think twice before calling it incorrect. Is there some way by which this code can be accessed. Is this a standard practice?
If you have a setter for isntance, you just need to call it before calling getStuff. This is standard (although some would say all needed fields should be set inside a constructor.
This answer just applies if you are using springbean and its broader than your question.. But I guess this will be useful to you
Yes this is generally used practice when you are using it as a spring bean. So, before calling this method, you need to be sure that this springbean is instantiated. Basically, this is done by either getting spring bean from ApplicationContext or the caller class itself receives instance of this bean from its parent bean....
General practise is to load application context by defining contextloaderlistener in web.xml. For more info on how to do it, see http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/web/context/ContextLoaderListener.html
I think the object instance is injected to AbcService via the Spring Dependency Injection. Please search for any ".xml" file in your project, which has fully qualified class name of AbcService mentioned in its bean definition.
I just want to confirm that I fully understood the prerequisites for CDI to work. If I have a class A:
public class A {
#Inject private B b;
}
Now when I instantiate this class using:
A a = new A();
In that case, A.b will be null.
But if I define in another class a member:
#Inject A a;
and later use a, a.b will be correctly populated?
Does CDI only work if the class requiring an injection was also created by CDI container? Or what am I missing if injections turn out to be null while creating a POJO using ordinary instantiation with new (yes, I got beans.xml in place)?
Does CDI only work if the class requiring an injection was also
created by CDI container?
Yes, that's pretty much it. The lifecycle of a ManagedBean is controlled by the container and should never be instantiated with the new keyword (BTW: the same is true for EJBs & Spring beans). If you need to create a new ManagedBean you will probably want to use a producer method.
While others have stated correctly that for the most part DI containers will not inject dependencies into bean that they did not instantiate this is not entirely true.
Spring has a wonderful feature that will autowire the bean when you create it using new A().
You just have to use AspectJ and mark your bean with the #Configurable annotation.
#Configurable
public class A {
#Inject private B b;
}
Its actually kind of an awesome feature cause you can do Active Record style POJO's while still honoring your DI (its in fact how Spring Roo does it).
You should also know that with Spring you can autowire a bean programmatically after its been instantiated with the AutowireCapableBeanFactory. This is how it typically autowires JUnit Test Case Classes because JUnit creates the test case classes.
Yes Spring is not CDI but in theory you could write your own #Configurable for CDI or there is probably a CDI way of doing the above.
That being said the above is sort of a sophisticated feature (and kind of a hack) and as #JanGroth mentioned understaning the lifecycle bean management of the container is critical whether its CDI, Spring, Guice etc.
You may use BeanProvider.injectFields(myObject); from Apache DeltaSpike.
Yes, #Inject works only inside a container because it is done using interceptors on method calls. When the container creates a bean it wrappes it in interceptors which perform injection, and in the case of instantiation using new no interceptors will be called during bean method invocation, and there will be no injection.
Here's the conditions needed for a class to be a managed bean (and hence, for the #Inject annotation to work on its fields/methods):
http://docs.oracle.com/javaee/6/tutorial/doc/gjfzi.html
I'm an end-user of one of my company's products. It is not very suitable for integration into Spring, however I am able to get a handle on the context and retrieve the required bean by name. However, I would still like to know if it was possible to inject a bean into this class, even though the class is not managed by Spring itself.
Clarification: The same application which is managing the lifecycle of some class MyClass, is also managing the lifecycle of the Spring context. Spring does not have any knowledge of the instance of MyClass, and I would like to some how provide the instance to the context, but cannot create the instance in the context itself.
You can do this:
ApplicationContext ctx = ...
YourClass someBeanNotCreatedBySpring = ...
ctx.getAutowireCapableBeanFactory().autowireBeanProperties(
someBeanNotCreatedBySpring,
AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT, true);
You can use #Autowired and so on within YourClass to specify fields to be injected etc.
One way to bring a bean into Spring despite its manufacture being external is to use a helper class marked as a #Configuration bean that has a method (marked with #Bean) that actually makes the instance and hands it back through Spring (which does its property injection and proxy generation at that point).
I'm not quite sure what scope you need; with prototype, you'll get a fresh bean in each place.
#Configuration
public class FooBarMaker {
#Bean(autowire = Autowire.BY_TYPE)
#Scope("prototype")
public FooBar makeAFooBar() {
// You probably need to do some more work in here, I imagine
return new FooBar();
}
}
You can inject properties required for manufacture into the #Configuration bean. (I use this to create instances of an interface where the name of the class to instantiate is defined at runtime.)
suppose that u have the following dependency chain:
A --> B --> C --> x --> y -- > Z
A, B, C are spring managed beans (constructed and manged by spring framework)
x, y are really simple POJOs that constructed by your application, without spring assistance
now if you want that y will get a reference to Z using spring that you need to have a 'handle' to the spring ApplicationContext
one way to do it is to implement ApplicationContextAware interface . In this case I would suggest that either A, B or C will implement this interface and will store the applicationContext reference in a static member.
so lets take Class C for example:
class C implmenets ApplicationContextAware{
public static ApplicationContex ac;
void setApplicationContext(ApplicationContext applicationContext) {
ac = applicationContext;
}
.............
}
now, in class y you should have:
(Z)(C.ac.getBean("classZ")).doSomething()
HTH -- Yonatan
Another way to do this is to us use AspectJ. This is the recommended way of injection Spring beans into non-managed objects that are created with the new operator. See this for details:
http://www.javacodegeeks.com/2011/02/domain-driven-design-spring-aspectj.html
Searching endless combos of autowire inject spring bean into pojo applicationcontextaware beanaware etc circled me back here but this didnt provide a complete enough solution for me.
This is a much better implementation/tutorial of this IMO:
I hope it helps everyone like it finally helped me.
Accessing Spring Beans from outside Spring Context
Be careful that in oldest version of Spring, there is thread-safe problem with bean factory http://jira.springframework.org/browse/SPR-4672
If you want to create an object outside the Spring context, and make that object available for injection into other beans that are in the Spring context, you can follow the steps in this article.
Basically, you create a parent application context and push your external object into this parent context as a singleton. Then you create you main application context (for example, from xml files), with the parent application context as its parent.
Object externalObject = ...
GenericApplicationContext parent = new StaticApplicationContext();
parent.getBeanFactory().registerSingleton( "externalObject", externalObject );
parent.refresh();
ApplicationContext appContext = new ClassPathXmlApplicationContext( ... , parent);
From a Spring configuration class, set a static field on the non-Spring class that needs the beans.
I have an example in my answer to a Liquibase question: https://stackoverflow.com/a/71191546/5499391