Command-line application using Spring context never ends - java

I created mini framework to executing some spring beans from main() method rather than deploying and running full-fledged webapp just to launch those beans. It looks like this:
public abstract class BaseLauncher {
private static final String APP_CONTEXT_PATH = "com/project/dev/launchers/launchersApplicationContext.xml";
static ApplicationContext context = new ClassPathXmlApplicationContext(APP_CONTEXT_PATH);
protected void launch() {
context.getBean(getClass()).perform();
//The process never ends so we want to know when we can kill it
System.out.println("launcher finished");
}
#Transactional
abstract protected void perform();
}
And example launcher looks like this:
#Component
public class ParamLoaderLauncher extends BaseLauncher {
#Inject
ParamLoader paramLoader;
public static void main(String[] args) {
new ParamLoaderLauncher().launch();
}
#Override
protected void perform() {
paramLoader.loadParams();
}
}
It all works great except that when the invoked bean method is finished, application just keep running and we need to kill it manually. I guess it has something to do with using spring app context. Maybe some special spring-related non-deamon thread is launched? If so, is there any way to kill it? Or what other cause of this may be in such simple code?

For standalone applications (not running in any container), shutdownhook needs to be registered for clean shutdown of the spring container when application exits.

Related

How to test #PreDestroy and #Bean methods inside a class

I have the following methods inside a class
#Bean(name = "boggle")
public BoggleImpl createBoggleClient() {
BoggleBuilder builder = new BoggleBuilder()
.setRegistryId(getRegistryId())
.setRegistryPassword(getPassword())
return new BoggleFeatureImpl(builder.build());
}
and am using the bean inside a class such as
class A {
private final Boggle boggle;
#PreDestroy
public void destroy() {
if (boggle != null) {
boggle.closeConnection();
}
}
}
Now my code coverage in unit tests show these methods as not covered. Not sure what can i do to cover these methods. Any pointers on the same.
Using SpringJUnit4ClassRunner the ApplicationContext is shared between all the running test cases and the #PreDestroy is called only when the ApplicationContext is closed.
Spring has this behavior because you can be working in a big application which has a slow startup and can be costly to create a new context.
You could annotate your test method with the #DirtiesContext annotation.
From it's javadoc:
Test annotation which indicates that the ApplicationContext associated
with a test is dirty and should therefore be closed and removed from
the context cache.
Use this annotation if a test has modified the
context — for example, by modifying the state of a singleton bean,
modifying the state of an embedded database, etc. Subsequent tests
that request the same context will be supplied a new context.
In this example, class A must be a spring bean. Methods annotated with #PreDestroy are called by the application context when it gets closed. Usually, this happens when the application gets shut down gracefully.
So basically you can "simulate" the situation of closing the application context even from a simple unit test, you don't have to start spring in the test for this.
Treat this method as a regular method with some code regardless of the fact that its called by spring:
class A {
private final Boggle boggle;
public class A(Boggle boggle)
{this.boggle = boggle;}
#PreDestroy
public void destroy() {
if (boggle != null) {
boggle.closeConnection();
}
}
}
Then a test can look like this:
class ATest {
#Test
public void test_boggle_closes_connection_when_the_bean_gets_destroyed() {
// given:
Boggle boggle = Mockito.mock(Boggle.class);
A underTest = new A(boggle);
// when:
underTest.destroy();
// then: verify that boggle closes connection
Mockito.verify(boggle, times(1)).closeConnection();
}
}

Spring Boot - Use Application Listener

After starting my spring boot application I want to start an customer process like creating required folders, files, etc. For that I'm using ApplicationListener<ApplicationReadyEvent>. This works like expected. But I'm building my spring application context with SpringApplicationBuilder. Every child notifies that the application is started correctly. So my customer post-process startes even more than one time.
#SpringBootApplication
#EnableConfigurationProperties(value = {StorageProperties.class})
#EnableAsync
public class Application {
public static void main(String[] args) {
SpringApplicationBuilder parentBuilder
= new SpringApplicationBuilder(Application.class);
parentBuilder.child(Config1.class)
.properties("server.port:1443")
...
.run(args);
parentBuilder.child(Config2.class)
.properties("server.port:2443")
...
.run(args);
}
}
My first idea was, that I can create manuelly a new Bean with #Bean in Config1 for my Event-Listener. But I was not able to overhand the configuration file StorageProperties.class, which is necessary for this class.
Because the Listener has an constructor based dependency injection:
private final Path mPathTo;
public AfterStart(StorageProperties prop) {
this.mPathTo = Paths.get(prob.getPath());
}
How can I be able to start the listener just once per start?
For everyone who is interested in this question. This solution worked for me:
public void onApplicationEvent(ApplicationReadyEvent e) {
if (e.getApplicationContext().getParent == null) {
System.out.println("******************************");
System.out.println("Post-process begins.");
System.out.println("******************************");
}
}

combination of jax-rs (rest api) and websockets - where to put common initialization

