Invoke a service method after the Spring Boot deployed successfully - spring-boot

I have a spring boot application and i want to invoke a service method once the application gets deployed successfully.
Ex:
#Service
public class MyServiceImpl implements MyUtilityService<Object, Object>{
#Override
public Object runOnce(Object credential) {
return null;
}
}
I want to invoke myService.runOnce(...) only after my application deployed successfully

You can register an EventListener for the ApplicationReadyEvent.
From the docs:
Event published as late as conceivably possible to indicate that the
application is ready to service requests. The source of the event is
the SpringApplication itself, but beware of modifying its internal
state since all initialization steps will have been completed by then.
#Service
public class MyServiceImpl implements MyUtilityService<Object, Object>{
#Override
#EventListener(ApplicationReadyEvent.class)
public Object runOnce(Object credential) {
return null;
}
}

Related

Spring Boot WebSockets #EventListener doesn't detect SessionConnectEvent but detect SessionDisconnectEvent at the same class

I try to create simple chat via WebSockets. I have configuration class which register appropriate endpoints and I try to create service which will save user id which is generated in handshake service. The problem is that I cannot inject any services to the handshake service so I decided to create class as below:
#Slf4j
#RequiredArgsConstructor
public class WebSocketEventListener {
#EventListener
public void handleWebSocketConnectListener(SessionConnectEvent event) {
log.debug("Handled connection event");
}
#EventListener
public void handleWebSocketConnectedListener(SessionConnectedEvent event) {
log.debug("Handled connected event");
}
#EventListener
public void handleWebSocketDisconnectListener(SessionDisconnectEvent event) {
log.debug("Handled disconnection event");
}
}
Register it as a Bean in configuration class:
#Bean
public WebsocketEventListener websocketEventListener() {
return new WebsocketEventListener();
}
And there try to save user id into database.
Unfortunately when I connect to the webSocket via android app, Spring doesn't detect any event connected with Connection session but when I close the connection between android app and spring server I'm getting log from handleWebSocketDisconnectListener method.
I also tried to add annotation #Component to the class WebSocketEventListener instead of registering it as a Bean but I got the same situation.
I tried to implement ApplicationListener and register it in META-INF folder but also without any results.
P.S. I use Spring Boot version: 2.6.4 and Java 17
I don't know what I'm doing wrong. Any suggestions?

How to trigger a Spring cloud task from an external application?

I have created a spring cloud task that will perform some specific task based on the requirement. I wanted to call this task from another spring boot application. Please let me know is there any way of calling the below task from an external application.
#SpringBootApplication
#EnableTask
public class FileGenerationTaskApplication {
#Autowired
private DataSource dataSource;
public class FileGeneratorTaskConfigurer extends DefaultTaskConfigurer {
public FileGeneratorTaskConfigurer(DataSource dataSource){
super(dataSource);
}
}
#Bean()
public FileGeneratorTaskConfigurer getTaskConfigurer() {
return new FileGeneratorTaskConfigurer(dataSource);
}
public static void main(String[] args) {
SpringApplication.run(FileGenerationTaskApplication.class, args);
}
#Component
public static class FileGeneratorTaskRunner implements ApplicationRunner {
#Autowired
private FulfillmentFileGenerationService service;
public void run(ApplicationArguments args) throws Exception {
System.out.println("FileGeneratorTaskRunner from Spring Cloud Task!");
service.fulFillmentFileGenerationTask();
}
}
}
Can we create a REST api to call the spring cloud task?
It would be nice to have the Task registered on Spring Cloud Dataflow.
After you have your Task registered, you can make REST calls to trigger the Task. Check this example out.
You can also use Spring Cloud Dataflow Rest Client
DataFlowOperations dataFlowOperations = new DataFlowTemplate(URI.create(springDataFlowUri));
TaskOperations operations = dataFlowOperations.taskOperations();
Then you can start launching the Tasks previously got using the API Rest.
In case you do not want to use Spring Cloud DataFlow, remember when you create a Task, this is a Spring Boot Application by itself, so you can expose end points to trigger the Task.

