I have a problem with #Autowired property in #Configuration bean.
I have a bean similar to the one below:
#Configuration
public class MyConfig {
#Autowired MongoTemplate mongoTemplate;
#Bean
MongoDbMetadataStore indexMetadataStore() {
return new MongoDbMetadataStore(mongoTemplate, "index");
}
}
and ... mongoTemplate is null while creating indexMetadataStore bean (checked with debugger). Unfortunately I cannot provide entire project structure, it is large (it has ~5 XML config files and around 20-30 #Configuration beans) and my bet is that there could a circular reference or something of sort.
However, this mongoTemplate bean is created earlier and injected to other beans (also checked with debugger), so at this point mongoTemplate is fully created and I cannot understand why it is not injected and left null.
Any ideas where I should look?
Ok, I found out a problem. I will describe it here, so that perhaps someone else may find this answer useful and save precious time resolving it :).
It turned out that there was a circular reference and Spring was doing its best to initialize and use not-fully-initialized config objects. There were config1 and config2 beans (both #Configuration) that used objects from each other.
It is interesting to know that in such a situation Spring tries to initialize #Resource, #Autowired and #Value in the following order:
#Resource is initialized first, in the order that objects were declared in the #Configuration bean
#Value is treated as #Autowired. Hence, #Value and #Autowired are initialized in the order of appearance AFTER all #Resource beans are initialized.
It is important to understand the above order, because your beans and circular reference may rely on #Value settings and such setting may still be null while creating a resource referenced from other config bean.
However, the best strategy is to avoid circular references and finally that is what I did - put offending resources to new, third, config bean.
The order statement seems to be true. I have a number of #Autowired properties in my #Configuration bean. Those at the end of the list appear as null when trying to use them in my #Bean.
#Configuration
public class MyConfig {
#Autowired
private MyClass myClass;
#Autowired
private MyClass2 myClass2;
...
#Autowired
private MyArgument1 myArgument1;
#Autowired
private MyArgument2 myArgument2;
#Bean(name = "myList")
public List<MyInterface> getMyList() { //given MyArgument1 & MyArgument2 implement MyInterface
List<MyInterface> myList= new ArraList<MyInterface>();
myList.add(myArgument1); //resolved as null
myList.add(myArgument2); //resolved as null
return myList;
}
}
If I put them in the top of the list they are resolved properly. So.. how many should I count on being properly resolved? Need a better approach.
This is working
#Configuration
public class MyConfig {
#Autowired
private MyClass myClass;
#Autowired
private MyClass2 myClass2;
...
#Bean(name = "myList")
public List<myInterface> getMyList((#Qualifier("myArgument1") MyInterface myArgument1, (#Qualifier("myArgument2") MyInterface myArgument2) { //given myArgument1 & myArgument 2 are properly labeled as #Component("myArgument1") & #Component("myArgument2")
List<myInterface> myList= new ArraList<myInterface>();
myList.add(myArgument1); //resolved!
myList.add(myArgument2); //resolved!
return myList;
}
}
This seems to implement the right dependency
Related
I am seeing a weird behavior with injecting Jackson ObjectMapper with Spring Boot 2.3.4.RELEASE.
I have both spring-boot-starter-web & spring-boot-starter-json in my maven dependencies. Yet when i auto-wire ObjectMapper in one of my #Service classes, it does not get injected & the reference is null.
I then tried creating & returning one manually in an #Primary #Bean bean method of a #Configurationclass but still with the same result.
I know the #Configuration is working fine since other bean methods in it are used to inject other objects correctly. In addition i also added a log statement inside the bean method that returns the ObjectMapper instance which is also getting logged, yet the reference on the #Service class is STILL null? (i also tried adding #AutoConfigureAfter(JacksonAutoConfiguration.class) in vain)
Anyone else faced this or knows what's going on here? please throw light..
Thanks
EDIT (10/22): Below is a snippet of the #Service class,
#Lazy
#Service
#EnableSpringConfigured
public class SampleServiceSingletonService {
private static final Logger LOGGER = LoggerFactory.getLogger(SampleServiceSingletonService.class);
#Autowired
protected ThreadPoolTaskScheduler threadPoolTaskScheduler;
#Autowired
private ObjectMapper objectMapper;
#EventListener({ApplicationReadyEvent.class})
private void initOnAppReady() {
LOGGER.info("No need to create ObjectMapper instances, most customizations can be set/overriden in application.properties, look at the one here for reference");
LOGGER.info("Injected ObjectMapper: {}", objectMapper);
LOGGER.info("Init on app ready complete..");
//...
}
EDIT 2 (10/22): For others who face this,
The problem appears to be (thanks to #M. Deinum below) that the instantiation and/or injection doesn't seem to happen at the time the ApplicationReadyEvent is fired & its event handlers are invoked. That seems strange to me for two reasons, one is as per the docs, the event is "published as late as conceivably possible to indicate that the application is ready to service requests...since all initialization steps will have been completed by then" and second i have not seen this behavior with other injections of other objects till now so i never suspected this as a cause. Below is a snippet where i see the injection working,
#Lazy
#Service
public class SampleServiceSingletonService {
private static final Logger LOGGER = LoggerFactory.getLogger(SampleServiceSingletonService.class);
#Autowired
public ThreadPoolTaskScheduler threadPoolTaskScheduler;
#Autowired
public ThreadPoolTaskExecutor threadPoolTaskExecutor;
#Autowired
public ObjectMapper objectMapper;
#EventListener(ApplicationReadyEvent.class)
private void initOnAppReady() {
// Its null here..
//LOGGER.info("The Injected ObjectMapper: {}", objectMapper);
LOGGER.info("Init on app ready complete..");
runAsync();
}
#Async
public void runAsync() {
LOGGER.info("This is run asynchronously.");
// Its no longer null here
LOGGER.info("The Injected ObjectMapper: {}", objectMapper);
}
}
Thanks
You have marked your bean with #Lazy. When put on a type what will happen is that a lazy proxy will be created for the object. In this case a class based proxy will be created (no interface on the class) and for this a subclass will be created to add the lazy behavior.
However due to the fact that your method is private there is no way to override this method in the dynamic created class and thus it will be called on the proxy instead or relaying it through to the actual object. The proxy object will not have any dependencies injected, at least not the private fields.
So to fix, make your method protected or public so it can be properly subclasses and overridden. Or remove the #Lazy if you don't need it.
See this blog for a more detailed explanation.
You should add setter and getter to your
private ObjectMapper objectMapper;
so Spring is able to assign it a value
what is the main difference between injecting objects with #Autowired and injecting without it ?
I know that spring will initialize the bean , but what it is really offering ?
There are several ways to configure Spring beans and inject dependencies using Spring. One way is by using constructor injection, where the constructor of your Spring bean has arguments which are the dependencies that should be injected:
#Component
public class MyBean {
private final SomeDependency something;
#Autowired
public MyBean(SomeDependency something) {
this.something = something;
}
}
However, since Spring 4.3, it is not necessary anymore to use #Autowired on such a constructor (click link for Spring documentation). So you can write it without the #Autowired:
#Component
public class MyBean {
private final SomeDependency something;
public MyBean(SomeDependency something) {
this.something = something;
}
}
This will work exactly the same as the code above - Spring will automatically understand that you want the dependency to be injected via the constructor. The fact that you can leave out #Autowired is just for convenience.
So, to answer your question: there is no difference.
#Autowired (so the injection) in some situation cannot be used, an example is if your autowired bean not ready because of some async stuff but in the target bean you want to use that.
So in this situation do not use inject (#Autowired) it is better to inject the ApplicationContext and in the exact moment get your bean from there by name or by class (there is a lot off possibilities there).
You can consider the #Autowired with the #Lazy annotation too.
I am absolutely new to TestNG, Spring framework etc. and I'm trying to use the annotation #Value access to configuration file via the #Configuration annotation.
All I'm trying to achieve here is to make the console write out "hi" from the config file accessing the value via #Value. I must be obviously missing the whole point of the #Value annotation (or #Autowired or some other annotations) as all I'm gettting is java.lang.NullPointerException.
I have the following three files (reduced to the absolute minimum):
config.properties
a="hi"
TestConfiguration.java
#Configuration
#PropertySource("config.properties")
public class TestConfiguration {
#Value("${a}")
public String A;
}
TrialTest.java
public class TrialTest {
#Autowired
private TestConfiguration testConfiguration;
#Test
public void test() {
System.out.println(testConfiguration.A);
}
}
Thanks a lot.
Try annotate your test class with these:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes={TestConfiguration.class})
[Edit] sorry I didn't see that OP was using TestNG. The essential point is still that the problem is caused by Spring not being bootstrapped. In TestNG that can be done via extending AbstractTestNGSpringContextTests.
Make sure that in your config, you are declaring the PropertySourcesPlaceholderConfigurer bean which can resolve the #Value expressions. Declare this bean:
#Configuration
#PropertySource("config.properties")
public class TestConfiguration {
#Value("${a}")
public String A;
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer()
{
return new PropertySourcesPlaceholderConfigurer();
}
}
Note that you do not have to do anything with this bean, just by declaring it, it will allow the #Value annotation expressions to work as expected.
You can either redundantly declare this bean in every class that uses a #Value annotation, but that would be bad practice/style as it would keep overwriting the bean in each new declaration. Instead, place this bean at the top most config which imports other configs using #Value and you can recycle the PropertySourcesPlaceholderConfigurer bean from the one place.
I have web application with several configuration classes.
#Configuration
public class ConfigA {
#Bean(name = "bean_1")
public MyBean getBean1() { /* Some code is here */ }
#Bean(name = "bean_2")
public MyBean getBean2() { /* Some code is here */ }
/* ... */
#Bean(name = "bean_99")
public MyBean getBean99() { /* Some code is here */ }
}
#Configuration
public class ConfigB {
public OtherBean getOtherBean() { /* Some code is here */ }
}
Đ•ach bean of class MyBean is registered in some global context when constructor is called. And OtherBean bean consumes this global context to get all instances of MyBean class. But spring creates OtherBean earlier then several of MyBean beans and I do not know how I can change this behavior.
PS:
I do not want to inject all MyBean beans directly (explictly) in OtherBean, there are many MyBean beans.
Now I have a solution: declare annotation #DependsOn({ "bean_1", "bean_2" .... "bean_99" }) on class ConfigB, but I think it is inconvenient (it is almost the same point 1).
I think a solution could be force spring to create all declared beans (bean_1, ...) as soon as this configuration class (ConfigA) was discovered.
add #Autowired List list; field to your configuration? This will inject all registered beans to a list so hopefully spring checks somehow where are those beans created.
You can add the #Lazy here, this is the javadoc
If this annotation is not present on a #Component or #Bean definition, eager initialization will occur. If present and set to true, the #Bean or #Component will not be initialized until referenced by another bean or explicitly retrieved from the enclosing BeanFactory. If present and set to false, the bean will be instantiated on startup by bean factories that perform eager initialization of singletons.
Let's say we have a class:
public class MyClass {
#Autowired private AnotherBean anotherBean;
}
Then we created an object of this class (or some other framework have created the instance of this class).
MyClass obj = new MyClass();
Is it possible to still inject the dependencies? Something like:
applicationContext.injectDependencies(obj);
(I think Google Guice has something like this)
You can do this using the autowireBean() method of AutowireCapableBeanFactory. You pass it an arbitrary object, and Spring will treat it like something it created itself, and will apply the various autowiring bits and pieces.
To get hold of the AutowireCapableBeanFactory, just autowire that:
private #Autowired AutowireCapableBeanFactory beanFactory;
public void doStuff() {
MyBean obj = new MyBean();
beanFactory.autowireBean(obj);
// obj will now have its dependencies autowired.
}
You can also mark your MyClass with #Configurable annotation:
#Configurable
public class MyClass {
#Autowired private AnotherClass instance
}
Then at creation time it will automatically inject its dependencies. You also should have <context:spring-configured/> in your application context xml.
Just got the same need and in my case it was already the logic inside non Spring manageable java class which had access to ApplicationContext. Inspired by scaffman.
Solved by:
AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory();
factory.autowireBean(manuallyCreatedInstance);
I used a different approach. I had spring loaded beans that I wanted to call from my extended classes of a third-party library that created its own threads.
I used approach I found here https://confluence.jaytaala.com/display/TKB/Super+simple+approach+to+accessing+Spring+beans+from+non-Spring+managed+classes+and+POJOs
In the non-managed class:
{
[...]
SomeBean bc = (SomeBean) SpringContext.getBean(SomeBean.class);
[...]
bc.someMethod(...)
}
And then as a helper class in the main application:
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
#Component
public class SpringContext implements ApplicationContextAware
{
private static ApplicationContext context;
public static <T extends Object> T getBean(Class<T> beanClass)
{
return context.getBean(beanClass);
}
#Override
public void setApplicationContext(ApplicationContext context) throws BeansException
{
SpringContext.context = context;
}
}
I wanted to share my solution that follows the #Configurable approach as briefly mentioned in #glaz666 answer because
The answer by #skaffman is nearly 10 years old, and that does not mean not good enough or does not work
The answer by #glaz666 is brief and didn't really help me solve my problem but, did point me in the right direction
My setup
Spring Boot 2.0.3 with Spring Neo4j & Aop starts (which is irrelevant anyway)
Instantiate a bean when Spring Boot is ready using #Configurable approach (using ApplicationRunner)
Gradle & Eclipse
Steps
I needed to follow the steps below in order to get it working
The #Configurable(preConstruction = true, autowire = Autowire.BY_TYPE, dependencyCheck = false) to be placed on top of your Bean that is to be manually instantiated. In my case the Bean that is to be manually instantiated have #Autowired services hence, the props to above annotation.
Annotate the Spring Boot's main XXXApplicaiton.java (or the file that is annotated with #SpringBootApplication) with the #EnableSpringConfigured and #EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)
Add the dependencies in your build file (i.e. build.gradle or pom.xml depending on which one you use) compile('org.springframework.boot:spring-boot-starter-aop') and compile('org.springframework:spring-aspects:5.0.7.RELEASE')
New+up your Bean that is annotated with #Configurable anywhere and its dependencies should be autowired.
*In regards to point #3 above, I am aware that the org.springframework.boot:spring-boot-starter-aop transitively pulls the spring-aop (as shown here mavencentral) but, in my case the Eclipse failed to resolve the #EnableSpringConfigured annotations hence, why I explicitly added the spring-aop dependency in addition to the starter. Should you face the same issue, just declare the dependency or go on adventure of figuring out
Is there a version conflict
Why the org.springframework.context.annotation.aspect.* is not available
Is your IDE setup properly
Etc etc.
This worked for me:
#Configuration
public class AppConfig {
#Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
See more information: https://docs.spring.io/spring-javaconfig/docs/1.0.0.m3/reference/html/creating-bean-definitions.html
Found the following way useful for my use case. Sharing here for reference, credit goes to the blogger entirely. This creates a static field and populates that from Spring and then provides a public static method which returns the field populated above.
https://sultanov.dev/blog/access-spring-beans-from-unmanaged-objects/