how to reload configuration object at runtime in spring mvc - java

i have a configuration class FTPSchedullingConfiguration which is initialise at app instantiation and get data from table for Starting a scheduler on given Scheduling Expression.
And also my question are not Duplicate as Reloading/Refreshing Spring configuration file without restarting the servlet container like this because i have no any XML File, my application is based on annotation and here Every classes are compiled in .class formate so we can`t change any code at runtime.
#Configuration
#EnableScheduling
public class FTPSchedullingConfiguration {
#Autowired
private FTPTransferServiceInterface ftpTransferServiceInterface;
#Bean
public String getCronFTPTransferValue()
{
return ftpTransferServiceInterface.getFTPTransferById((long) 1).getTransferCroneTime();
}
#Scheduled(cron="#{#getCronFTPTransferValue}")
public void ftpTransfer() {
ftpTransferServiceInterface.transferFTPRecording();
}
}
But when i change the Schedule Expression of table then no changing on scheduled time. if i restart server then changed Expression load.
by using updateFTP(),
#RequestMapping(value= {"/updateFTPTransfer"})
private String updateFTP(...){
ftpTransferServiceInterface.updateFTP(ftpDomain);
//here i want to change the value of #Scheduled
}
my actual need like when i changed Expression value in table by updateFTP(...){...} at that time also my schedulling value changed (OR) Refreshed FTPSchedullingConfiguration class.
Thanks in Advance.

Related

field annotated with `#value` is not initialized in mongock configuration

I need to assure data migration using mongock.
The #ChangeUnit class holds the logic for migration. It has a field annotated with #Value which is always null, even though I properly initialized in application.properties:
mongock.migration-scan-package=my.package
login-secret=test
Then the MigrationConfiguration looks as follows:
#ChangeUnit(id = "test", order = "001", author = "test")
#RequiredArgsConstructor
#Configuration
public class InitUsersChangeLog {
private final MyService service;
private final MongoTemplate template;
#Value("${login-secret}")
private String LOGIN;
#Execution
public void initUser() {
service.create(User.builder().login(LOGIN).build());
}
}
Main class:
#EnableMongock
#SpringBootApplication
public class MailServiceApplication {...}
My assumption is that this value is not injected properly into the MongockConfiguration bean. I tried to configure the bean manually (without using mongock.migration-scan-package=my.package) in the properties, but with no success.
As Mongock currently doesn't support #Value annotation you can try to use getProperty method from Environment bean. Environment bean can be injected same as other beans using constructor or Lombok annotations.
You want to change this:
#Value("your.key.property")
to that:
private final Environment env;
public void method(){
env.getProperty("your.key.property")
}
Mongock currently no supports #value injection via field o method parameter. We will provide that in a future minor release within version 5, but we can't give you dates, yet.
Extending MichalJ's answer, which is absolutely valid. I would like to add that the changeUnits are not retrieved by Mongock via Springboot, they are processed by Mongock independently. So the annotation #Configuration, #Component, etc. won't be taken into account and they could even be damaging.
Related to that, this code won't work, at least not in a near future:
#Value("${login-secret}")
private String LOGIN;
First, as said, Mongock doesn't support value currently, but the first approach will require the constructor parameter to have that #Value("${login-secret}"), not at the field level.

How to Lazy load all the Spring beans whether it is defined by #Bean or #Component in Springboot 2.2

