Not able to get application context object using ApplicationContextAware - java

i have a microservice application developed using spring boot. i also have a project under under the same application which contains some java classes (non spring classes). i am trying to use some of the beans which are available in the spring container in this non java class using the ApplicationContextAware approach. when i debug the code during the bootrun, i can see the setApplicationContext(ApplicationContext ctx) is getting call and the context is getting set.
when from inside my non spring java class when i tried to get the instance of the context using the public static getApplicationContext(), i am getting null for context.
below is the sample example i had used.
#Component
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
public ApplicationContext getApplicationContext() {
return context;
}
#Override
public void setApplicationContext(ApplicationContext ctx) {
context = ctx;
}
}
this is how i try to get the instance
ApplicationContext c = ApplicationContextProvider.getApplicationContext();
i am not able to figure it out what is missing here, as i am using spring boot, i dont think there is a need to configure any bean in xml.

This worked for me with your code. I could get the application start time after fetching the provider from the context.
#RestController
public class SampleController {
#Inject
ApplicationContextProvider provider;
#RequestMapping(value = "..", method = RequestMethod.GET)
public ResponseEntity<String> someMethod() throws IOException {
ApplicationContext c = provider.getApplicationContext();
System.out.println(c.getApplicationName());
c.getStartupDate()
}
}

Related

Run spring boot without #SpringBootApplication annotation as jar library in another project

I'm trying to use #autowired annotation in a spring boot project that's not started by main method with #SpringBootApplication annotation. Instead, i did created a jar of that spring project and i'm using that jar as an external jar in a legacy project (non-spring project).
As result i can't get ApplicationContext and all beans managed by spring when you run application from main method are null.
Is that possible to use Spring boot project as a .jar without run main method??
public class RetrieveSubscriberType {
public RetrieveSubscriberType() {
ApplicationContext appCtx = ApplicationContextUtils
.getApplicationContext();
this.subscriber = (SubscriberDAOImpl)appCtx.getBean("subscriber");
}
appCtx always null
#Configuration
public class ApplicationContextUtils implements ApplicationContextAware {
private static ApplicationContext ctx;
#Override
public void setApplicationContext(ApplicationContext appContext)
throws BeansException {
ctx = appContext;
}
public static ApplicationContext getApplicationContext() {
return ctx;
}
}
ApplicationContextUtils where method setApplicationContext is not called
From the provided docs
You might need to bootstrap your #Configuration classes via AnnotationConfigApplicationContext
#Configuration classes are typically bootstrapped using either AnnotationConfigApplicationContext or its web-capable variant, AnnotationConfigWebApplicationContext.
A simple example with the former follows:
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class);
ctx.refresh();
MyBean myBean = ctx.getBean(MyBean.class);
// use myBean ...

Pretty way to inject Spring properties to object not managed by Spring

I have a Spring application and I'm using a third party library. There's no constructor, everything is configured and instantiated inside of this library.
I can add some custom behavior by creating a class. What I need is to add my Spring properties to this class.
Here's the class:
public static class CustomClass implements ExternalClass {
#Override
public Object create() {
//Here I would like to inject my properties.
}
}
I'm looking for a pretty approach.
Use the #Configurable annotation on this class to make it possible to inject Environment or directly a property via #Value as usual. This is the documentation of this annotation.
#Configurable
public static class CustomClass implements ExternalClass {
//..
//inject Environment to get property or via #Value as usual
//..
}
create this class in your project
#Component public class IOC implements ApplicationContextAware {
private static ApplicationContext ctx;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.ctx = applicationContext;
}
public static ApplicationContext getCtx() {
return ctx;
}
}
then call
Environment environment = IOC.getCtx().getEnvironment();
in the create method to get your properties

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()
}

Insert bean from applicationContext into POJO

I have all of my DAO's as beans in my applicationContext. Now this works great for autowiring these objects into my controllers to make database calls. However, given that I have embedded objects within some of my POJO's (Example: User class has list of pendingsurvey objects, list of appointment objects, etc) and don't want to grab these embedded objects when I grab the main object (Example: In a page with a list of users I don't need to know their pendingsurveys or appointments), I had set it up so that if the embedded object is null, go to the database to get the data. However, apparently #Autowire doesn't work in this case because the POJO's are not a Spring controlled object or something.
So question now is, how can I get a bean from applicationContext to use in my POJO's? I'm not that good with Spring so specific instructions would be greatly appreciated..
I've tried this but it gives me a bunch of injection dependency errors:
/* applicationContext.xml */
<bean id="userDao" class="UserDao" scope="singleton">
<property name="connectionWrapper" ref="connectionWrapper" />
</bean>
/* User.java - I tried putting in constructor and in the getter for userDao */
ApplicationContext ctx = AppContext.getApplicationContext('applicationContext.xml');
UserDao userDao = (UserDao) ctx.getBean("userDao");
Got it to work, same concept as Ric Jafe's answer but different implementation of it (Source: http://blog.jdevelop.eu/?p=154):
Made this class:
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext ctx = null;
public static ApplicationContext getApplicationContext() {
return ctx;
}
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
// Assign the ApplicationContext into a static method
this.ctx = ctx;
}
}
Added this line into applicationContext.xml:
<bean id="applicationContextProvider" class="org.ApplicationContextProvider"></bean>
Called it in my POJO with:
ApplicationContext applicationContext = ApplicationContextProvider.getApplicationContext();
if (applicationContext != null && applicationContext.containsBean("keyName")) {
object = (Object) applicationContext.getBean("keyName");
}
Thanks for all the help guys.
When you load a context like that you are creating a new context, a copy of what was created when the application loaded. To access the same context that your application is using, you have several options, documented here: http://mythinkpond.wordpress.com/2010/03/22/spring-application-context/
For ease of access I'll copy/paste the one that most likely you want to use:
public class MyClass implements ApplicationContextAware {
static final long serialVersionUID = 02L;
ApplicationContext applicationContext = null;
public void doSomething(){
if (applicationContext != null && applicationContext.containsBean("accessKeys")){
MyBean beanA = (MyBean) applicationContext.getBean("mybean");
//Do something with this AccessBean
}
return null;
}
#Override
public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
System.out.println("setting context");
this.applicationContext = applicationContext;
}
}
Notice the implements ApplicationContext.
This tells the Spring framework you need the Application Context in this class.. So it autowires it to the applicationContext variable. For this to happen you also need the setter method. Then you can just use it and get your beans. Good coffee :)
P.S. - If you need the context in other classes, you can pass the applicationContext variable to them or use the same method. This way you only have 1 context at all times, containing your beans.

Categories