Spring Boot - Impossible for JavaFX app to implement SmartLifeCycle? - spring-boot

I am building a JavaFX app and i want it to implement Spring's SmartLifeCycle interface to perform tasks when the main class terminates. A JavaFX main class must extend the Application class which contains a stop() method. The SmartLifeCycle interface also contains a stop method. It looks like these 2 methods refuse to co-exist even if they have different method signatures. The JavaFX method extended from the Application class has no parameters and throws an exception while the implemented method from SmartLifeCycle takes a Runnable object as an argument.
Is it possible for both these methods to exist in the same class? Both are required to implement by subclasses therefore the compiler complains no matter what i do.
Thanks

The Application abstract class has the following method:
public void stop() throws Exception {}
And the SmartLifecycle interface has the following method, inherited from Lifecycle:
void stop();
As you can see, one can throw an Exception and the other cannot. If you want to extend Application and implement SmartLifecycle, then you can't have throws Exception in your overridden stop() method.
public class MySpringJavaFxApp extends Application implements SmartLifecycle {
#Override
public void start(Stage primaryStage) throws Exception {
// ...
}
#Override
public void stop() {
// ...
}
// other methods that need to be implemented...
}
But note you have to override stop() to remove the throws clause. Otherwise the methods clash (Application#stop is not abstract, thus tries to implement Lifecycle#stop in this situation).

Related

Spring Boot - the best way to read data from database on startup

I would like to read data to List or Map from database on startup.
Which is the best way to do it? The Spring Boot version is 5.
Is the below solution is good?
#Component
public class ApplicationStartup
implements ApplicationListener<ApplicationReadyEvent> {
/**
* This event is executed as late as conceivably possible to indicate that
* the application is ready to service requests.
*/
#Override
public void onApplicationEvent(final ApplicationReadyEvent event) {
// here your code ...
return;
}
}
I'd like to storage data on static class, but I have doubt that is the best solution.
I don't quite understand what is your motive for doing so but for doing so you can create a bean using #Component and in that bean create a method with annotation #PostConstruct. you can do whatever you want in this method.
Using the ApplicationRunner interface is the best way to run code once the Spring boot context has loaded.
#Component
public class ApplicationStartup implements ApplicationRunner {
#Override
public void run(ApplicationArguments args) throws Exception {
}
}
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-spring-application.html#boot-features-command-line-runner

init method in jersey jax-rs web service

I'm new with jax-rs and have build a web service with jersey and glassfish.
What I need is a method, which is called once the service is started. In this method I want to load a custom config file, set some properties, write a log, and so on ...
I tried to use the constructor of the servlet but the constructor is called every time a GET or POST method is called.
what options I have to realize that?
Please tell, if some dependencies are needed, give me an idea how to add it to the pom.xml (or else)
There are multiple ways to achieve it, depending on what you have available in your application:
Using ServletContextListener from the Servlet API
Once JAX-RS is built on the top of the Servlet API, the following piece of code will do the trick:
#WebListener
public class StartupListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent event) {
// Perform action during application's startup
}
#Override
public void contextDestroyed(ServletContextEvent event) {
// Perform action during application's shutdown
}
}
Using #ApplicationScoped and #Observes from CDI
When using JAX-RS with CDI, you can have the following:
#ApplicationScoped
public class StartupListener {
public void init(#Observes
#Initialized(ApplicationScoped.class) ServletContext context) {
// Perform action during application's startup
}
public void destroy(#Observes
#Destroyed(ApplicationScoped.class) ServletContext context) {
// Perform action during application's shutdown
}
}
In this approach, you must use #ApplicationScoped from the javax.enterprise.context package and not #ApplicationScoped from the javax.faces.bean package.
Using #Startup and #Singleton from EJB
When using JAX-RS with EJB, you can try:
#Startup
#Singleton
public class StartupListener {
#PostConstruct
public void init() {
// Perform action during application's startup
}
#PreDestroy
public void destroy() {
// Perform action during application's shutdown
}
}
If you are interested in reading a properties file, check this question. If you are using CDI and you are open to add Apache DeltaSpike dependencies to your project, considering having a look at this answer.

Catch application stop event for Spring-boot application

