AnnotationConfigApplicationContext has not been refreshed yet using ApplicationContextAware - java

I am using Spring beans in a non-spring framework and for that I have implemented the ApplicationContextAware to access the spring beans.
#Service
public class ApplicationContextProviderService implements ApplicationContextAware {
private static ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextProviderService.applicationContext = applicationContext;
}
public static <T> T getBean(Class<T> beanType) {
System.out.println("bean out: " + applicationContext);
return applicationContext.getBean(beanType);
}
}
I try to access a Spring service: ConnectionStateService from the non-spring class:
this.connectionStateService = ApplicationContextProviderService.getBean(ConnectionStateService.class);
I get the following error:
java.lang.IllegalStateException:
**org.springframework.context.annotation.AnnotationConfigApplicationContext#7f485fda has not been refreshed yet at
** org.springframework.context.support.AbstractApplicationContext.assertBeanFactoryActive(AbstractApplicationContext.java:1072) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE] at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1102) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE] at com.example.app.service.ApplicationContextProviderService.getBean(ApplicationContextProviderService.java:19) ~[classes/:na] at com.example.app.CustomFilter.<init>(CustomFilter.java:26) ~[classes/:na]
How to resolve this issue?

The issue is related when the application tries to call to ApplicationContext before the application runs, so you won't be able to have application context because it wasn't created. The solution is create a singleton for ConnectionStateService class so you won't need to create a service for calling the ApplicationContext.
public class ConnectionStateService {
// static variable instance of type Singleton
private static ConnectionStateService single_instance = null;
// private constructor restricted to this class itself
private ConnectionStateService() {
// some stuffs for initialize here
}
// static method to create instance of Singleton class
public static ConnectionStateService getInstance() {
if (instance == null)
instance = new ConnectionStateService();
return instance;
}
}

I think you are getting the bean when the context is not initialized
So actually be sure you are invoking this piece of code :
this.connectionStateService = ApplicationContextProviderService.getBean(ConnectionStateService.class);
after context is initialized

Related

Spring Application context is null in a ApplicationContextAware class

I am getting NullPointerException inside an ApplicationContextAware class and I am not sure why.
Why is the applicationContext null on calling getBean(SomeClass.class) method
Following is my BeanProviderUtil class:
#Component
public class BeanProviderUtil implements ApplicationContextAware {
public static ApplicationContext applicationContext;
public static <T extends Object> T getBean(Class<T> beanClass) {
return applicationContext.getBean(beanClass);
}
public static Object getBean(String beanName) {
return applicationContext.getBean(beanName);
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
BeanProviderUtil.applicationContext = applicationContext;
}
}
On calling function
SomeOtherClass obj = BeanProviderUtil.getBean(SomeOtherClass.class)
I am getting NPE. On debugging, it comes out that applicationContext is not properly initialized by Spring.
Note
Is it because I have enabled lazy bean initialization?
However, I tried disabling lazy initialization by #Lazy(false) as well as from Global application.yml, but it didn't help.
So I figured out what was going wrong here by Myself.
I have set global lazy Initialization and that was the main culprit.
Since I was not Autowiring BeanProviderUtil, the bean was never created and hence applicationContext never got initialized.
Setting #Lazy(false) fixes the issue.
Earlier, on disabling #Lazy using #Lazy(false) it was not working because somehow Spring was not recognizing the BeanProviderUtil a component. Adding #ComponentScan to my test class does the trick.

Programmatically bind instance of class to qualifier in spring

I have instances of the same class being created from config values such that I need them to be injected/autowired from that config value. I was doing it in guice like:
for (String s : config.getStrings()) {
bind(Foo.class).annotatedWith(Names.named(s)).toInstance(new Foo(s));
}
Is there any way to do something like this in Spring or is there a way to use something like a FactoryBean to create instances of a class given a qualifier?
public final class FLEXSyncFactory implements ApplicationContextAware {
private static AbstractApplicationContext context;
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
context = (AbstractApplicationContext) applicationContext;
}
And to register alias of bean
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getBeanFactory();
Foo fooBean = beanFactory.getBean(Foo.class);
beanFactory.initializeBean(fooBean, "TheAliasForBeanNameYouNeed");
beanFactory.autowireBeanProperties(fooBean, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);

Not able to load Application Context in Spring Boot app

