ApplicationContextProvider suddenly null - java

For the past 2 weeks things have been going great in my application. Last night I login remotely to work to find out that when I run my application my ApplicationContextProvider class no longer has knowledge of the Application Context. I've run Maven clean & build in addition to rebooting my PC. Can't seem to shake it...
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public void setApplicationContext (ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
My Main class:
public static void main(String[] args) throws IOException {
System.setProperty("java.util.logging.SimpleFormatter.format", "%4$s: %5$s%n");
final HttpServer server = HttpServer.createSimpleServer(".", 80);
WebappContext ctx = new WebappContext("ProductionQueue", "/");
//enable annotation configuration
ctx.addContextInitParameter("contextClass", "org.springframework.web.context.support.AnnotationConfigWebApplicationContext");
ctx.addContextInitParameter("contextConfigLocation", "com.production");
//allow spring to do all of it's stuff
ctx.addListener("org.springframework.web.context.ContextLoaderListener");
....
ctx.deploy(server);
server.start();
//start the production process
Production.init();
System.in.read();
server.stop();
My Production class:
public class Production {
private static final Logger logger = Logger.getLogger(Production.class.getName());
/* A list of active workflows */
private static List<Workflow> workflowList = new ArrayList<Workflow>();
private static ProductionService productionService;
/**
* Initialize the production line
*/
public static void init() {
logger.info("Initializing production workflows...");
ApplicationContext context = ApplicationContextProvider.getApplicationContext(); //THIS IS NULL
productionService = (ProductionService) context.getBean("productionService");
No configuration has been modified at all. Within my config class I do have a bean for it...
#Configuration
#ComponentScan(basePackages = {
"com.production"
})
#PropertySource(value= {
"classpath:/application.properties",
"classpath:/environment-${FETTER_ENVIRONMENT}.properties"
})
#EnableJpaRepositories("com.production.repository")
#EnableTransactionManagement
public class Config {
#Value("${db.url}")
String PROPERTY_DATABASE_URL;
#Value("${db.user}")
String PROPERTY_DATABASE_USER;
#Value("${db.password}")
String PROPERTY_DATABASE_PASSWORD;
#Value("${persistenceUnit.default}")
String PROPERTY_DEFAULT_PERSISTENCE_UNIT;
#Value("${hibernate.dialect}")
String PROPERTY_HIBERNATE_DIALECT;
#Value("${hibernate.format_sql}")
String PROPERTY_HIBERNATE_FORMAT_SQL;
#Value("${hibernate.show_sql}")
String PROPERTY_HIBERNATE_SHOW_SQL;
#Value("${entitymanager.packages.to.scan}")
String PROPERTY_ENTITYMANAGER_PACKAGES_TO_SCAN;
#Bean
public ApplicationContextProvider applicationContextProvider() {
return new ApplicationContextProvider();
}

I'd say its mudsoup between the try to have it static and use it as a bean.
You creating a new instance of the ApplicationContextProvider as a spring bean. This is ApplicationContextAware and so gets the AC injected. But THEN you do not use said bean, you use its static getter to read the field, yet this, static thing never received the AC in the first place. You're never using your actual bean.
I'd say scratch that provider completly, and rely soley on the ApplicationContextAware interface, it does what you want, ie it was designed to do exactly that, why use a delegating bean?

I do not know if
#Bean
public ApplicationContextProvider applicationContextProvider() {
return new ApplicationContextProvider();
}
the ApplicationContextAware interface.
Try to add #Component at ApplicationContextProvider class and then remove the #Bean. I hope that the ApplicationContextAware` interface is taken in account if this class is found by your normal component scan.

Turns out there was a buried exception my logging was preventing me from getting access to. Thanks for help.

Related

Trying start RabbitListener on command after builded Application - RabbitListenerEndpointRegistry is empty

I searched all over the stackOverFlow and couldn't find an answer.
I need to start RabbitListener on command - from just REST send request to start this listener (no other option).
So I found that I need set properties in Listener like that: #RabbitListener(queues = "myQueue", id = "listener_id", autoStartup = "false") (of course is albo annotation #Component).
I made also initializer class using implementation of ApplicationContextAware and RabbitListenerEndpointRegistry like below:
#Slf4j
#Component
public class ListenerInitializer implements ApplicationContextAware {
private ApplicationContext applicationContext;
public void startListener() {
RabbitListenerEndpointRegistry listenerRegistry = applicationContext.getBean(RabbitListenerEndpointRegistry.class);
listenerRegistry.getListenerContainer("listener_id").start();
log.info("Listener started.");
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
And when I tried to use method startListener() mostly I received NullPointerException: null like RabbitListenerEndpointRegistry doesn't exist. I wrote mostly, because sometimes (every time I make mvn clean install) it works and everything is fine. But mostly I received NullPointerException.
With #Autowired of ApplicationContext same situation.
I tried with:
#Autowired RabbitListenerEndpointRegistry rabbitListenerEndpointRegistry
but in that case shows me that RabbitListenerEndpointRegistry bean doesn't exist (also through #RequiedArgsConstructor.
I tried also to make configuration like below:
#Configuration
#EnableRabbit
class ListenerConfig {
#Bean
#DependsOn("listener")
ListenerInitializer ListenerInitializer() {
return new ListenerInitializer();
}
#Bean(name = "listener")
Listener listener() {
return new listener();
}
}
and also doesn't work.
Anybody have any idea how I can fix it? I guess I need to initialize injection of ApplicationContext into ListenerInitializer as late as possible due to need to initialize itself RabbitListenerEndpointRegistry, but how to do it?
Many thanks for any advice
edit:
I call it to start through controller
#RequiredArgsConstructor
#RestController
class RestController {
private final ListenerInitializer listenerInitializer;
#GetMapping("/startListener")
ResponseEntity<String> startListener() {
listenerInitializer.startListener();
return ResponseEntity.ok("Listener started.");
}
}
I don't know if this is going to help you somehow, but here is a fully working Spring Boot application:
#SpringBootApplication
public class So75236736Application {
public static void main(String[] args) {
SpringApplication.run(So75236736Application.class, args);
}
#Bean
Listener listener() {
return new Listener();
}
public static class Listener {
#RabbitListener(queuesToDeclare = #Queue("myQueue"), id = "listener_id", autoStartup = "false")
void handle(Object body) {
System.out.println("Received: " + body);
}
}
#Component
public static class ListenerInitializer implements ApplicationContextAware {
private ApplicationContext applicationContext;
public void startListener() {
RabbitListenerEndpointRegistry listenerRegistry =
this.applicationContext.getBean(RabbitListenerEndpointRegistry.class);
listenerRegistry.getListenerContainer("listener_id").start();
System.out.println("Listener started");
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
#RestController
public static class StartListenerController {
private final ListenerInitializer listenerInitializer;
public StartListenerController(ListenerInitializer listenerInitializer) {
this.listenerInitializer = listenerInitializer;
}
#GetMapping("/startListener")
ResponseEntity<String> startListener() {
this.listenerInitializer.startListener();
return ResponseEntity.ok("Listener started.");
}
}
}
Only difference that I don't use an #EnableRabbit explicitly, but rather rely on the auto-configuration. I also don't declare ListenerInitializer as a #Bean since it is already marked with #Component and that is enough for Spring Boot to scan it.
Ok, I found the solution and sorry for bother you guys. Lack of knowledge. Still I don't know how it possible it works before, because I didn't changed anything, cause I was sure it should be like that, but solution was to move annotation #RabbitListener(queues = "myQueue2", id = "listener_id", autoStartup = "false") from over a class to over a method or add #RabbitHandler over a method.
Thank you #Artem Bilan for your help!

Injecting a single Spring bean instance into a static variable of a utility class

I have this web application built with Spring and Vaadin, in which I wanted to do this, for the sake of convenience:
Create a utility class that wraps a Spring service, and allows the use of its static methods throughout the application, without having to worry about injecting this service everywhere, like so:
String configurationValue = ConfigurationUtil.getString("some.property.key");
If you work with Vaadin, you might see how convenient this is, because the whole presentation layer is written in Java and you can't always inject Spring services into your Vaadin components as these Vaadin components are not always Spring components themselves.
So this is my utility class:
public final class ConfigurationUtil {
// this is the spring service:
private static ConfigurationService configurationService;
public static void setConfigurationService(final ConfigurationService configurationService) {
ConfigurationUtil.configurationService = configurationService;
}
public static String getString(final String key) {
return configurationService.getString(key);
}
}
This is my service:
#Service("configurationService")
public class ConfigurationServiceImpl implements ConfigurationService, BeanFactoryAware {
private final FrameworkService frameworkService;
#Autowired
public ConfigurationServiceImpl(final FrameworkService frameworkService) throws IOException, ConfigurationException {
// this is where I set this service bean to the utility class
ConfigurationUtil.setConfigurationService(this);
this.frameworkService = frameworkService;
}
public String getString(String key) {
// code that retrieves a configuration value from our configuration files
}
}
My question here is: I'm a bit worried about this causing a bottleneck to access the configuration service, as multiple threads will be calling it, from multiple user sessions. Would this be a problem? Please explain why. Also, feel free to point out other problems with this solution.
I suggest to create a bean that implements ApplicationContextAware like this:
#Component
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext ac) {
context = ac;
}
public static String getString(final String key) {
ConfigurationService configurationService = context.getBean(ConfigurationService.class);
return configurationService.getString(key);
}
public static <T> T bean(Class<T> beanType) {
return context.getBean(beanType);
}
}
You can create a method like in the example to give static access to Spring Beans or what you requested to get a String from your ConfigurationService.
Btw. I use this a lot in Vaadin applications because I don't want to make every component a Spring Bean.

BeanCreationException error when referencing configuration class inside a service class

I am trying to #Autowire a #Configuration class inside a #Service class. basically my #Configuration class contains mapping to my custom .properties file. When i try to autowire my configuration class inside my service class, BeanCreationException occurs. I am not sure what happen. Just followed the guide on creating Property classes from spring. There must be something i missed out.
Also, when i try to autowire #Configuration class to another #Configuration class, it runs smoothly
Currently, i know that, prop is always null because when i remove prop.getUploadFileLocation() call, everything will be fine. There must be something wrong during autowiring.
Here is my Service class
#Service
public class ImageService {
public static Logger logger = Logger.getLogger(ImageService.class.getName());
#Autowired
MyProperties prop;
private final String FILE_UPLOAD_LOCATION = prop.getUploadFileLocation() +"uploads/images/";
public void upload(String base64ImageFIle) throws IOException {
logger.info(FILE_UPLOAD_LOCATION);
}
}
Here is my Configuration class
#Data
#Configuration
#ConfigurationProperties (prefix = "my")
public class MyProperties {
private String resourceLocation;
private String resourceUrl;
public String getUploadFileLocation() {
return getResourceLocation().replace("file:///", "");
}
public String getBaseResourceUrl() {
return getResourceUrl().replace("**", "");
}
}
And here is where i can successfully use MyProperties
#Configuration
public class StaticResourceConfiguration implements WebMvcConfigurer {
#Autowired
MyProperties prop;
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler(prop.getResourceUrl())
.addResourceLocations(prop.getResourceLocation());
}
}
The issue is that you are trying to use an autowired field to set the value in an inline field assignment.
That means
private final String FILE_UPLOAD_LOCATION = prop.getUploadFileLocation() +"uploads/images/";
is executed before the prop is autowired, meaning it will always be null
The way to mitigate this would be to use constructor injection instead.
#Service
public class ImageService {
//Fine since you are using static method
public static Logger logger = Logger.getLogger(ImageService.class.getName());
//Not needed if you are only using it to set FILE_UPLOAD_LOCATION
//Allows field to be final
private final MyProperties prop;
//Still final
private final String FILE_UPLOAD_LOCATION;
//No need for #Autowired since implicit on component constructors
ImageService(MyProperties prop){
//Again not needed if you aren't going to use anywhere else in the class
this.prop = prop;
FILE_UPLOAD_LOCATION = prop.getUploadFileLocation() +"uploads/images/";
}
public void upload(String base64ImageFIle) throws IOException {
logger.info(FILE_UPLOAD_LOCATION);
}
}
See this question for why constructor is preferred over #autowired in general
If you need MyProperties bean to be created before StaticResourceConfiguration bean, you can put #ConditionalOnBean(MyProperties.class) as following. Spring will make sure MyProperties is there before processing StaticResourceConfiguration.
#Configuration
#ConditionalOnBean(MyProperties.class)
public class StaticResourceConfiguration implements WebMvcConfigurer {

Spring dependency injection with constructor arguments

I have spring boot, hibernate application and android application for client side. Also I am using java.net.Socket api for socket connection.
Before I was creating server socket like this new Server(12346); and everything was good enough. But now I need access to database from socket class e.g. with #Autowired UsersDao field, but of course it is null because Socket class is not visible by Spring Framework.
So how do I make dependency injection on Socket class using port as constructor argument and make UserDao non-null?
You can access the Spring Application Context from static method and use this static method to load your repository bean in your Server class instead of autowiring it.
You need to create the following classes (found here):
ApplicationContextProvider
#Component
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
public ApplicationContext getApplicationContext() {
return context;
}
#Override
public void setApplicationContext(ApplicationContext ctx) {
context = ctx;
}
}
SpringConfiguration
#Configuration
public class SpringConfiguration {
#Bean
public static ApplicationContextProvider contextProvider() {
return new ApplicationContextProvider();
}
}
And then your non-Spring managed Server class:
public class Server {
//your code
public void doUsersDaoStuff() {
UsersDao usersDao = (UsersDao) SpringConfiguration.contextProvider().getApplicationContext().getBean("UsersDao");
// Do your own stuff with UsersDao here...
}
}

How to get bean using application context in spring boot

I am developing a SpringBoot project and I want to get the bean by its name using applicationContext. I have tried many solution from web but could not succeed. My Requirement is that I have a controller
ControllerA
and inside the controller I have a method getBean(String className). I want to get instance of registered bean. I have hibernate entities and I want to get an instance of the bean by passing the name of class only in getBean method.
Please help if someone know the solution.
You can Autowire the ApplicationContext, either as a field
#Autowired
private ApplicationContext context;
or a method
#Autowired
public void context(ApplicationContext context) { this.context = context; }
Finally use
context.getBean(SomeClass.class)
You can use ApplicationContextAware.
ApplicationContextAware:
Interface to be implemented by any object that wishes to be notified
of the ApplicationContext that it runs in. Implementing this interface
makes sense for example when an object requires access to a set of
collaborating beans.
There are a few methods for obtaining a reference to the application context. You can implement ApplicationContextAware as in the following example:
package hello;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
#Component
public class ApplicationContextProvider implements ApplicationContextAware {
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public ApplicationContext getContext() {
return applicationContext;
}
}
Update:
When Spring instantiates beans, it looks for ApplicationContextAware implementations, If they are found, the setApplicationContext() methods will be invoked.
In this way, Spring is setting current applicationcontext.
Code snippet from Spring's source code:
private void invokeAwareInterfaces(Object bean) {
.....
.....
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
}
}
Once you get the reference to Application context, you get fetch the bean whichever you want by using getBean().
actually you want to get the object from the Spring engine, where the engine already maintaining the object of your required class at that starting of the spring application(Initialization of the Spring engine).Now the thing is you just have to get that object to a reference.
in a service class
#Autowired
private ApplicationContext context;
SomeClass sc = (SomeClass)context.getBean(SomeClass.class);
now in the reference of the sc you are having the object.
Hope explained well. If any doubt please let me know.
Even after adding #Autowire if your class is not a RestController or Configuration Class, the applicationContext object was coming as null. Tried Creating new class with below and it is working fine:
#Component
public class SpringContext implements ApplicationContextAware{
private static ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws
BeansException {
this.applicationContext=applicationContext;
}
}
you can then implement a getter method in the same class as per your need to get the bean. Like:
applicationContext.getBean(String serviceName,Interface.Class)
Using SpringApplication.run(Class<?> primarySource, String... arg) worked for me. E.g.:
#SpringBootApplication
public class YourApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(YourApplication.class, args);
}
}
As an alternative approach you can use ConfigurableApplicationContext to get bean of any class which is annotated with #Component, #Repository or #Service.
Let's say you want to get a bean of the class BaseComponent :
#Service
public class BaseComponent {
public String getMessage() {
return "hello world";
}
}
Now you can use ConfigurableApplicationContext to get the bean:
#Component
public class DemoComponent {
#Autowired
ConfigurableApplicationContext applicationContext;
public BaseComponent getBeanOfBaseComponent() {
return applicationContext.getBean(BaseComponent.class);
}
}
You can use the ApplicationContextAware class that can provide the application context.
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext ctx = null;
public static ApplicationContext getApplicationContext() {
return ctx;
}
#Override
public void setApplicationContext(final ApplicationContext ctx) throws BeansException {
ApplicationContextProvider.ctx = ctx;
}
/**
* Tries to autowire the specified instance of the class if one of the specified
* beans which need to be autowired are null.
*
* #param classToAutowire the instance of the class which holds #Autowire
* annotations
* #param beansToAutowireInClass the beans which have the #Autowire annotation
* in the specified {#classToAutowire}
*/
public static void autowire(Object classToAutowire, Object... beansToAutowireInClass) {
for (Object bean : beansToAutowireInClass) {
if (bean == null) {
ctx.getAutowireCapableBeanFactory().autowireBean(classToAutowire);
}
}
}
}
If you are inside of Spring bean (in this case #Controller bean) you shouldn't use Spring context instance at all. Just autowire className bean directly.
BTW, avoid using field injection as it's considered as bad practice.
One API method I use when I'm not sure what the bean name is org.springframework.beans.factory.ListableBeanFactory#getBeanNamesForType(java.lang.Class<?>). I simple pass it the class type and it retrieves a list of beans for me. You can be as specific or general as you'd like to retrieve all the beans associated with that type and its subtypes, example
#Autowired
ApplicationContext ctx
...
SomeController controller = ctx.getBeanNamesForType(SomeController)
Easy way in configration class call the BEAN annoted method . Yes u heard it right---- :P calling SpringBoot #Bean annoted method return the same bean from config .I was trying to call a logout in #predestroy method in config class from a bean and direcltly called the method to get the same bean .
P.S. : I added debug in the #bean annotated method but it didn't entered the method even when i called it.Sure to blame -----> Spring Magic <----
You can use ServiceLocatorFactoryBean. First you need to create an interface for your class
public interface YourClassFactory {
YourClass getClassByName(String name);
}
Then you have to create a config file for ServiceLocatorBean
#Configuration
#Component
public class ServiceLocatorFactoryBeanConfig {
#Bean
public ServiceLocatorFactoryBean serviceLocatorBean(){
ServiceLocatorFactoryBean bean = new ServiceLocatorFactoryBean();
bean.setServiceLocatorInterface(YourClassFactory.class);
return bean;
}
}
Now you can find your class by name like that
#Autowired
private YourClassfactory factory;
YourClass getYourClass(String name){
return factory.getClassByName(name);
}
Just use:
org.springframework.beans.factory.BeanFactory#getBean(java.lang.Class)
Example:
#Component
public class Example {
#Autowired
private ApplicationContext context;
public MyService getMyServiceBean() {
return context.getBean(MyService.class);
}
// your code uses getMyServiceBean()
}

Categories