Here is brief what BeanFactoryPostProcessor does
A BeanFactoryPostProcessor lets you modify the actual bean definition
instead of the instance as it's created.Spring IoC container will
allow BeanFactoryPostProcessors to read the configuration metadata and
potentially change it before the container has actually instantiated
any bean. PropertyPlaceholderConfigurer is the example of
BeanFactoryPostProcessors to externalize some property values into
another separate file in Java Properties format
What i understand from above is BeanFactoryPostProcessor modies the bean definition at the start of application context(ie while applocation load).
But i did not get does it changes class definition physically in the file or in memory.
i am usingPropertyPlaceholderConfigurer in my project. To verify it , once application got started , i went to class path and opend the class file in decompiler
whether propert {test.property} got replaced with actual value or not. Its not. So does spring modifies the class definition in memory ?
The BeanFactoryPostProcessor will not change the physical class definition. And in most of the applications in production, the user who runs the application will not even have access to 'write' to the files. All modifications happen once the classes are loaded. So when you need a bean instance, Spring will load the bean definition (but won't instantiate 'any' instance), apply the bean factory post processor that's registered and then create an instance (and then apply the bean post processor, which is different from bean factory post processor) and then only returns the bean.
a BeanFactoryPostProcessor can change/add BeanDefinition
a BeanDefinition is just a metadata describing a bean :
The name of the bean
The class to instanciate
Properties to inject
Dependencies
...
It's the equivalent in xml of a <bean id=".." class=".."/> tag
Related
My question is: Why does this piece of code correctly set the constructor parameter property port:
private final RedisServer redisServer;
public RedisTestConfiguration(#Value("${cache.port}") final int port) {
this.redisServer = new RedisServer(port);
}
As of my understanding, #Value("${cache.port}") is resolved by a BeanPostProcessor called AutowiredAnnotationBeanPostProcessor. Spring bean lifecycle works in a way that the constructor method is called before any BeanPostProcess, see picture below. Note The constructor is called before BeanPostProcessor.postProcessBeforeInitialization().
How come this is still working?
Regards,
Bart
This behavior is supported by PropertySourcesPlaceholderConfigurer
Ref: https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-placeholderconfigurer
PropertySourcesPlaceholderConfigurer is a BeanFactoryPostProcessor. It collects #Value fields and updates bean definition in spring container. PropertySourcesPlaceholderConfigurer should be created in the container before any bean is initialized.
Bean metadata is described here in the documentation:
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-metadata
So, the flow is the following:
1. Bean definition readers collect beans declarations in xml files or from java classes. Example, XmlBeanDefinitionReader.
Ref: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/xml/XmlBeanDefinitionReader.html
Bean Factory Post Processors update bean definitions. Example, PropertySourcesPlaceholderConfigurer.
Spring container looks at the bean definition and creates beans(calls constructor) according to bean definition values.
Ref: https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-class
So, the problem is that
As of my understanding, #Value("${cache.port}") is resolved by a BeanPostProcessor is not correct. #Value is managed by BeanFactoryPostProcessor, not BeanPostProcessor
Actually, documentation states:
A default lenient embedded value resolver is provided by Spring. It will try to resolve the property value and if it cannot be resolved, the property name (for example ${catalog.name}) will be injected as the value. If you want to maintain strict control over nonexistent values, you should declare a PropertySourcesPlaceholderConfigurer bean, as the following example shows:...
Spring has some kind of default property resolver, that is another BeanFactoryPostProcessor. But it is possible to override it with PropertySourcesPlaceholderConfigurer
I would like to inject a bean (lets call it clientStub) into my service bean.
There are two requirements for that:
In order to create the clientStub bean, I need to access the #Client annotation, that carries some important information that are used to lookup the relevant configuration in the properties.
It must support constructor based injection (and #Bean method parameter injection)
Expected usage:
#Autowired
public MyService(
#Client("invoice-manager") InvoiceManagerClientStub clientStub,
SomeOtherBean bean1, ...) {
or
#Bean
MyService myService(
#Client("invoice-manager") InvoiceManagerClientStub clientStub,
SomeOtherBean bean1, ...) {
So I would like to do the same as the #Value annotation e.g. derive the value from the annotation on the parameter (plus some internal lookups).
Unfortunately, the usual BeanFactorys don't seem to be aware of the target's annotations.
Alternatives considered
Using an BeanPostProcessor to inject the values into annotated fields. Well, this is what I'm currently doing, but it doesn't feel right to have an immutable class with a single setter for injection.
Injecting it to a field and then exposing it as a bean or manually invoking the constructor is even worse.
Creating a proxy instance of the injected class. This isn't possible since the injected classes are generated + final and not part of my library.
Derive the configuration from the bean name: Not sure how to implement this and how to explain the user what the configuration parameters should be named in their properties files. I also would like to avoid bean name conflicts.
Non-Goals
Overwriting any core beans. I would like to distribute the extension as a library (spring-boot based), so any excessive replacement of spring internal beans should be avoided.
TLDR
How do I tell spring to resolve the parameter using my annotation's value (resolver)?
I know I can not use #Autowired annotation in a non managed spring class. But I notice I do able to get a bean instance inside a non managed spring class if I am retrieving it through ApplicationContext getBean method.
can someone explain me why is that ? what is the different between the options ? in both spring doesn't know the non managed class
1) You can use #Autowired in a non-managed spring class if you use #Configurable -with the usage of internal aspect weaving spring will manage to autowired the referenced beans into your "Configurable" class when it is constructed with the "new" operator. Here is an article how this works: http://www.javacodegeeks.com/2013/09/spring-configurable-magic.html
If a class is not configurable spring cannot notice when a new instance is created to autowire its references.
2) The ApplicationContext is "Central interface to provide configuration for an application." Here you have access to the whole spring managed beans etc. That's why you can get everything due to accessing it via ApplicationContext. http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/ApplicationContext.html
ok, so here's the major points:
the "bean declaration" (either in xml or java) is just a recipe of how to instantiate the object (not a object itself).
when spring application boots, the beanFactory receives this recipes from beanDefinitionReader, instantiates objects according to them (recipes) and then pass them (objects) to a list of beanPostProcessors (several times) that are "injecting" dependences to the instantiated objects and then puts the objects into hashMap.
roughly saying applicationContext is a class exposing access to this beans;
and that's how you can access this beans out of spring application using applicationContext.
another thing is that, actually you can inject beans into non managed beans through #Configurable. in this case the AspectJ would be used for making this work
I have a situation and im trying to figure out why it is so. The scenario is I have a class A that implements an operation exposed by a webservice. For each request for the operation a new instance of A is created. The entire thing is manged by Spring internally and I am not sure how exactly the Class A in instantiated by the webservice.
Now i have a class variable whose value i want to inject during runtime through
#Value("${someValue}")
String someVariable
someValue is defined a system property. But each of the beans created has someVariable as NULL.
I tried the same thing in another class annotated with #Configuration in the same package and it is resolving the variable fine.
So, Im thinking if the ability to inject through #Value depends on the way a bean is created like #Component, #Configuration-#Bean, XML definiti
Not really. Actually You can inject value with #Value in both the component scan bean and xml definition bean. But pay attention to this, It depends on which xml file that you put the Placeholder in, it just valids in the per-container. For example, you put it in applicationContext, then the bean create in xxx-servlet.xml can not inject value with #Value.
I have two beans, beanA and beanB, in my Spring config. Both of these beans implement the same interface. I have a class with an autowired field of the interface type (i.e. it will be populated with an instance of beanA or beanB).
Initially there was only one bean, so I simply used the #Autowired annotation and the field was populated. However, now there's two potential beans that could be autowired. I want to autowire the bean based on the existence of a property in one of my .properties resources. Is there any elegant way to do this?
The solution I'm using now is to use the #Qualifier annotation on the autowired field to specify beanA and then make a check to see if the property exists in code. If it does, I reassign the field to an instance of beanB. It's a very clunky way of doing it, so I'm looking for a better option.
Apart from the newer feature of bean profiles, you can also take advantage of FactoryBean which instantiate a bean at the time of access. The idea is to inject the FactoryBean with the bean types (e.g. fqcn.BeanA or fqcn.BeanB). Then factory bean will return the bean factory to instantiate the correct type of the bean that you may need. The configuration of FactoryBean then can take advantage of properties coming from a resource bundle.
Bean profiles could be great fit for this - based on the "active" profile let one or the other bean be created.
Somewhat of an older article, but is still a good reference to profiles in Spring 3.1- http://blog.springsource.com/2011/02/11/spring-framework-3-1-m1-released/
Spring Profile can help
Configuration Changes
web.xml
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>a</param-value>
</context-param>
spring-beans.xml with profiles. Profile value can behave as the
property value for decision making.
<bean id="A" profile="a"/>
<bean id="B" profile="b"/>