Does BeanPostProcessor override the initializing bean notification? - spring

I was experimenting Spring's BeanPostProcessor, BeanFactoryPostProcessor, Initializing bean , destroy bean.
I'm confused with these notification concepts.
I created a simple bean implementing Initi*Bean, Disposable bean. And also registered sample post processor , factoryPostprocessor. And added sysout in all the interface methods.
I created AbstractApplicationContext and registered shutdown hooks as well.
When i ran the app, i see BeanFactoryProcessor method prints, AfterProperties method, and then destroy method called. I dont see "initializing bean" called..
Does BeanPostProcessor override the initializing bean notification?
Kindly explain.

You're returning null in both your BeanPostProcessor methods. This causes Spring to think you don't want any further processing on that bean, including initializing through InitializingBean.
Just return the original bean you receive (in both methods)
#Override
public Object postProcessAfterInitialization(Object bean, String arg1) throws BeansException {
System.out.println("postProcessAfterInitialization");
return bean;
}
since you don't want to process it.

Related

Spring Boot - A bean referencing itself to trigger AOP #Async within the same class, not working

I want to within my own Bean call a method within itself which has its own #Async and #Transactional proxies but it isnt working.
public class MyClass {
private MyClass _selfWithProxy;
#PostConstruct
public void postContruct() {
_selfWithProxy = applicationContext.getBean(MyClass.class);
}
void myMethodA() {
_selfWithProxy.myMethodB()
}
#Async
#Transactinal
void myMethodB() {
//do stuff
}
However when I call myMethodA from another Bean the call to myMethodB does not intercept with an Async interceptor. I can see _selfWithProxy is a proxy bean, and the proxy activates but there are is no Async interceptor in the chain.
When I call myMethodB from another bean the #Async works, so I know it is setup correctly
Self invocation won't work for #Async. I believe that is because the proxy (your code + AOP advice) object calls your methodA on the target object (just your code) which then calls it's own methodB which isn't advised by AOP. In general I would not advise having spring bean methods call other methods of the same bean.
"#Async has two limitations:
It must be applied to public methods only.
Self-invocation — calling the async method from within the same class — won't work.
The reasons are simple: The method needs to be public so that it can be proxied. And self-invocation doesn't work because it bypasses the proxy and calls the underlying method directly."
https://www.baeldung.com/spring-async

Injecting dependencies using an Interceptor

Would it be technically a good and acceptable practice to inject required dependencies using an Interceptor type. For example:
public #interface Inject {
public Class thisType();
}
public class InjectionInterceptor implements HandlerInterceptor {
#Override
public bool preHandle(HttpServletRequest hsr, HttpServletResponse hsr1, Object o) {
HandlerMethod handlerMethod = (HandlerMethod) o;
Class type = handlerMethod.getBeanType();
Annotation[] annotations = type.getAnnotationsByType(Inject.class);
for(Annotation annotation: annotations){
Inject inject = (inject) annotation;
for(Field field :type.getDeclaredFields()){
if(field.getType().equals(inject.thisType())){
field.setAccessible(true);
field.set(handlerMethod.getBean(), Services.find(inject.thisType()));
}
}
....
return true;
}
...
}
A bean can have 4 scopes.
Singleton
Only one shared instance of the bean will be managed, and all requests for beans with an id or ids matching that bean definition will result in that one specific bean instance being returned by the Spring container.
It is default scope of a bean.
Prototype
New instance is returned by the container when bean with the specified id is requested.
Ex: If you have a bean with id as "employee" in your spring container, then everytime you do a
Employee emp = context.getBean("employee");
A new instance will be returned.
request, session, and global session are for use only in web-based applications
Request
A new instance is created for every single HTTP request.
Ex : Login needs different instance everytime.
Session
A new instance will be created of the bean using the bean definition for the lifetime of a single HTTP Session.
global
The global session scope is similar to the standard HTTP Session scope and really only makes sense in the context of portlet-based web applications
You can specify the scope of a bean in two ways
Using XML:
<bean id="employee" class="com.company.Employee" scope="singleton"/>
Using annotation.
mark the class with #Scope("prototype")
you can read more about scopes here
sample code for reference is available here

Replace ScheduledAnnotationBeanPostProcessor in integration tests

So, I've got a spring application that uses the #Scheduled annotation to do various jobs. In prod, it works great. However this feature causes us some problems when running spock integration tests-as soon as the container starts up, all our tasks are fired and it mucks up our test runs.
I'm looking for a way to turn off the scheduling functionality, but still have the container (configured with #ComponentScan) pick it up as a regular 'ol bean.
Based on some legwork I've done so far, it seems that if I could override the built-in ScheduledAnnotationBeanPostProcessor with a no-op implementation I could achieve this goal..but when I create this bean in the container(created using the #Bean("scheduledAnnotationBeanPostProcessor"-see the code section below), it just seems to be added to the list of BeanPostProcessors-which still contains the original implementation.
#Bean(name="scheduledAnnotationBeanPostProcessor")
ScheduledAnnotationBeanPostProcessor scheduledAnnotationBeanPostProcessor(){
return new ScheduledAnnotationBeanPostProcessor(){
#Override
public Object postProcessAfterInitialization(final Object bean, String beanName){
return bean
}
}
}
So, I guess my question is-how can I wire in a bean that will replace a built-in BeanPostProcessor? FYI I'm using Spring 3.2.4 and the application is configured 100% via Spring annotations.
thanks.
My mistake was that I didn't name the bean correctly. I ended up finding where this bean was being built(in org.springframework.scheduling.annotation.SchedulingConfiguration) and I copied it's configuration.
This method demonstrates the proper names/config:
#Bean(name=AnnotationConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
#Role(BeanDefinition.ROLE_INFRASTRUCTURE)
BeanPostProcessor scheduledAnnotationBeanPostProcessor(){
return new BeanPostProcessor(){
#Override
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean
}
#Override
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean
}
}
}