I am writing a spring application which is interactive and basically handles lots of commands like create, list, update, delete various types of resources.
For now, just assume a single run of the application handles only a single command and the program exits.
For all the classes to validate command, execute the command, required factory classes for each resource there is a separate class and each class is annotated with #Component annotation for spring to manage all the components.
There are also some of the manually defined beans by #Bean method.
Now that my application first identifies what kind of command is executed (create, delete, list, update, etc), I want the only beans of that command to be created and Autowired wherever required (after taking command from user) and I want to avoid the creation of dozens of beans related to other commands.
On searching, I came to know about Lazy instantiation of Beans that spring provides.
However, I am not sure if it is the weapon I am searching for.
What I tried
Very first I found #Lazy annotation, but since I want to lazily load all the Beans, I don't want to write #Lazy everywhere in each class.
Then I found setting below property in application.yml does the work.
spring:
main:
lazy-initialization: true
I tried that but still, it is not lazily creating the beans.
My application.yml files looks like this
spring:
main:
lazy-initialization: true
My main SpringBootApplication file looks like this:
#Slf4j
#SpringBootApplication
public class SpringBootApplication {
public static void main(String[] args) {
System.out.println("Loading Application...");
ApplicationContext context = SpringApplication.run(SpringBootApplication.class, args);
final AtomicInteger counter = new AtomicInteger(0);
log.info("**************** START: Total Bean Objects: {} ******************", context.getBeanDefinitionCount());
Arrays.asList(context.getBeanDefinitionNames())
.forEach(beanName -> {
log.info("{}) Bean Name: {} ", counter.incrementAndGet(), beanName);
});
log.info("**************** END: Total Bean: {} ******************", context.getBeanDefinitionCount());
}
}
My other classes looks like this:
#Component
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class MyClass1 implements ResourceCreator<MyClass2, MyClass3> {
private final RequestValidatorImpl requestValidator;
private final ResourceCreator resourceCreator;
#Override
public MyClass2 toImplementFunction(MyClass3 myclass3) {
//logic
}
On running the application, It prints all the classes where I annotated #Component as well as beans created by #Bean method.
I have also tried using below in Application.properties but still no use.
spring.main.lazy-initialization=true
Also, if you wish, please comment on whether I should use #Component for each Class like I am using or not and what is better practice instead.
I think you misunderstood the meaning of the lazy flag you are passing,
It means that the object will be created only when it is invoked but it does not say that it will not scan that package. Spring will scan all packages and store bean definition names but it will create the objects only when it is invoked, if you have passed the lazy flag to it.
You can verify this behaviour by checking the number of beans created when you pass the lazy flag as true and false.
you can check it as given below
ApplicationContext context = SpringApplication.run(SpringBootApplication.class, args);
System.out.println("count:"+context.getBeanDefinitionCount());
Edit on Apr/7th 2020 start
Another way to do that is create a constructor and use that to inject the autowired properties and print out a log when they enter the constructor.
I did the same in a sample project and below is he result, first one is for eager initialization and next one for lazy.
spring.main.lazy-initialization=false
Application logs
Inside Constructor
calling bean
inside bean method
spring.main.lazy-initialization=true
Application logs
calling bean
Inside Constructor
inside bean method
Edit on Apr/7th 2020 end
Please mark this as answered if I answered your question.
Thank you
Long story short:
For anyone wanting to lazily initialize their whole Spring Boot context, setting this property to true is the way to go:
spring.main.lazy-initialization=true
Pro tip:
It can be used in combination with the #Lazy annotation, set to false; so all the defined beans will use lazy initialization, except for those that we explicitly configure with #Lazy(false).
In such a way, the lazy initialization becomes opt-out instead of the default opt-in.

How to instantiate Spring boot Repository under standalone evironment?

all,
I am using spring boot in my project. It is great.
My project has a part of it that operates on database periodically(with a timer), and not in response to a http request.
It's periodically queries a sensor(a lot of sensors) and collects temperature readouts, and stores the readouts into database.
Before storing it into database, the readout number is compared to a warning threshold to test if a warning should be generated.
The threshold number is to be queried(complicated) out from database, too.
I have a ThresholdRepository extending JPAResository for this query, so I want to use it in this scenario.
My question is: Could I use #Autowire to make spring boot generate ThresholdRepository instance for me? If not, how to instantiate ThresholdRepository in this timer thread?
I find some code at :http://www.yjs001.cn/java/spring/33161827667841434606.html
unfortunately, the code is outdated and RepositoryMetadata has no getDomainClass and I don't know which alternative should be used.
Please someone help me out.
Any recommendation is appreciated.
The repository I mentioned is as following:
public interface ThresholdInfoRepository extends JpaRepository<ThresholdInfo, Long> {
ThresholdInfo findOneByGatewayIdAndNodeAddrAndChannel(Long gatewayId, Byte nodeAddr, Byte channel);
List<ThresholdInfo> findByGatewayId(Long gatewayId);
}
It's short, but does a lot of work.
Yes, you can,
You have to #EnableJpaRepositories for your repositories to become a bean.
Then, to be able to autowire it, your TimerTask needs to be a Spring Bean as well. You could use spring-tasks https://spring.io/guides/gs/scheduling-tasks/
#SpringBootApplication
#EnableScheduling
#EnableJpaRepositories
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class);
}
}
#Component
public class UpdateTask {
#Autowired
ThresholdInfoRepository thresholdInfoRepository;
#Scheduled(fixedRate = ...)
public void updateSensor() {
thresholdInfoRepository.find(...)
readoutRepository.save(...);
}
}
Spring boot will start a timer thread to execute your scheduled method.