I am working on a Spring Boot application wherein I am using that application to expose a SOAP webservice. I am using Apache CFX framework for SOAP impl in Spring boot app. I am using Annotation based approach.
I am facing issue in setting the Application Context from the Spring Boot Configuration file in one of the Beans. Below is my code.
#SpringBootApplication
#ComponentScan("com.test")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
The configuration file is as below.
#Configuration
public class WebServiceConfiguration {
//All individual bean definitions should go here
#Autowired
ApplicationContext appContext;
#Bean
public ServletRegistrationBean cxfServlet() {
return new ServletRegistrationBean(new CXFServlet(), "/soap-api/*");
}
#Bean(name = Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
return new SpringBus();
}
#Bean(name="IValidator")
public IValidator getValidator(){
return new Validator();
}
#Bean(name="SOAPprocessImpl")
public IPSoap getService() {
return new SOAPprocessImpl();
}
#Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(springBus(), getService());
endpoint.publish("/WS_1.0");
endpoint.setWsdlLocation("process.wsdl");
return endpoint;
}
Now I have the bean SOAPprocessImpl implementation in which I need to get the Application Context so that I can get handle to the Validator bean. I have declared SOAPprocessImpl as a bean in the configuraton file. The code is as below
#javax.jws.WebService (endpointInterface="com.test.IPSoap")
public class SOAPprocessImpl implements IPSoap, ApplicationContextAware {
private static ApplicationContext context;
public static ApplicationContext getApplicationContext() {
return context;
}
#Override
public void setApplicationContext(ApplicationContext ac)
throws BeansException {
context = ac;
}
private static final Logger logger = Logger.getLogger(SOAPprocessImpl.class.getName());
private IValidator validator = (IValidator) context.getBean("IValidator"); // context is NULL here
public IRResponse GetBalance(TSSearchParams SearchParams) {
// Some processing logic
}
}
So the issue is that when I run the boot application by deploying to the embedded Tomcat then the Application Context is not getting set in the SOAPprocessImpl class even after implementing the ApplicationContextAware. I also tried Autowiring but that also is not working.
Strangely I tried to see if I can get the ApplicationContext in the Configuration file where all the bean are defined. Here it is getting setting properly.
Can anyone help me how to solve this issue. I am new to Spring Boot and may have missed some configutaion. Thanks in advance.
Option(1): To fix the issue, you need to use #Configuration to register your SOAPprocessImpl bean to the Spring container as shown below so that ApplicationContext object can be injected :
#Configuration
#javax.jws.WebService (endpointInterface="com.test.IPSoap")
public class SOAPprocessImpl implements IPSoap, ApplicationContextAware {
private static ApplicationContext context;
private IValidator validator;
public static ApplicationContext getApplicationContext() {
return context;
}
#Override
public void setApplicationContext(ApplicationContext ac)
throws BeansException {
SOAPprocessImpl.context = ac;
}
#PostConstruct//use PostConstruct
public void init() {
validator = (IValidator) context.getBean("IValidator");
}
//add your current code
}
The important point is that you can't use the context object until the bean is prepared by the container, so you need to use #PostConstruct method as shown above to initialise your variables.
Option2 (recommended):
The best approach is that you can use #Autowired to inject IValidator object into SOAPprocessImpl as shown below so that you don't need your SOAPprocessImpl bean to be aware of ApplicationContextAware. Spring container will inject the instance for the implementation provided for the IValidator class (provided it is under the packages of #Componentscan).
#Component
#javax.jws.WebService (endpointInterface="com.test.IPSoap")
public class SOAPprocessImpl implements IPSoap {
private static final Logger logger = Logger.getLogger(SOAPprocessImpl.class.getName());
#Autowired //spring directly injects this object
private IValidator validator;
public IRResponse GetBalance(TSSearchParams SearchParams) {
// Some processing logic
}
}

Inject spring bean in custom el functions

i want to create a custom el functions to get in a fast way select options from dao. I'm using Spring and i want to inject spring bean dao in my custom el functions class.
In el functions class i'm using static methods and i'm unable to access application context.
I used an implementation of ApplicationContextAware in this way
public class AppContextUtil implements ApplicationContextAware
{
private ApplicationContext applicationContext;
private static final AppContextUtil instance=new AppContextUtil();
private AppContextUtil()
{
}
public static AppContextUtil getInstance()
{
return instance;
}
public <T> T getBean(Class<T> clazz)
{
return applicationContext.getBean(clazz);
}
/**
* {#inheritDoc}
*/
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
this.applicationContext = applicationContext;
}
}
but applicationContext is null.
The only way to access to applicationContext is as belove
WebApplicationContext appCtx =
WebApplicationContextUtils.getWebApplicationContext(context.getServletContext());
MyDAO myDAO = appCtx.getBean(MyDAO.class);
but in this way i need to pass PageContext in el functions params.
How i can create an el functions class with spring bean support? how i can access in static way to applicationContext?
Thank you.
A dirty solution to "inject" a bean or Application Context into an static field:
#Component
public class AppContextUtil {
private static ApplicationContext applicationContext;
#Autowire
private set ApplicationContext(ApplicationContext applicationContext) {
AppContextUtil.applicationContext = applicationContext;
}
}

How to pass a service to an EmptyInterceptor class?

public class Auditing extends EmptyInterceptor {
#Resource
private ApplicationService applicationService;
public boolean onFlushDirty(Object entity, Serializable id,Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
if(applicationService == null){
System.out.println("applicationService is null");
}
return(true);
}
}
I observed for each hibernate action a new Auditing object is getting created and in onFlushDirty() it is always printing " applicationService is null "
Can anyone tell me how can i make ApplicationService available in an EmptyInterceptor?
I found a work around for this by having a Class with static applicationService property.
Now by creating a static reference for it i can use applicationService.
Its working for now.. Please post any better or efficient suggestions if you have :)
Regards,
You can create a class with application context object by implementing ApplicationContextAware interface.
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
public static ApplicationContext getApplicationContext() {
return context;
}
#Override
public void setApplicationContext(ApplicationContext ctx) {
context = ctx;
}
}
Now you can obtain your bean using below code.
applicationService = (ApplicationService ) ApplicationContextProvider.getApplicationContext().getBean("applicationService")
Above code can be used to obtain any other bean in future and would not require you to keep adding static beans.

Categories

Resources