Spring bean creation lifecycle : Why having multiple interaction points? - java

I'm learning spring and I'm stuck with the bean lifecycle !
When creating a bean, spring gives us several maners to interact with it. We can use one or all of :
BeanFactoryPostProcessor
BeanPostProcessor#postProcessBeforeInitialization
#PostConstruct
InitializingBean#afterPropertiesSet
#Bean#initMethod
BeanPostProcessor#postProcessAfterInitialization
Spring calls them in the order above
My question is : why all these points of interaction ? and when to use each of them (the use case) ?

A BeanFactoryPostProcessor and a BeanPostProcessor are quite different beast and also apply to different things.
A BeanFactoryPostProcessor will operate on the metadata for a bean (I like to call it the recipe) and will post process that. A well know example is the PropertySourcesPlaceholderConfigurer which will inject/replace all #Value in configuration with the value. A BeanFactoryPostProcessor operates on the metadata and thus before any bean has been created.
The BeanPostProcessor can be applied to a bean and can even replace a bean. Spring AOP uses this quite a lot. An example is the PersistenceExceptionTranslationPostProcessor, when a bean has been created it will pass through this BeanPostProcessor and when it is annotated with #Persistence the bean will be replaced by a proxy. This proxy adds exception translation (i.e. it will convert JpaException and SQLException to the Spring DataAccessException). This is done in a BeanPostProcessor. And can be be done before the init-callbacks are called (the postProcessBeforeInitializationor after they have been called thepostProcessAfterInitialization). The PersistenceExceptionTranslationPostProcessorwill run in thepostProcessAfterInitialization` as it needs to be certain the bean has been initialized.
The ServletContextAwareProcessor will run right after the object has been created to inject the ServletContext as early as possible as the initializing of a bean might depend on it.
The 3 callbacks for initializing a bean are more or less the same but are called in sequence because they have been included in later versions. It starter with only an interface InitializingBean and init-method in xml (later also added to #Bean and the annotation support was added when annotations became a thing.
You need init methods to initialize a bean, you might want to check if all properties have been set (like a required datasource) or you might want to start something. A DataSource (especially a connection pool) is a good example to initialize. After all dependencies have been injected you want to start the pool so it will open the connections. Now as you probably cannot modify the code you want to use the init-method if you control the code you probably want to add #PostConstruct. If you are writing an framework that depends on Spring I would use the InitializingBean.
Next to those 3 init methods you also have the destruction counter-parts. The DisposableBean interface (and destroy-method) and the #PreDestroy annotation. Again when you stop your application you also want to close the connections in your connection pool and you want to probably call the close method on the DataSource. A perfect sample of a destruction callback.

Related

BeanFactory Vs ApplicationContext in concern of BeanPostProcessor And BeanFactoryPostProcessor

I am now learning little bit detail about Spring IoC Containers with the difference between BeanFactory Vs Application Context. I was also referring the previous stack overflow discussion and tutorial point from the following links,
BeanFactory vs ApplicationContext
https://www.tutorialspoint.com/spring/spring_ioc_containers.htm
In my learning I found that ApplicationContext is capable of resolving textual messages from a properties file and the ability to publish application events to interested event listeners
And BeanPostProcessor Registration and BeanFactoryPostProcessor Registration doing manually in BeanFactory and automatically doing in application context,
So my confusions are,
Since BeanFactory Manually doing BeanPostProcessor registration, Does that mean the developer is doing something while bean is getting initiating ? Because, the same process ApplicationContext does automaticall according to documentations
What is the purpose of BeanFactoryPostProcessor registration ? What is the difference between BeanPostProcessor and BeanFactoryPostProcessor ?
If we say ApplicationContext has the ability to resolving text messages from properties file (Message source access), So for what purpose application context is communicating with property file ?
How can I better understand this concept ?
BeanFactory is lightweight and it doesn't load in-memory/initialize any bean from application.xml (even singleton beans) unless factory.getBean("bean-name") method is called; whereas ApplicationContext is heavyweight is loads everything on container startup. BeanFactory also supports limited scopes like proto and singleton and features like AOP doesn't work with BeanFactory.
So to answer your 1st question YES while using BeanFactory just loading the xml and creating BeanFactory object does not guarantee any bean is initialized; only place to use it is when you are concerned of runtime memory consumption
Note: ApplicationContext extends ListableBeanFactory extends BeanFactory.
BeanPostProcessor as the name suggest gives you hooks to work on an instance of a bean created by the spring container by ApplciationContext/BeanFactory implementation (i.e. before and after initialization) Spring AOPs like transactions. caching etc. ref #Required for example. BeanFactoryPostProcessor on the other end lets you modify the actual bean definition before initialization of the instance. The PropertyResourceConfigurer and PropertyPlaceholderConfigurer are two good examples refer PropertyResourceConfigurer example, how properties are changed before initializing the actual beans.
ApplicationContext main responsibility is initialization of bean, now based on the individual bean is defined it provides way to perform specialized tasks like resources bundle loading/property configurer. I suggest you look at the javadoc for a concrete implementation of ApplicationContext like GenericApplicationContext . If you look at how each methods are implemented you will understand how the control flows from AppContext to individual beans before and after they are initialized. AppContext only has the contract for supports tasks

how can I limit the context of a #Primary Bean?

I have a bean defined in a appContext named MyBean in MyProject1.
I have in other app that injects all the bean definitions of MyProject1 (including MyBean).
Now I need to override that bean but there is no easy way , so in MyProject2 I make
<bean primary="true" class=MyBean />
It works great, my question is....
What will happen with all others that were using MyBean? Will now use the new bean with the primary=true or how can I specify which should use this new bean and which should keep using the old one?
Following spring documentation primary bean is used only if there are some candidates to be injected. All created beans are in the context.
If you need only your primary bean to be injected, you can use:
#Autowired
private MyBean myBean;
So all your old beans will be replaced with primary one.
If you need to handle all MyBean beans (for example you do Chain Of Responsibilities) you can inject:
#Autowired
private List<MyBean> myBeans;
and injected object would contain all your bean instances (primary and nonprimary). As Usual primary bean can be accessed from list by 0 index: myBeans.get(0). All alternative markers (for example filter by vendorType...) to detect bean that you needs you should specify and handle in you code filtering collection, but in usual way if project architecture doesn't have issues you have no needs make alternative markers filtering bean objects in collection.
Do not forget about singleton if you need only one bean in your context.
If you have specified different bean unique names you can inject with #Qualifier (sometimes using #Resource from java API javax.annotation.Resource) specifying correspond name as parameter to detect bean by name.
Spring provides ability to inject properties using SpEL. May be they'll provide new functionality to inject beans using SpEL also (it could help you in your issue in best way).
Use profiles or #Conditional. #Qualifier is meant for resolving conflict for autowire, not for deactivating all but one. When using #Qualifier, all the candidate beans are still active.
Using profiles, when you want to use the bean from project2, simply start the app with a profile=project2; the link above describes multiple ways to do that.
See my answer here for a complete example of using #Conditional.

Order of Configuration in SpringBoot

I am trying to understand how beans that we make using #Configuration tends to override the beans that are generated by SpringBoot by default. I have been working on a project where in many cases we create beans for things like ZuulConfigs and the assumption is, whatever we are making shall take precedence over the default generated bean. I have been trying to figure this out but can't. Basically,
Is Spring achieving this via some custom class loader
If not how is this precedence working. Can I give some precedence in similar manner to my beans
Can I generate similar hierarchy in my project,if so how
The help is highly appreciated
Spring AutoConfiguration is used to provide a basic configuration if certain classes are in the classpath or not.
If you want to configure the order in which beans are instantiated by spring you can use
#DependsOn("A")
public class B {
...
}
This would create bean "A", then "B". Hence you can order the configuration depending upon the beans need first to be done. Anyways Spring automatically detects the dependencies by analyzing the bean classes.
for more help check this question
Spring Boot AutoConfiguration Order
Alternative :
There is also "#AutoConfigureOrder" annotation(where you can prioritise the configuration), you can have a look in the code for deeper understanding.
Documentation of AutoConfiguration is here
First of all, class loading and bean creation are two different things. We don't need to create a bean to load a class, however, a class has to be loaded in order to create a bean.
Now, coming back to Spring's example, Spring looks into all the packages configured by #componentScan and creates beans of all the classes annotated with #Bean, #Configuration and/or #Component. Spring's container keeps track of all the beans created and hence, when it encounters user defined bean with same name and class type as default bean, it replaces the original definition with user defined one (e.g. we can create our custom #ObjectMapper to override Spring boot's own instance). You can also use #Primary annotation to make you bean take precedence if another definition with same class exists (documentation here).
Below are the answers for your questions:
Spring uses reflection to load the classes and create instances. Although you can load the classes with your custom class loader (more on that here), you don't need to worry about it for #Configuration.
Yes, you can use #Primary annotation to give your bean a precedence. You can also use #Order(here) to define the creation order for your beans.
With #Primary, #Order and #Qualifier annotation you can define your own hierarchy for bean creation.
Can I give some precedence in similar manner to my beans
Yes.
A) To define a specific order your Configuration classes will be handled (by the way, a Configuration class does not have to be annotated with #Configuration (so-called full definition), but it's enough to be annotated with #Component, #ComponentScan, #Import, #ImportResource or just have a method annotated with #Bean - so-called lite definition), you should
1) add your Configuration Candidates to your SpringApplication's primarySource, for example, in your main method like that
SpringApplication.run(
new Class[]{YourSpringBootApplication.class, Config1.class, Config2.class, ...},
args);
2) and annotate each of your Configuration Candidates with #Order annotation, any other ordering means like Ordered interface, #DependsOn etc will be ignored by ConfigurationClassPostProcessor, the order in the primarySource array will also be ignored.
Then ConfigurationClassPostProcessor will sort your Configuration Candidates and handle them according the #Order annotation value you specified.
B) The precedence can also be achieved by defining your own AutoConfiguration classes. Although both Configuration and AutoConfiguration are handled by the same ConfigurationClassPostProcessor, they are essentially distinctive machineries. To do so
1) define in your classpath /META-INF/spring.factories file and put in the EnableAutoConfiguration section of it your AutoConfiguration classes like that
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
your.package.AutoConfig1,your.package.AutoConfig2
2) and annotate your AutoConfiguration classes with #AutoConfigureOrder, #AutoConfigureAfter, or #AutoConfigureAfter annotations, any other ordering means again will be ignored.
Like #Strelok pointed out, AutoConfiguration classes, your own and provided e.g. by spring-boot-autoconfigure library alike, will be added to the end of the list of Configuration Candidates.
Remember, however, that the order the Configuration Candidates will be handled by ConfigurationClassPostProcessor does not necessarily coincide with the order the beans defined by the Configuration classes will be created. For example, you might define your Configuration class that overrides TomcatServletWebServerFactory to make your own customization of Tomcat web server like
#Configuration
public class EmbeddedTomcatConfig {
#Bean
public TomcatServletWebServerFactory containerFactory() {
...
return customizedTomcatWebServerFactory;
}
but this method will be called right at the moment when your Spring Boot application decides to create a Web server, regardless of how you defined the precedence for your EmbeddedTomcatConfig Configuration class.
Is Spring achieving this via some custom class loader
There is no need to. Although you could, as always with Spring, define your own ClassLoader for BeanFactory, standard ClassLoader is good enough if everything you need for Configuration in your application is available in the classpath. Please notice, that at first phase ConfigurationClassPostProcessor does not load (i.e. does not resolve) the Configuration candidates classes (otherwise, most of the classes in spring-boot-autoconfigure library will fail to load). Instead it analyzes their annotations with bytecode analyzer, ASM by default. For that purpose, it is just enough to get a binary form, a byte array, of a class to feed it to bytecode analyzer.
Just know this: Spring Boot (specifically) auto configuration classes are always configured last. After all user beans have been created. Spring Boot auto configuration classes almost always use the #ConditionalXXXX annotations to make sure that any beans of the same type/name and other conditions that are configured in your application will take precedence over the Spring Boot auto-configured beans.
If you want your #Component to take precedence over other #Component while scanning all the components by spring, use #Order(Ordered.LOWEST_PRECEDENCE) i.e. the max value to load your component over other.
#Primary is used to give your bean a default preference, we can override the default preference using #Qualifier

Instantiating arbitrary classes thru Spring

I'm writing a service registry class. This service registry will scan packages for annotated classes and then populate some internal map. What I need then, is to be able to query for services (by String name) using some method (let's say Object get(String name)). This method will then search internal map for a service with such name and returns instance.
What I'm doing right now, is having this ServiceRegistryBean implement ApplicationContextAware and BeanDefinitionRegistryPostProcessor and a list of Strings (package names) given on construct.
Then, as soon as the bean is constructed, registry post processor kicks in (see note) and the registry class adds the service classes as new beans (singleton, lazy loaded) to the spring bean registry. Then, getting the service instance is as simple as requesting a bean from context, returning singleton instance.
My question is: is there a better way in Spring to do this? I've looked into bean factories, but it does not seem to me the same. Support for auto-wiring and DI in service instances is essential, that's why I want Spring to instantiate it. Also, I like the idea of Spring taking care of singletons.
Note: I've found out, that when I inline the bean creation in <constructor-arg> (that is, bean is not named and is just an instance passed as constructor argument of other bean - in my case, I'm passing registry as a parameter to other constructor), BeanDefinitionRegistryPostProcessor interface methods (namely public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)) is not called at all! I'm quite sure, it is some behavior of Spring I don't know about, but I was not able to find proper documentation for the post-processor.
Thank you for any hints or insights!
Scanning for custom annotations it's already supported, you only need to add a include-filter to <context:component-scan> tag, ie
<context:component-scan base-package="org.example">
<context:include-filter type="annotation" expression="some.Annotation"/>
</context:component-scan>
see http://static.springsource.org/spring/docs/current/spring-framework-reference/html/beans.html#beans-scanning-filters
If you turn on default-lazy-init I suppose that the DI Container is ready to use as Service Locator Registry.
About the note, only root bean definitions are taken into account when looking for BeanFactoryPostProcessors, inner beans are ignored.
Usually, scanning and registering beans is done by BeanDefinitionParsers instead because you known when the beans are registered and beans are visible for tools, like STS Spring Bean Explorer, but using a BeanDefinitionRegistryPostProcessor is correct. The interface ensures that beans are defined before other BeanFactoryPostProcessors run.