SpringBootTest: how to know when boot application is done

Spring boot integration test looks like this
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Application)
class IntegrationTest {
static QpidRunner qpidRunner
#BeforeClass
static void init() {
qpidRunner = new QpidRunner()
qpidRunner.start()
}
#AfterClass
static void tearDown() {
qpidRunner.stop()
}
}
So, Qpid instance is run before and teared down after all tests. I want to know is there a way to check whether spring boot application is still running before calling qpidRunner.stop(). I want to stop Qpid only when I'm sure that spring app has finished its stopping.
The Spring Boot integration test can configure an ApplicationListener which listens for ContextClosedEvent. Define a nested #TestConfiguration class inside the test class to add beans to the application's primary configuration.
#TestConfiguration
static class MyConfiguration {
#Bean
public ApplicationListener<ContextClosedEvent> contextClosedEventListener() {
return event -> qpidRunner.stop();
}
}
Taking into account that ConfigurableWebApplicationContext can be injected in a SpringBootTest, adding this lines to the code solved the problem
static ConfigurableWebApplicationContext context
#Autowired
void setContext(ConfigurableWebApplicationContext context) {
AbstractDocsIntegrationTest.context = context
}
#AfterClass
static void tearDown() {
context.stop()
qpidRunner.stop()
}
Spring docs about stop method
Stop this component, typically in a synchronous fashion, such that the
component is fully stopped upon return of this method.
JUnit AfterClass annotated method must be static, therefore #Autowired workaround with setContext method.

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.

Access Spring Web Acclication Context in Stateless EJB

at the moment we use Spring 4 and have a Java class loading all of our xml-config files:
Root: Basic Framework
Child: Project Application Services
Child: Project Application Workflow
Child: Framework Controller
Child: CXF Webapplication Context
Every child knows the beans of it's parent and everythings works fine. Now I have to use an IBM EJB on an Websphere Application Server for communication with legacy systems. This EJB gets called and now I want to use our Spring Context to get some services.
The EJB is defined as
#Stateless(mappedName = "ejb/LegacyRocks")
#RemoteHome(com.ibm.websphere.ola.ExecuteHome.class)
public class WolaUseCaseOne {...}
I have alreade read about the SpringBeanAutowiringInterceptor, but I do not get the point. I do not a a simple xml-file to get loaded, so can anybody provide me another way the autowire mit Spring Beans inside the EJB ?
PS:
I have also found this post (http://www.schakko.de/2013/10/11/sharing-the-spring-application-context-from-a-war-with-ejbs/), but we do not use JSF and it does not help me
I have already read, there is no way to inject the complete context, because we have a Webapplication Context, and there is not such a Web Context inside EJB... ?
you need to create ejb as per following
#Local
public interface TestManager {
boolean isValid();
}
#Stateless(name = "java:global/TestManagerImpl", mappedName = "java:global/TestManagerImpl")
#EJB(name = "java:global/TestManagerImpl", beanInterface = TestManager.class)
public class TestManagerImpl implements TestManager {
#PostConstruct
public void ejbCreate() {
}
#PreDestroy
public void ejbDestroy() {
}
#Override
public boolean isValid(){
//your code
}
}
and you need to implement spring service class with
#Service(value = "testServiceImpl")
public class TestServiceImpl {
#EJB(name = "java:global/TestManagerImpl", mappedName = "java:global/TestManagerImpl")
private TestManager testManager;
#Override
public boolean isValid(){
retrun testManager.isValid();
}
}
Edited
call ejb to spring service method
#Stateless
#Interceptors(SpringBeanAutowiringInterceptor.class)
public class TestManagerImpl implements TestManager {
// automatically injected with a matching Spring bean
#Autowired
private TestService testService ;
// for business method, delegate to POJO service impl.
public String myFacadeMethod(...) {
return testService.myMethod(...);
}
...
}
Hope it work for you!!

Resources