Spring boot reading properties from a bean - spring-boot

I found an spring boot sample code in which properties are being injected directly with #Value.
The point is that those properties come from a bean which is not present actually in the code.
The annotations have this aspect:
#Value ("#{envPC['desktop.url']}")
private String url = "";
So I have a couple of questions:
1-how can I define env bean?
2-when defining the env bean, how can I modelate the correct structure for references like: desktop.url, desktop.port....
I hope the questions are clear.
Thanks in advance

Environment bean is implicitly defined within Spring context. Spring collects properties from multiple sources into this bean: JVM options, property files added via #PropertySource, etc.
Also it can be injected like any other bean:
#Autowired
private org.springframework.core.env.Environment environment;
More details can be found at https://docs.spring.io/ or in this nice article: http://www.baeldung.com/properties-with-spring

Related

Spring boot environment property returns null

I have a spring boot 2 app. I am trying to access my application properties file properties through spring Environment as well as #Value property, neither of them works.
#Autowired
Environment env;
logger.info(env.getProperty("app.environment"));
#Value("${app.environment}")
private String _env;
logger.info(_env);
app.environment=LOCAL
Looks like spring boot is not detecting application.properties file at all.
What am I doing wrong here, Thanks in advance
If the injected property is null, it most probably means your bean has not been created yet. Spring boot injects values to bean properties only after the bean has been created.
Here's a simple experiment to demonstrate this behavior:
#Value("${spring.application.name}")
private String instanceApplicationName;
public UserController(#Value("${spring.application.name}") String appNameInConstructor) {
System.out.println("Constructor app name: " + appNameInConstructor);
System.out.println("Instance application name: " + this.instanceApplicationName);
}
Which property would be null? instanceApplicationName or appNameInConstructor?
Yes, it's the instanceApplicationName property that's null because, the constructor is called first and the instance property has not been initialized yet. The appNameInConstructor correctly logs the application name.
So, where you reference the injected properties and how you inject them, both matter.
You can check the entire project here: https://github.com/nkumashi/springboot-webmvc-demo.

Implementation provided for BatchConfigurer is not connsidered when using #EnableBatchProcessing(modular=true)

I am developing a sample application that Spring Batch with Spring Boot. My requirement is:
Have my own implementation of BasicBatchConfigurer so that I can configure AsyncTaskExecutor and my own dataSource as I am using SAP HANA as DB for which databaseType is not supported.
I want to use #EnableBatchProcessing(modular=true) so that I can register multiple jobs and launch them with separate Child Context
I have added all the required configurations. Without setting modular=true the Job is Launched and works as expected. It initializes the beans defined from my implementation of BasicBatchConfigurer.
However, once modular=true is set, the beans from my implementation are not initialized.
The code is hosted here: https://github.com/VKJEY/spring-framework-evaluation
I debugged further into the issue:
Looks like, When we set modular=true, BatchConfigurationSelector uses ModularBatchConfiguration
In ModularBatchConfiguration, there's a field Collection<BatchConfigurer> configurers. This has been annotated as #autowired.
I assume that this field is auto initialized if I provided a implementation
of BatchConfigurer as it has been mentioned in the comments of ModularBatchConfiguration class as well
However, While debugging I realized that the above field is still null beacuse of which, It loads DefaultBatchConfigurer and follows the default flow.
My question is why is that field configurers not being initialized in ModularBatchConfiguration? Am I missing something?
I am using Spring boot 2.1.2.
My question is why is that field configurers not being initialized in ModularBatchConfiguration? Am I missing something?
You are hitting a lifecycle issue between Spring Boot custom auto-configuration that you defined in the META-INF/spring.factories file and Spring Batch configuration.
I debugged your code and here is how to fix the issue:
remove org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.job.data.persistence.config.AsyncBatchConfigurer
from META-INF/spring.factories file. This is not needed as Spring Batch
will detect the AsyncBatchConfigurer when it is declared as a bean.
You can even remove this spring.factories file
remove #ConditionalOnMissingBean(BatchConfigurer.class) from AsyncBatchConfigurer:
Since you declared this class as a #Configuration class, it will also be defined as a bean of type BatchConfigurer and will be detected by ModularBatchConfiguration
With these two changes, the field configurers in ModularBatchConfiguration is correctly autowired with your AsyncBatchConfigurer.
As a side note, you don't need the AsyncBatchConfigurer#configurers method as Spring will do the work of injecting all BatchConfigurer beans in ModularBatchConfiguration.
Hope this helps.