I am developing a project which involves JAX-RS (for REST API) and Websocket (for notifications). The project will be deployed as a WAR into a application server.
For JAX-RS, I do the following:
#ApplicationPath("/")
public class MyApplicationREST extends ResourceConfig {
public MyApplicationREST() {
... initialization here ...
}
}
For Websockets, I do the following:
public class MyApplicationWebsockets implements ServerApplicationConfig {
... callbacks for discovery of endpoints here ...
}
Both classes are perfectly picked up by the application server (Tomcat in my case) when the WAR is deployed and work fine in vacuum.
However, in both classes, I need a reference to a command instance (being the database connection in this case, but it can be anything). I cannot instantiate it in one of the two classes above (and use it in the other), as there is no guarantee of the initialization order of the two classes.
What is the best way to do this?
Initialization
(1) Create a class that implements ServletContextListener.
(2) Write your initialization code in contextInitialized(ServletContextEvent) method.
public class MyContextListener implements ServletContextListener
{
#Override
public void contextInitialized(ServletContextEvent context)
{
// Your initialization code here.
}
#Override
public void contextDestroyed(ServletContextEvent context)
{
// Your finalization code here.
}
}
(3) Register the class as a listener in web.xml.
<listener>
<listener-class>com.example.MyContextListener</listener-class>
</listener>
Shared Instance
Regarding a shared instance, singleton pattern is one of possible means to achieve it.
public class DB
{
private static final DB sInstance = new DB();
// Private constructor to prevent DB instances from being created by others.
private DB()
{
}
// Get the singleton instance.
public static DB getInstance()
{
return sInstance;
}
}

How to check for start and stop with spring framework?

Hi I need to send an email when my application starts and and email when my application stops.
Using spring...
public class Main {
public static void main(String[] args) {
FileSystemXmlApplicationContext fac = new FileSystemXmlApplicationContext("config/applicationContext.xml");
}
}
The rest is wired up through the application context...
I suppose I can just inject a simple bean that implements smart life cycle and send an email from within the start() and stop() methods?
You can simply use a bean in default singleton scope, and declare its init and destroy method. The bean need no adherence to Spring and could be something like :
public class StartAndStop {
public void onStart() {
// send the mail signaling start of application
...
}
public void onStop() {
// send the mail signaling stop of application
...
}
}
In xml config :
<bean class="org.example.StartAndStop" init-method="onStart" destroy-method="onStop"/>
And with Java configuration
#Configuration
public class Configurer {
#Bean(initMethod="onStart", destroyMethod="onStop")
StartAndStop startAndStop() {
return new StartAndStop();
}
... other beans configuration ...
}
Of course, you can also use spring to set properties on the bean ...
Spring automatically raises events in these sitatuations.
You can listen for events by creating an ApplicationListener bean:
#Component
public class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(final ContextRefreshedEvent event) {
// is called whenever the application context is initialized or refreshed
}
}
Spring raises the following application context events:
ContextClosedEvent (ApplicationContext gets closed)
ContextRefreshedEvent (ApplicationContext gets initialized or refreshed)
ContextStartedEvent (ApplicationContext gets stopped)
ContextStoppedEvent (ApplicationContext gets stopped)
See Standard and Custom Events documentation

How do you inject jdbiFactory DAOs into a Dropwizard Command?

I'm starting to work with Dropwizard and I'm trying to create a Command that requires to use the database. If someone is wondering why I'd want to do that, I can provide good reasons, but this is not the point of my question anyway. It's about dependency inversion and Service initialization and run phases in Dropwizard.
Dropwizard encourages to use its DbiFactory to build DBI instances but in order to get one, you need an Environment instance and/or the database configuration:
public class ConsoleService extends Service<ConsoleConfiguration> {
public static void main(String... args) throws Exception {
new ConsoleService().run(args);
}
#Override
public void initialize(Bootstrap<ConsoleConfiguration> bootstrap) {
bootstrap.setName("console");
bootstrap.addCommand(new InsertSomeDataCommand(/** Some deps should be here **/));
}
#Override
public void run(ConsoleConfiguration config, Environment environment) throws ClassNotFoundException {
final DBIFactory factory = new DBIFactory();
final DBI jdbi = factory.build(environment, config.getDatabaseConfiguration(), "postgresql");
// This is the dependency I'd want to inject up there
final SomeDAO dao = jdbi.onDemand(SomeDAO.class);
}
}
As you can see, you have the configuration for your Service and its Environment in its run() method, but commands need to be added to the Service's bootstrap in its initialize() method.
So far, I've been able to achieve this by extending ConfiguredCommand in my Commands and creating DBI instances inside their run() methods, but this is a bad design, because dependencies should be injected into the object instead of creating them inside.
I'd prefer to inject DAOs or any other dependencies of my Commands through their constructor, but this seems currently impossible to me, as the Environment and the configuration are not accesible in Service initialization, when I need to create and add them to its bootstrap.
Does anyone know how to achieve this?
Can you use the EnvironmentCommand?
This is how I use Guice with Dropwizard. Inside your run() method add the line
Guice.createInjector(new ConsoleModule());
Create the class ConsoleModule
public class ConsoleModule extends AbstractModule {
public ConsoleModule(ConsoleConfiguration consoleConfig)
{
this.consoleConfig = consoleConfig;
}
protected void configure()
{
bind(SomeDAO.class).to(SomeDAOImpl.class).in(Singleton.class)
}
}

Categories