Is there a clean way to detect when a spring-boot application is stopped and perform some action before? Kind of CommandLineRunner for stopping a service
Thanks in advance
Similar to ApplicationReadyEvent you can use ContextClosedEvent:
#Component
public class ContextClosedEventListener {
#EventListener(ContextClosedEvent.class)
public void onContextClosedEvent(ContextClosedEvent contextClosedEvent) {
System.out.println("ContextClosedEvent occurred at millis: " + contextClosedEvent.getTimestamp());
}
}
I've come up with this solution. If you have better one, feel free to share
#Component
public class PortalServiceLifeCycle implements CommandLineRunner {
static final Logger LOGGER = LoggerFactory.getLogger(PortalServiceLifeCycle.class);
#Override
public void run(String... arg0) throws Exception {
LOGGER.info("###START FROM THE LIFECYCLE###");
}
#PreDestroy
public void onExit() {
LOGGER.info("###STOP FROM THE LIFECYCLE###");
}
}
Don't know if you have resolve this problem perfectly. I meet this issue recently, and have got a solution that a little different.
Firstly, my Spring boot Application is a Tomcat embedded one. (The second method of this issue doesn't depends on the web structure. don't mad, my friend.) In this case, it's naturally to get the idea of catch the stop event by register a listener. I do it like this,
#WebListener
public class HelloListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("HelloListener contextInitialized");
}
#Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("HelloListener contextDestroyed");
}
}
and, at the same time, add the annotation #ServletComponentScan on your Application class.
Surely, there are some other ways to register a ServletContextListener, and once you registered it, you can get the stop event in the contextDestroyed function.
BUT, that don't match my issue very much. I must catch the stop event BEFORE the Spring Beans being destroyed. And here comes the second solution.
modify your application main method like the follow:
SpringApplication application = new SpringApplication(DemoApplication.class);
application.addListeners(new MyListener());
application.run(args);
and provide the defination of class MyListener:
class MyListener implements ApplicationListener<ContextClosedEvent>{
#Override
public void onApplicationEvent(ContextClosedEvent contextClosedEvent) {
// your code here
}
}
NOTE: the second solution has nothing to do with Tomcat or other web container. The ContextClosedEvent isn't introduced in the Spring document, but I found it in the source, it's very useful i think.
I will be very glad if this can help some one.
It depends what you want to do but one thing you could do is have a bean that implements SmartLifecycle and implement the stop method. Whenever the context is being stopped, you'd get a callback. Note that it does not necessarily means that the process is shutting down. If you want to invoke some code when that happens, I'd register a shutdown hook as Sven wrote in a comment.

Spring Event and Scope request

I would like to use Spring Event to "speak" with my beans in my web application.
So, for example, my bean which fires event is like this:
#Controller
#Scope("request")
#KeepAlive
public class Controller extends InitializingBean, ApplicationEventPublisherAware {
private ApplicationEventPublisher applicationEventPublisher;
public void test() {
applicationEventPublisher.publishEvent(new TestEvent(this));
}
}
And my listener event is like this:
#Component
#Scope("request")
#KeepAlive
public class Module implements ApplicationListener<TestEvent> {
#Override
public void onApplicationEvent(TestEvent event) {
}
}
The most important point is these beans are scope request because they need to be initialized at every time the page is called.
But in startup, I get this message:
Caused by: java.lang.IllegalStateException: No thread-bound request
found: Are you referring to request attributes outside of an actual
web request, or processing a request outside of the originally
receiving thread? If you are actually operating within a web request
and still receive this message, your code is probably running outside
of DispatcherServlet/DispatcherPortlet: In this case, use
RequestContextListener or RequestContextFilter to expose the current
request.
Like if Spring try to instantiate my Module bean in startup and as the bean is scope request, it can't do this (the context request is not instantiate)
If I delete event management, everything works fine.
So, my question is:
Is it possible to have event listener is scope request ? And how to do this ?
Thanks
Try to inject a scoped proxy in a Singleton ApplicationListener to handle the TestEvent.
#Scope(proxyMode=ScopedProxyMode.TARGET_CLASS, value="request")
public class TestEventHandler {
public void onTestEvent(TestEvent event)
// ...
}
}
public class TestEventApplicationListener implements ApplicationListener<TestEvent> {
#Autowired
private TestEventHandler handler;
#Override
public void onApplicationEvent(TestEvent event) {
handler.onTestEvent(event);
}
}

Trigger a second advised method from a method already being advised in Spring

I have a Class, call it X, in this class I have successfully advised a method call it method(){} from an Annotated Spring.
So, here it is:
public class X {
public void method(){...}
public void method2(){...}
}
Here is my aspect, shortened of course:
#Aspect
public class MyAspect{
#Pointcut("execution(* X.method(..))")
public void methodJP(){}
#Pointcut("execution(* X.method2(..))")
public void method2JP(){}
#Around("methodJP()")
public void doMethodJP(ProceedingJoinPoint pjp) throws Exception {
pjp.proceed(); //Amongst other things!!!
}
#After("method2JP()")
public void doMethod2JP(JoinPoint jp) throws Exception {
//Do some stuff here
}
}
Now... both join points work well, however, I within my X.method, I also call the method that is advised by method2JP()... and of course, my method2JP does not get triggered.
Is there any way I can get this to work?
Thanks.
Since Spring AOP works by proxying classes, for the advice to be invoked, you must call the method through the proxy or wrapper supplied by the bean factory.
If you don't want to break out into multiple classes, you can have the method retrieve a the proxied version of "itself" from the beanfactory. Something like this
#Service
public class MyService {
#Autowired
ApplicationContext context;
public void method1() {
context.getBean(MyService.class).method2();
}
public void method2() {
}
}
This will guarantee that the invocation of method2 from method1 will apply any aspects on the method2 pointcut.
methodJP() should be declared in another class. In the regular scenario the aspects are not triggered when you invoke a method from within the same object.

Resources