null pointer exception whilst using spring - although bean loaded correctly

i have a bean:
public class StatusPollingFilter extends AbstractDiscovery implements UserTester
defined as :
<bean
id="statusPollingFilter"
class="com.xxxxx.yyyyyyy.zzz.StatusPollingFilter">
<property
name="evoDao"
ref="evoDaoFacade">
</property>
it loads ok, as logs show:
2013-03-07 11:30:14,703 INFO DefaultListableBeanFactory [RunJSPModule] - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#14966cc: defining beans [org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.config.internalTransactionAdvisor,tilesConfigurer,viewResolver,urlMapping,discovery,statu
sPollingFilter,
when i try to use it as:
TopoObject topoobj = evoDao.getTopoObjectDao().findById(topoId);
evoDao is the main guy doing the work this is defined in:
class AbstractDiscovery
as:
//Reference to the DAO facade, for accessing the database via hibernate.
protected EvoTAMDAOFacade evoDao;
The Question?
because i extend AbstractDiscovery i thought i would be able to access evoDao and use it as normal to get my Dao but it seems not - where am i going wrong?
why can it not find the Dao?
The EvoTAMDAOFacade is injected into AbstractDiscovery as:
/**
* DI method for accessing the DAO facade for accessing the
* database via hibernate.
* #param dao
*/
public void setEvoDao(EvoTAMDAOFacade dao)
{
this.evoDao = dao;
}
the getTopoObjectDao() is defined in the injected EvoTAMDAOFacade of as:
public TopoObjectDAO getTopoObjectDao()
{
return this.topoObjectDao;
}
AbstractDiscovery is defined as:
public abstract class AbstractDiscovery implements Discovery
The exception is :
[07 Mar 2013 11:42:24:353] POLL: Exception while getting obj during status update java.lang.NullPointerException 162.109.37.114 at:
java.lang.NullPointerException
Another Q? the statusPollFilter is running as thread in a scheduler for multiple objects - i'm not actually sure i should be defining it as a singleton bean but how do i access the Dao if i don't?
thanks in advance for your help.
having read more - i have come across the ans.
because the StatusPollingFilter object is under control of scheduler (i knew that scheduler had something to do with it) then it is unaware of the spring beans which is why i keep getting null when i try injecting the bean.
i created a class:
ApplicationContextProvider implements ApplicationContextAware
added static access
private static ApplicationContext appContext;
did a setter for it :
public void setApplicationContext(ApplicationContext context)
{
appContext = context;
}
and added
public static Object getBean(String beanName) throws BeansException
{
return appContext.getBean(beanName);
}
used in code as :
EvoTAMDAOFacade evoDao = (EvoTAMDAOFacade) ApplicationContextProvider.getBean("evoDaoFacade");
i now have access to the facade bean and all injected beans into facade.
i still have an issue with hibernate session but thats prob due to some other issue.
pt here is i don't have access to the bean as its not in control of the spring container so i needed to somehow get it , probably could have done it via the factory method but why mess around when there a simpler way.
thanks for help by anyone who may have posted or tried to understand my problem.

Instantiation of Bean through Factory method

I have declared a bean which is instantiated via a factory method. The factory method invokes some remote services. So, the method has been declared to throw Exception.
The bean is correctly being instantiated when everything works fine. However, when the factory method throws exception, then everything starts going wrong. because my declared bean is referenced from another bean.
I want to set a default value, if the factory method throws Exception.
Part of my config file is as follows :
<bean id="Helper" class="com.test.Helper">
<constructor-arg ref="myBean" />
</bean>
<bean id="myBean" class="com.test.Factory" factory-method="getBean" />
the getBean() method is as follows:
Factory {
public static Bean getBean() throws Exception{
//Invokes some Remote Services and does some processing
....
....
//returns bean object
}
}
Please help me how I can solve this. I am not allowed to modify the factory method.
If bean or factory method throws an exception during creation, the whole application context startup fails (I guess this is what you mean by "everything starts going wrong"). There is nothing you can do about it on the Spring side.
If you want to return some default value, simply catch the exception in your custom factory, log it and return that default. If you cannot modify the existing factory, consider #Configuration approach:
#Configuration
public SafeCfg {
#org.springframework.context.annotation.Bean
public Bean bean() {
try {
return Factory.getBean();
} catch(Exception e) {
return //some default Bean
}
}
}
It works since Spring 3.0. Just place it somewhere so that the application context can pick it up.
But I doubt this is what you want. Even when the external system becomes available, you'll be still using the default, fallback value. Do you expect it to work like this? More advanced approach is to use lazy proxy (Spring has support for that: Is there a spring lazy proxy factory in Spring?) and initialize it only when needed and refresh when broken.

Resources