Spring mvc : Access properties file value in controller without #Value

I have a properties file for messages in my Spring application.I want to access these value directly in controller.How can i do this ?.
Note: I don't want to use #Value annotation to store data in another variable.
You can reference this question and answer regarding accessing files directly within controller.
It is what i used to implement mine.
Accessing multiple property files with #PropertyResource in spring
As M.Deinum suggested already, you should have a MessageSource bean definition if the purpose of the properties file is to externalize messages. A message source is automatically picked by the application context, meaning it is available for injection in every other bean. You can autowire it for example in your controller:
#Autowired
private MessageSource messageSource;
and then use its methods to access any message in any locale

Injected bean reset to NULL in the Aspect

I am new Spring AOP and Aspectj. I have seen various posts related to injected bean in an aspect being null and I have run into a similar problem. I am still not clear how I should proceed to get past the problem I am currently encountering.
Issue: Currently we are using Spring 3.2.3 and all injection is through Annotation. In my case, the dependent bean is injected properly by Spring but at the point of execution the injected bean is NULL. BTW, this doesn't happen all the time but what I can say is the stack trace when it fails and when it succeeds is slightly different. When the injected bean is not null (I can successfully use the injected bean service), the call to the before advice (in the aspect) always happens before the target method is called as it should.When the injected bean is NULL, the call to the aspect is from the first statement of the target method. At this point, I think another aspect is instantiated and has no reference to the injected bean. Here is the aspect I have created:
#Component
#Aspect
public class Enable{
private NameService nameService;
#Autowired
public void SetNameService(NameSerice service){
// service is injected properly
this.nameSerice = service;
}
#Before("* *.*(..)")
public void callBefore(JoinPoint jp){
//sometimes nameService is null and sometimes it not not
this.nameService.lookup(...);
}
}
Examining the various posts, one way to get around this (as suggested in the post) is to configure the aspect in the XML configuration file and use the factory-method ="aspectOf" and in the configuration inject the reference to the NameService bean as a property. Our whole project uses Annotation based injection (as stated earlier). Assuming I can still configure the above aspect in an XML configuration file, how can I get the reference NameService bean Id so that I can add it to the configuration. I also saw a post related to using Configurable annotation but I assume that is for objects created outside the Spring IOC.
Currently, the aspects are woven using Aspectj compile option in pom.xml. Our root-context.xml contains the entry context:annotation-config and the aspect is injected into Spring IOC because component-scan is turned on for the folder where the aspect resides. Any help will be appreciated
This is well common error when use aspects in spring, you should add
<context:spring-configured/>
and
<aop:aspectj-autoproxy />
also add
#Configurable
#Aspect
public class Enable
To your appContext.xml
aspectOf is another style to do the above but I prefer use the nature of context.
It might be too late to answer this question. But i have come across the same situation and i fixed it as below.
1) Have a setter and getter for "NameService" in your aspect class.
2) Mark "NameService" with #Component ("nameService")
3) Configure "nameService" in xml configuration using setter injection.
4) Re-Start your server after making changes.
This should resolve the problem of getting null for "NameService" in aspect.

Spring InitializingBean interface

In XML file in spring we have two bean with different id but same class. They have the same properties offcourse. Now I have InitializingBean interface and in afterPropertySet() I am just printing the value of properties.
Its printing the values two times for me?
According Spring Documentation:
afterPropertySet()
Invoked by a BeanFactory after it has set all bean properties supplied (and satisfied BeanFactoryAware and ApplicationContextAware).
So the short answer on your question is: yes
Spring doesn't manipulate classes or object. Spring manipulates Bean Entity. It is the simplest object manipulated by Spring IOC. Bean has additional behaivior rules introduced by Spring.
If you create two beans for example with Singleton scope and not Lazy initializated Spring creates two instances of your class.
Probably you are calling this Class also invoking a Test or by launching a Integration test like this . check the breakpoints , if you are using SpringRunner, try to mock the component

Resources