I want to execute a java class (which contains a java thread I want to execute) after spring boot starts. My initial code:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
And here is is the code I want to execute at start:
public class SimularProfesor implements Runnable{
// Class atributes
// Constructor
public SimularProfesor() {
//Initialization of atributes
}
#Override
public void run() {
while(true) {
// Do something
}
}
}
How can I call this thread? This is what I'm supposed to do:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
// Call thread (constructor must be executed too)
}
}
Don't mess around with threads yourself. Spring (and also plain Java) has a nice abstraction for that.
First create a bean of the type TaskExecutor in your configuration
#Bean
public TaskExecutor taskExecutor() {
return new SimpleAsyncTaskExecutor(); // Or use another one of your liking
}
Then create a CommandLineRunner (although an ApplicationListener<ContextRefreshedEvent> would also work) to schedule your task.
#Bean
public CommandLineRunner schedulingRunner(TaskExecutor executor) {
return new CommandLineRunner() {
public void run(String... args) throws Exception {
executor.execute(new SimularProfesor());
}
}
}
You could of course make also your own class managed by spring.
Advantage of this is that Spring will also cleanup the threads for you and you don't have to think about it yourself. I used a CommandLineRunner here because that will execute after all beans have bean initialized.
Main Class SpringBoot
#SpringBootApplication
#EnableAsync
#Controller
public class ...
Example Class Controler
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;
#Component
public class ExecutorBase {
private static final Logger log = LoggerFactory.getLogger(ExecutorBase.class);
#Autowired
private TaskExecutor taskExecutor;
#Autowired
private ApplicationContext applicationContext;
private Boolean debug = true;
#PostConstruct
public void atStartup() {
ClasseTaskRunn classeTaskRunn = applicationContext.getBean(ClasseTaskRunn.class);
taskExecutor.execute(classeTaskRunn );
if (debug) {
log.warn("###### Startup ok");
}
}
}
Example Class Task Runnable
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
#Component
#Scope("application")
public class ClasseTaskRunn implements Runnable {
private static final Logger log = LoggerFactory.getLogger(ClasseTaskRunn.class);
#Autowired
ClasseDAO classeDAO;
#Override
public void run() {
longBackgorund();
}
protected void longBackgorund() {
while (test) {
if (debug) {
log.warn("###### DEBUG: " ... );
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Related
I have some classes below. Obviously, if I invoke "printMessage" in CustomAtm class, it will execute the method in PrinterFile because I declared it by #Qualifier. But I wonder Is there any way to execute both "printMessage" method in PrinterConsole and PrinterFile when I invoke it and I don't declare #Qualifier ?
Printer interface
public interface Printer {
void printMessage(String message);
}
PrinterConsole class
import org.springframework.stereotype.Component;
#Component("printerConsole")
public class PrinterConsole implements Printer {
#Override
public void printMessage(String message) {
System.out.println(message);
}
}
PrinterFile class
import org.springframework.stereotype.Component;
#Component("printerFile")
public class PrinterFile implements Printer {
Logger logger = LoggerFactory.getLogger(PrinterFile.class);
#Override
public void printMessage(String message) {
logger.info(message);
}
}
CustomAtm class
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
#Component("customAtm")
public class CustomAtm {
#Autowired
#Qualifier("printerFile")
Printer printer;
public void printCurrentMoney() {
printer.printMessage("Current ATM money is... ");
}
}
You can look up all instances that are registered as bean and implement the Printer interface:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component("customAtm")
public class CustomAtm {
#Autowired
private ApplicationContext applicationContext;
public void printCurrentMoney() {
Map<String, Printer> printers = context.getBeansOfType(Printer.class);
for(Printer printer: printers.values()){
printer.printMessage("Current ATM money is... ");
}
}
}
Method 1
Inject list of printer
#Autowired(required = false)
private List<Printer> printers;
public void printAll() {
for (Printer printer : printers) {
printer.print();
}
}
Method 2
you can define another class that combine the 2 beans
#Component("printerAdapter")
public class PrinterAdapter implements Printer {
#Autowired
#Qualifier("printerFile")
Printer printerFile;
#Autowired
#Qualifier("printerConsole")
Printer printerConsole;
#Override
public void printMessage(String message) {
printerConsole.printMessage();
printerFile.printMessage();
}
}
And in your client class inject the new printer class and use it
#Autowired
#Qualifier("printerAdapter")
Printer printer;
I am new to SpringBoot. I don't know how to create a few objects of the same type in the way that enables to use this objects later for example in the controller.
Let's say I would like to create collection/list of objects (let's say collection of Rabbits) when the application starts:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
// I would like to create here a collection
// or a list of objects (let's say collection of Rabbits)
}
}
I would like to have the possibility to use this objects later in the controller to get some information (obtained for example by index in the list).
What is the right way to keep state of my model without having a database?
Ignoring synchronization issues.
You can create a List and inject into your controllers.
or what I like to do is wrap that in a repository. This insulates you from the underlying datasource and it can be changed later.
Note that synchronization is important for this type of data structure as you can have many threads updating the repository.
package com.example.demo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#SpringBootApplication
public class Demo1Application {
public static void main(String[] args) {
SpringApplication.run(Demo1Application.class, args);
}
#Bean
public RabbitRepository rabbitRepository() {
RabbitRepository rabbitRepository = new RabbitRepository();
rabbitRepository.add("Bugs");
rabbitRepository.add("Flopsy");
return rabbitRepository;
}
public static class RabbitRepository {
private List<Rabbit> rabbits = Collections.synchronizedList(new ArrayList<Rabbit>());
public List<Rabbit> getAll() {
return rabbits;
}
public Rabbit add(String rabbitName) {
Rabbit rabbit = new Rabbit(rabbitName);
this.rabbits.add(rabbit);
return rabbit;
}
public Optional<Rabbit> findById(int id) {
return this.rabbits.stream().filter(r-> r.getId() == id).findFirst();
}
}
public static class Rabbit {
private final String name;
private final int id;
private static AtomicInteger counter = new AtomicInteger();
public Rabbit(String name) {
super();
this.name = name;
this.id = counter.incrementAndGet();
}
public String getName() {
return name;
}
public int getId() {
return this.id;
}
}
#RestController
#RequestMapping("/rabbits")
public static class RabbitController {
private final RabbitRepository repository;
public RabbitController(final RabbitRepository repository) {
this.repository = repository;
}
#GetMapping
public List<Rabbit> getAll() {
return repository.getAll();
}
#PostMapping("/{name}")
//You can also use requestparam / requestbody and probably should
public Rabbit addRabbit(#PathVariable("name") String name) {
return repository.add(name);
}
#GetMapping("/id/{id}")
public Optional<Rabbit> findById(#PathVariable("id") int id) {
return repository.findById(id);
}
}
}
Curl tests
➜ ~ curl localhost:8080/rabbits
[{"name":"Bugs","id":1},{"name":"Flopsy","id":2}]%
➜ ~ curl localhost:8080/rabbits/id/2
{"name":"Flopsy","id":2}%
➜ ~ curl -XPOST localhost:8080/rabbits/Babs
{"name":"Babs","id":3}%
➜ ~ curl localhost:8080/rabbits
[{"name":"Bugs","id":1},{"name":"Flopsy","id":2},{"name":"Babs","id":3}]%
Using spring you need to create objects in the context of spring, otherwise spring created instances can't find them. A solution can be putting them in a class annotated with #Configuration and retrieve them with the annotation #Autowired.
The annotation #Configuration:
Indicates that a class declares one or more #Bean methods and may be processed by the Spring container to generate bean definitions and service requests for those beans at runtime.
You can use it as follow:
#Configuration
public class MyConfiguration {
#Bean
public MyClass getMyClass() {
MyClass myClass = ...
...
return myClass;
}
}
#Controller
public class MyController {
#Autowired
private MyClass myClass;
public void method() {
// Use myClass instance as you like
}
}
You can also generate a standard java.util.List, but in this case is better to give a name to the bean generated, for example:
#Configuration
public class MyConfiguration {
#Bean("myname") // To give an explicit name to the List
public List getMyList() {
List myList = ...
...
return myList;
}
}
#Controller
public class MyController {
#Autowired
#Qualifier("myname") // To retrieve a List with a specific name
private List myList;
public void method() {
// Use myList instance as you like
}
}
You need something like this i guess !
#Component
public class RabbitListHolder {
private List<Rabbit> rabbits = new ArrayList<Rabbit>
public void initializeList(){
rabbits.add(new Rabbit('white', 3));
...
}
}
#Controller
public class RabbitsRessource{
#Autowired
RabbitListHolder rabbitListHolder;
...
#GetMapping("/rabbits")
public List<Rabbits> getRabbits(){
rabbitListHolder.initializeList();
return rabbitListHolder.getRabbits();
}
}
I need to audit timeout logOut event, I searched a bit and find a solution. But it doesn't work. The event method is not called at all when the user logs out or timeout.
This is my code:
ObjectLock.java:
#Component
public class ObjectLock implements ApplicationListener<SessionDestroyedEvent> {
#Override
public void onApplicationEvent(SessionDestroyedEvent event)
{
List<SecurityContext> lstSecurityContext = event.getSecurityContexts();
String userName;
for (SecurityContext securityContext : lstSecurityContext)
{
userName = (String)securityContext.getAuthentication().getPrincipal();
System.out.println("Log Out " + userName);
// ...
}
}
}
Application.java:
public class Application {
public static void main(String[] args) throws Exception {
TimeZone.setDefault(TimeZone.getTimeZone("Etc/UTC"));
SpringApplication application = new SpringApplication( Application.class );
application.addListeners(new ObjectLock());
ConfigurableApplicationContext context = application.run(args);
// ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
}
}
Anyone can tell me what is wrong? Thanks.
Add the following code/class and then the listener will get called:
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.web.session.HttpSessionEventPublisher;
#Configuration
public class ApplicationConfig {
#Bean
public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() {
return new ServletListenerRegistrationBean<HttpSessionEventPublisher>(new HttpSessionEventPublisher());
}
}
As per the documentation, spring boot will automatically check the bean class object created in any classes annotated with #Configuration & will override the default bean of that class & return the object with any properties that are injected as it is defined. But when i test this application in junit, it does not return any value that is being injected. All my classes are defined in the same package My code is as below,
//Engine class
package com.test.simpletest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class Engine {
private String msg;
public Engine() {
System.out.println("Engine class is being called");
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
//Test configuration class
package com.test.simpletest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class TestConfiguration{
#Bean
public Engine engine() {
Engine eng = new Engine();
eng.setMsg("Message is being called");
return eng;
}
}
//Spring boot main app
package com.test.simpletest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class SimpleTestExampleApplication {
public static void main(String[] args) {
SpringApplication.run(SimpleTestExampleApplication.class, args);
}
}
//JUnit Test class
package com.test.simpletest;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
#SpringBootTest
public class SimpleTestExampleApplicationTests {
#Autowired
private Engine engine;
#Test
public void contextLoads() {
engine.getMsg();
//Both above and below approach does not work
// ApplicationContext apx = new
AnnotationConfigApplicationContext(TestConfiguration.class);
// Engine engine = (Engine)apx.getBean(Engine.class);
// engine.getMsg();
}
}
Please help me in finding a solution to the above problem.
DemoApplication
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Engine
public class Engine {
private String msg;
public Engine() {
System.out.println("Engine class is being called");
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
TestConfiguration
#Configuration
public class TestConfiguration {
#Bean
public Engine getEngine() {
Engine eng = new Engine();
eng.setMsg("Message is being called");
return eng;
}
}
DemoApplicationTests
#RunWith(SpringRunner.class)
#SpringBootTest
#Import(TestConfiguration.class)
public class DemoApplicationTests {
#Autowired
private Engine engine;
#Test
public void contextLoads() {
System.out.println("engine : " + engine.getMsg());
}
}
Output
Engine class is being called
engine : Message is being called
Can you please remove #Component from Engine class and try again. I guess it’s should work fine.
I've stared to use spring's #EventListener annotation to create event handlers that handle my non-spring specific events. Initially everything went pretty well. I used a test to verify that I could put the #EventListener annotation on a method of a abstract class and everything worked as expected.
However, once I started adding generics to the mix I started getting NullPointerExceptions from ApplicationListenerMethodAdapter.java:337.
I've created a test case to illustrate the problem. Currently all the test methods fail with the exception:
java.lang.NullPointerException
at java.lang.Class.isAssignableFrom(Native Method)
at org.springframework.context.event.ApplicationListenerMethodAdapter.getResolvableType(ApplicationListenerMethodAdapter.java:337)
at org.springframework.context.event.ApplicationListenerMethodAdapter.resolveArguments(ApplicationListenerMethodAdapter.java:161)
at org.springframework.context.event.ApplicationListenerMethodAdapter.processEvent(ApplicationListenerMethodAdapter.java:142)
at org.springframework.context.event.ApplicationListenerMethodAdapter.onApplicationEvent(ApplicationListenerMethodAdapter.java:106)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:163)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:136)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:381)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:348)
When I move the #EventListener annotation down to each concrete listener the exception disappears and things behave as expected with the exception of testSendingEventWithGenericsWithExtendedUniquePayload.
Questions
Q1) Is it a valid usage pattern to put #EventListener on a method of a abstract super class? I was hoping to implement common behavior there.
Q2) I read about implementing ResolvableTypeProvider on my event in the spring docs. My understanding was that this would allow me to avoid having to create many concrete subclasses for each payload type. This is what I'm attempting to test in testSendingEventWithGenericsWithExtendedUniquePayload. I'm expecting the event fired in this test to be handled by TestEventWithGenericsExtendedUniquePayloadListener but it's not. Have I misunderstood something here?
Spring: 4.2.4.RELEASE
Java: 1.8.0_65
Thanks for your help
Oliver
Test Code
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.core.ResolvableType;
import org.springframework.core.ResolvableTypeProvider;
import org.springframework.stereotype.Component;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import static org.springframework.core.ResolvableType.*;
/**
* #author Oliver Henlich
*/
#ContextConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
#DirtiesContext
public class EventListenerTest {
private static final Logger log = LoggerFactory.getLogger(EventListenerTest.class);
#Autowired
protected transient ApplicationEventPublisher applicationEventPublisher;
#Test
public void testSendingEvent1() {
log.info("testSendingEvent1");
// this should go to TestEvent1Listener
applicationEventPublisher.publishEvent(new TestEvent1(new UniquePayload()));
}
#Test
public void testSendingEventWithGenerics() {
log.info("testSendingEventWithGenerics");
// this should go to TestEventWithGenericsListener
applicationEventPublisher.publishEvent(new TestEventWithGenerics<>(new UniquePayload()));
}
#Test
public void testSendingEventWithGenericsWithExtendedUniquePayload() {
log.info("testSendingEventWithGenerics");
// I was expecting this to go to TestEventWithGenericsExtendedUniquePayloadListener
applicationEventPublisher.publishEvent(new TestEventWithGenerics<>(new ExtendedUniquePayload()));
}
#Test
public void testSendingEvent2() {
log.info("testSendingEvent2");
// there is no listener for this one
applicationEventPublisher.publishEvent(new TestEvent2(new UniquePayload()));
}
// LISTENERS --------------------------------------------------------------
interface TestDataEventListener<E extends TestDataEvent> {
#SuppressWarnings("unused")
List<String> handleEvent(E event);
}
abstract static class AbstractTestDataEventListener<E extends TestDataEvent> implements TestDataEventListener<E> {
#Override
#EventListener
public final List<String> handleEvent(E event) {
return onEvent(event);
}
public abstract List<String> onEvent(E event);
}
#Component
static final class TestEvent1Listener extends AbstractTestDataEventListener<TestEvent1> {
#Override
public List<String> onEvent(TestEvent1 event) {
log.info("Listener {} handled {}", this, event);
return Collections.emptyList();
}
}
#Component
static final class TestEventWithGenericsListener extends AbstractTestDataEventListener<TestEventWithGenerics> {
#Override
public List<String> onEvent(TestEventWithGenerics event) {
log.info("Listener {} handled {}", this, event);
return Collections.emptyList();
}
}
#Component
static final class TestEventWithGenericsExtendedUniquePayloadListener extends AbstractTestDataEventListener<TestEventWithGenerics<ExtendedUniquePayload>> {
#Override
public List<String> onEvent(TestEventWithGenerics<ExtendedUniquePayload> event) {
log.info("Listener {} handled {}", this, event);
return Collections.emptyList();
}
}
// EVENTS -----------------------------------------------------------------
interface TestDataEvent<T extends Unique> extends ResolvableTypeProvider {
T load();
}
abstract static class AbstractTestDataEvent<T extends Unique> implements TestDataEvent<T> {
protected final UUID uuid;
private final ResolvableType resolvableType;
public AbstractTestDataEvent(T uniqueObject) {
uuid = uniqueObject.getUuid();
ResolvableType temp = ResolvableType.forClass(getClass());
if (temp.hasGenerics()) {
temp = forClassWithGenerics(getClass(), forInstance(uniqueObject));
}
resolvableType = temp;
log.info("class = {} resolvableType = {}", getClass(), resolvableType);
}
#Override
public ResolvableType getResolvableType() {
return resolvableType;
}
}
static final class TestEvent1 extends AbstractTestDataEvent<UniquePayload> {
public TestEvent1(UniquePayload uniqueObject) {
super(uniqueObject);
}
#Override
public UniquePayload load() {
return new UniquePayload(uuid);
}
}
static final class TestEvent2 extends AbstractTestDataEvent<UniquePayload> {
public TestEvent2(UniquePayload uniqueObject) {
super(uniqueObject);
}
#Override
public UniquePayload load() {
return new UniquePayload(uuid);
}
}
static final class TestEventWithGenerics<T extends UniquePayload> extends AbstractTestDataEvent<T> {
public TestEventWithGenerics(T uniqueObject) {
super(uniqueObject);
}
#Override
public T load() {
return (T) new UniquePayload(uuid);
}
}
static class UniquePayload implements Unique {
private final UUID uuid;
public UniquePayload() {
this(UUID.randomUUID());
}
public UniquePayload(UUID uuid) {
this.uuid = uuid;
}
#Override
public UUID getUuid() {
return uuid;
}
}
static class ExtendedUniquePayload extends UniquePayload {
}
interface Unique {
UUID getUuid();
}
#Configuration
#ComponentScan(basePackageClasses = EventListenerTest.class)
public static class ContextConfiguration {
}
}