Depending on a Spring project from a non-Spring project

I've got two Java applications that I have to combine. One is Spring, and methods within it need to be called by the second, an Elasticsearch plugin (that I don't think can be turned into a Spring app as it already uses some form of Guice for dependency injection).
The Spring class I need to call looks like:
#Component
public class DataServiceController {
//This is defined within a #Config
#Autowired
DataTypesMap dataTypesMap;
/**
* Create an item in the data platform
*/
public ItemCreatedResponse createItem(String data, String dataType)
throws IOException {
ProcessStrategy dataStrategy = dataTypesMap.get(dataType);
return dataStrategy.add(data);
}
If I just add this project as a Maven dependency within the ES plugin, the Autowired dataTypesMap is always null (which is to be expected as nothing in the Elasticsearch plugin will be telling it how to autowire).
What can I do here?
You can use a setter method for your autowired fields, then sets the value.
#autowired
public void setDataTypesMap (DataTypesMap dataTypesMap ){
this.dataTypesMap = dataTypesMap ;
}
In your application you can not autowired the bean, but you can set it.
myBean.setDataTypeMap();
The second option is initiate a the context of the spring application inside the non-spring application.
You can see how to do it here.
http://www.springbyexample.org/examples/intro-to-ioc-creating-a-spring-application.html

Update values on properties file on Runtime

I've configuration as below:
#Configuration
public class PropertyConfiguration {
#Bean
#Profile("local")
public static PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() {
PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer();
configurer.setLocation(new FileSystemResource("path/to/resources/app-local.properties"));
configurer.setIgnoreUnresolvablePlaceholders(true);
return configurer;
}
}
My app-local.properties file contains values as:
cache.time.milliseconds=1000
So, I'm accessing the value as:
#Value("${cache.time.milliseconds}")
private long cachingTime;
I'm getting the correct value.
System.out.println(cachingTime);
Now, I want to update the cachingTime to some other value and serve that updated value. For example, from 1000 to 99.
Is there any way to update this property value at runtime??
Or is there any other way to update this value except restarting app or server?
I'm using Spring Boot 1.4.3.RELEASE.
I tried to google it, but none of answer gave me the solution. :(
Thank you for any help.
If you will change the value on property file it will not effect on runtime because all the configuration is done while server starting, if you don't want to redeploy the code base you can do one thing, change the property file value and just restart the server.
You can have a look at spring-boot admin once. Though it acts as a monitoring server, it gives you ability to update properties and environment variables.
http://codecentric.github.io/spring-boot-admin/1.5.3/
Attaching a screenshot put up a proof of concept by codecentric guys.

Categories