Wicket #SpringBean doesn't create serializable proxy

#SpringBean
PDLocalizerLogic loc;
When using above I receive java.io.NotSerializableException. This is because loc is not serializable, but this shouldn't be problem because spring beans are a serializable proxies.
I'm using wicket-spring library, and as injector SpringComponentInjector, where wrapInProxies is by default set to true, so I think that proxies should be created, but they aren't.
On the page https://cwiki.apache.org/WICKET/spring.html#Spring-AnnotationbasedApproach is written:
Using annotation-based approach, you
should not worry about
serialization/deserialization of the
injected dependencies as this is
handled automatically, the
dependencies are represented by
serializable proxies
What am I doing wrong?
Do you know how the bean is being injected?
Through component initialization (i.e. a Component and being filled in by the SpringComponentInjector)
Some other object using InjectorHolder.getInjector().inject(this)?
Injected directly by spring (i.e. this is a spring bean where the property is being set by Spring configuration)
Cases 1 and 2 would use wicket-spring integration and would wrap the bean with a wicket proxy which is serializable.
Case 3 would only provide you whatever spring passes to you without wrapping.
First, make sure your bean is really proxied. By default spring does not create proxies.
Second, check your proxying strategy - whether it is proxy-target-class="true" or not. If it is false, (afaik) a reference to your object is stored in the invocation handler of the JDK proxy, and is attempted to be serialized.
So you'll need to make your class Serializable as well, if you need it to be.
Can you double check that the instantiation listener is added in your application class:
addComponentInstantiationListener(new SpringComponentInjector(this));
Also, this only works for fields in Wicket components, not arbitrary classes.
See also wicket #SpringBean can not create bean

Categories

Resources