I want to have a service in my Spring application that watches a directory for changes using the Java 7 WatchService. The idea is that when a file in the directory is changed, clients connected via WebSockets are notified.
How do I get a bean to run in its own thread as a service?
What you are looking for is Asynchronous execution. With a correctly configured context (see the link), you declare a class like so
#Component
public class AsyncWatchServiceExecutor {
#Autowired
private WatchService watchService; // or create a new one here instead of injecting one
#Async
public void someAsyncMethod() {
for (;;) {
// use WatchService
}
}
}
Everything you do in someAsyncMethod() will happen in a separate thread. All you have to do is call it once.
ApplicationContext context = ...; // get ApplicationContext
context.getBean(AsyncWatchServiceExecutor.class).someAsyncMethod();
Use the WatchService as described in the Oracle documentation.
If you don't have direct access to your ApplicationContext, you can inject the bean in some other bean and call it in a #PostConstruct method.
#Component
public class AsyncInitializer {
#Autowired
private AsyncWatchServiceExecutor exec;
#PostConstruct
public void init() {
exec.someAsyncMethod();
}
}
Careful which proxying strategy (JDK or CGLIB) you use.
Related
I'm building a Spring Boot Starter for a college project on Java Reflection and Bytecode alteration.
The Reflection/Bytecode is done now, but it will scan for Spring #Controllers/#RestControllers so it can detect certain annotations to run the process.
My question here is what's the best approach? Seems to me that an annotation processor doesn't quite work nicely, and my idea is to create a #Configuration class. Now I need to ensure that all #Controller beans have been booted before I actually process them and I also need to put the result of this processing in a bean that could already exist.
So for example:
#Configuration
public class TestConfig {
#Autowired //I want to autowire but it may not exist, if the user doesn't define I need to create it
private ExternalAnnotatedRequestsModel model;
#Autowired // needed for the framework to acess spring controllers
private ConfigurableApplicationContext ctx;
#Bean // this can also be overriden since the definitions can be done via yaml
public ExternalRequestsProvider() {
return new AnnotationExternalRequestsProvider(ctx);
}
}
Now I also want that when the ExternalRequestsProvider bean is started, it runs the process method and saves the result in the object in the "model" variable.
Using #EventListener for ApplicationReadyEvent to run your process after Spring is fully configured.
#Configuration
public class ExternalRequestsConfig {
#Autowired
private ExternalAnnotatedRequestsModel model;
#Autowired
private ExternalRequestsProvider provider;
#EventListener(ApplicationReadyEvent.class)
public void onApplicationReady(ApplicationReadyEvent event) {
// do your process
}
}
I'm using spring-boot to start an HTTP server. It contains the following two files:
BeanUtils
#Service
public class BeanUtils implements ApplicationContextAware {
public static ApplicationContext cxt;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
cxt = applicationContext;
}
}
MainController
#RestController
public class MainController {
#GetMapping("/getData")
public Object getData() {
return BeanUtils.cxt.getBean("someBean").getData();
}
}
Does spring guarantee to finish all the beans, including both BeanUtils and MainController when the server starts? If not, the user might get a NullPointerException when he/she tried to access /getData because the BeanUtils bean hasn't been loaded. I want to know if it's safe to write like this.
you can try it. before send /getData request, BeanUtils has been loaded when server starts.
all the beans are instantiated on starting up in Spring IOC container, if it is a singleton bean(as are by default) an instance of bean is created at startup and passed wherever required and if not(prototype), an instance is created at the time required and passed. so in this case you won't get NullPointerException.
I'm developing an app with Spring boot, I'm using the MVC model.
I have an entity called A, which has its controller, service and repository. all right up here.
I have an utility class, which is runnable and is called when the server start. This utility class create a set of A entities, and then, stored it into database. The problem is that the autowired service of the class is null, because I have created a new instance of the utility class in order to run it, so Spring doesn't create the autowired service correctly.
that is:
Main.java
#SpringBootApplication
public class MainClass {
public static void main(String[] args) {
...
Runnable task = new Utility();
...
}
}
Utility.java
#Autowired
private Service service;
...
public void run() {
...
service.save(entities); <-- NPE
}
I know that Spring cannot autowired the service of this new instance, but I need to create the utility instance in order to run it.
I have tried to access to the service through application context, but the problem is the same:
#Autowired
private ApplicationContext applicationContext;
I have tried to make runnable the controller (where the service is autowired correctly), but the problem is the same, since I need to do the new controller();.
I have read these posts
post 1
post 2, but any solution works.
UPDATE: I need that the task run in a new thread, since it will be executed each X hours. The task downloads a data set from Internet and save it into database.
If you need to do some task periodically:
#SpringBootApplication
#EnableScheduling
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application .class, args);
}
}
#Component
class Runner {
#Autowired
private Service service;
#Scheduled(cron = "0 */2 * * * ?") // execute every 2 hours
public void run() {
// put your logic here
}
}
If I understood correctly, you're trying to populate your database with dummy data.
This utility class create a set of A entities, and then, stored it
into database
Why are you using a Runnable? Is this task run via a new Thread?
If not, then use #PostConstruct inside your #Controller, which has access to the right #Service. The marked method is guaranteed to be invoked after the Bean has been completely constructed, and all its dependencies have been satisfied.
#PostConstruct
private void persistEntities() {
...
service.save(entities);
}
If you're on Spring Boot, you can just place a data-*.sql file under src/main/resources/. It will be run at startup.
Just as said #CoderinoJavarino in comments, I need to use #Scheduled instance of a runnable class.
With scheduled, Spring can autowired correctly the service. So, finally, my initial runnable utility class has become into a scheduled class.
I am currently trying to deploy a Spring Boot Application into an external Tomcat instance, and am running into some questions regarding how to best manage the instantiation of certain things.
As presently structured I have something along the lines of
public class MyClass extends SpringBootServletInitializer{
#Bean
public ThreadPool pool(){
return new ThreadPool();
}
#Bean
public BackgroundThread setupInbox() {
BackgroundThread inbox = new BackgroundThread(pool());
inbox.start();
return inbox;
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(MyClass.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(MyClass.class, args);
}
}
where BackgroundThread is a thread that is listening to an AMQP type messaging queue for new jobs. I know Spring offers some RabbitMQ ways to do this, but we are not using Rabbit for this so it doesn't help.
The entire purpose of this *.war file that is being deployed is to expose some functionality to the wire via messaging, so my question is what is the best way to instantiate, start and then destroy the BackgroundThread through the lifecycle of Spring? XML Configuration?
From the docs:
The JSR-250 #PostConstruct and #PreDestroy annotations are generally considered best practice for receiving lifecycle callbacks in a modern Spring application. Using these annotations means that your beans are not coupled to Spring specific interfaces.
For details see Section 7.9.8, “#PostConstruct and #PreDestroy”
Those annotation are meant to be put on some init and cleanup methods:
#PostConstruct
public void initAfterStartup() {
...
}
#PreDestroy
public void cleanupBeforeExit() {
...
}
Also useful :
Each SpringApplication will register a shutdown hook with the JVM to ensure that the ApplicationContext is closed gracefully on exit. All the standard Spring lifecycle callbacks (such as the DisposableBean interface, or the #PreDestroy annotation) can be used.
In addition, beans may implement the org.springframework.boot.ExitCodeGenerator interface if they wish to return a specific exit code when the application ends.
Java EE 7 application is running on Wildfly 9.0.2.Final. There is a problem to access request scoped data from within #Asynchronous methods.
In web filter data (e.g. token) is set into RequestScoped CDI bean. Later we want to access this data. Everything works fine if we work in one thread. But if there is need to run code asynchronously the problem appears. CDI injects empty bean and request data is lost.
Here is the example:
#RequestScoped
public class CurrentUserService implements Serializable {
public String token;
}
#Stateless
public class Service {
#Inject
private RestClient client;
#Resource
private ManagedExecutorService executorService;
#Resource
private ContextService contextService;
#Asynchronous
private <T> Future<T> getFuture(Supplier<T> supplier) {
Callable<T> task = supplier::get;
Callable<T> callable = contextService.createContextualProxy(task, Callable.class);
return executorService.submit(callable);
}
public String getToken() throws Exception {
return getFuture(client::getToken).get();
}
}
#ApplicationScoped
public class RestClient {
#Inject
private CurrentUserService currentUserBean;
public String getToken() {
return currentUserBean.token;
}
}
In the given example we want to access current user token (CurrentUserService#token) from asynchronous Service.getToken method. As the result we will receive null.
It's expected that 'request scoped' data should be accessible from tasks executed within request scope. Something like InheritableThreadLocal should be used to allow assess to original thread data from new threads.
Is it a bug? May be I'm doing something wrong? If yes - what it the correct way to propagate such data into async calls?
Thanks in advance.
According to §2.3.2.1 of the Java EE Concurrency Utilities specification, you should not attempt to do this:
Tasks that are submitted to a managed instance of ExecutorService may still be running after the lifecycle of the submitting component. Therefore, CDI beans with a scope of #RequestScoped, #SessionScoped, or #ConversationScoped are not recommended to use as tasks as it cannot be guaranteed that the tasks will complete before the CDI context is destroyed.
You need to collect your request scoped data and pass it to your asynchronous task when you create it, whether you use concurrency utilities or #Asynchronous methods.