I have 2 scenarios where I would like to understand/confirm the usage of #Component:
Extending concrete class:
I have a concrete super class A and its sub-class Aa in my web application. I have annotated with Aa with #Component(value="aa") and #Scope(value=WebApplicationContext.SCOPE_SESSION). Also, I have annotated A class with #Component(value="a") and #Scope(value=WebApplicationContext.SCOPE_SESSION).
My question -> I am only doing applicationContext.getBean("aa"). I can skip the annotations in A class (please correct me if I am wrong), but I don't know why and how? My understanding has been that if a class is not annotated with #Component or defined in bean configuration file then Spring doesn't handle its instance management.
Abstract concrete class:
Same scenario and question as above just that in this case super class is an abstract class.
You have to register the beans via beans in a config or via component annotations (Repo or controller or service). If not the bean is not contained in your application context container.
#Component add a bean in the Spring registry. Then, you can retrieve this bean later.
If you don't use the bean, there is no need to add it to the bean registry. (so just remove #Component(value="a") and #Scope(value=WebApplicationContext.SCOPE_SESSION) )
On your use case, you set a scope to SESSION. It means that every time you create a session, Spring will instantiate your class (A / Aa) and put it on the session. As it is an instance of the class you don't need the super class instance (A) to be able to create the Aa instance.
With A beeing abstract, it is exactly the same thing, except if you try to scan it for Spring to pick it, Spring will throws an error saying A cannot be instantiated.
Related
I have been given a task to assign a property from .properties file to a non Spring bean class using #Value annotation. To do this, I created a method on a #Component annotated class and set the property into it, then called that method from the non Spring bean class. I thought this would work, however, still showing as null.
I was told this is because the #Component annotated class I used is not spring loaded. Question, how can I tell if a class is Spring loaded bean? I have been searching on google but can't find anything helpful aside from examples with #Component or #Configuration annotations. Thanks.
Spring Container is responsible for creating or managing beans. It all satisfy the dependencies by injecting them either through constructor or setter method. But in your case you want the #Value injection in your non spring bean which is really not possible as per my understanding. Because here the spring does not creating the object then how it satisfy the dependencies of it.
You have two options for this situation.
Either annotate class using #Component
Either read property file using Properties
https://www.mkyong.com/java/java-properties-file-examples/
I encountered this issue when I'm trying to override the RibbonRoutingFilter bean defined in spring zuul. To emphasis, I'm doing an override, not just creating a bean of the same type. So end of the day, I want the "ribbonRoutingFilter" bean from zuul not registered at all.
So I have my own implementation. First thing I tried, I used the #component annotation and autowire the dependencies. Added a breakpoint in the constructor, and it ended up never being called. So I realize my definition must be loaded earlier than zuul's. So I created a configuration class with #Configuration annotation and #Order(Ordered.HIGHEST_PRECEDENCE), and use a #Bean annotation to instantiate my class there. Still, my method is always loaded earlier.
It turned out there's certain order Spring is following when loading configuration classes definitions and that is where overrides happen. Class org.springframework.context.annotation.ConfigurationClassParser has the detailed logic in method doProcessConfigurationClass(). I'll put my simplified summarization or the ordering rule here:
if you application class(where main() method is defined) has any classes defined in it, they are parsed and definition inside them are registered first
then it will registered Beans defined as #component and defined in #Configuration class
then it will add definitions introduced by #Import
then it will add definitions introduced by #ImportResource
then add definitions from #bean methods inside the application class
then from default methods on interfaces( I think it's java 8)
then try to do the same steps above for any parent classes you application class has extended.
This explained why my override was not working. It's because all I have been trying is in step 2. But zuul defined the bean by a #Import which is step 3.
So to solve my problem, I added a #Bean annotated method to my application class there and do the instanciation and the override just happend as expected.
The above summarization might not be accurate, it just give you an idea about what could have failed your override. You'd better debug the ConfigurationClassParser when you are trying your specific use case.
I am trying to understand purpose of Spring-created beans. Are they just global shared object (such that they are declared like
#Component
public class MySpringBean{},
and later this object is used anywhere like inside some class
public class MyClass {
#Autowired
MySpringBean mySpringBean;
}
)?
Can their internal creation/implementation assumed like this? -
public class MyApp {
MySpringBean mySpringBean;
}
and used in MyClass like -
public class MyClass {
MySpringBean mySpringBean = MyApp.mySpringBean;
}
Its the object valid for only that class hierarchy. In your case Spring just create an object for mySpringBean and will keep it available for MyClass. Internally its more like
MySpringBean mySpringBean = new MySpringBean()
But actually
all Spring beans are managed - they "live" inside a container, called "application context".
Autowiring happens by placing an instance of one bean into the desired field in an instance of another bean. Both classes should be beans, i.e. they should be defined to live in the application context.
so in your case both mySpringBean and an instance of MyClass will be in application context.
Based on your question, I believe you should know about how beans are managed by Spring (or how Spring manages the life cycle of beans from initialization to destroy). But also note that you don't have to go into too much of details (wells, it's a framework that's is providing you). Yes, it's definitely true to init involves using new operator. These objects live inside the Container and Spring wires them whenever it's called for. Since beans are managed by Spring, you can implement callback methods too.
I have a class GList which implements the interface IQList.
I have a class Qurious in which I need a Provider to provide prototypes of GList. (Besides annotating GList scope as prototype).
However, I do not want Qurious to be aware of the existence of GList. Therefore, in Qurious, I have a declaration
Provider<IQList> qlistProvider.
What do I have to do with either GList or applicationContext, so that Spring will instantiate GList to satisfy
Provider<IQList>
?
I am trying to avoid defining a factory.
If I understood you correctly:
Instantiatin Spring bean of type Provider in spring configuration
and annotating your Provider<IQList> qlistProvider. as #Autowired should be enough.
Or do you want Spring framework to guess that you will need a particular type of object instance and do it for you? I don't think that it can
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