Run Spring-Enabled #Component Method on Tomcat Startup - spring

My SpringMVC application runs in Tomcat. I have a Spring-enabled #Component with a method that needs to execute just once on Tomcat startup. It's a method to go into the Service/DAO layer and send an email.
Normally, the way to do a Tomcat Startup Java class call is in web.xml as a Servlet with load-on-startup (link).
<servlet>
<servlet-name>StartupEmail</servlet-name>
<servlet-class>com.app.StartupEmail</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
But that Servlet won't have access to my Spring layer with dependencies.
public class StartupEmail extends HttpServlet {
..
}
I can also have Cron-based Scheduled Jobs in SpringMVC, but they are time-based rather than on Tomcat Startup.
#Component
public class StatusScheduleJob {
#Autowired
private MyService myService;
#Scheduled(cron = "${statusjob.cron.expression}")
public void changeStatuses() {
myService.execute(); //...
}
}
statusjob.cron.expression=0 0 * * * *
So is there a good solution here?

If I understand the problem, there are several options depending on when exactly the startup code needs to be executed:
Javax #PostConstruct annotation on a bean
Implementing the InitializingBean interface
Implementing the ApplicationListener interface for ContextRefreshedEvent
Implementing the Spring CommandLineRunner interface
Here are a few references to learn about these options and more:
https://www.baeldung.com/running-setup-logic-on-startup-in-spring
https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/CommandLineRunner.html
https://docs.oracle.com/javaee/7/api/javax/annotation/PostConstruct.html

Related

EJB injected to #Controller

I am trying to inject EJB into spring #Controller (spring boot), each time I receive null pointer on stetelessBean.tt();
#Local
public interface IStetelessBean {
void tt();
}
#Stateless
public class StetelesBean implements IStetelessBean {
public void tt(){
System.out.println("ttt");
}
}
#Controller
public class PersonService {
#EJB
IStetelessBean stetelessBean;
#RequestMapping("/test")
public void test(){
stetelessBean.tt();
}
}
Any idea? I am not sure what is wrong.
Spring can only inject beans, it knows about. By default, EJBs are not registered as Spring Beans. Also the #EJB annotation is not recognised by Spring. The only examples in the Spring documentation use XML configuration, so far i could not find any example for Java configuration. You might be better off with changing your EJB into a Spring component, if that's possible.

What exactly is the ResourceConfig class in Jersey 2?

I have seen a lot of Jersey tutorials that starts with something like
#ApplicationPath("services")
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
packages("com.abc.jersey.services");
}
}
without explaining what exactly the ResourceConfig class is. So where can I find its documentation, usage, etc.? Googling for "jersey resourceconfig" does not yield any official doc.
Some of my questions about this class and its usage are:
What things can I do inside the subclass of ResourceConfig?
Do I need to register the subclass of ResourceConfig somewhere so that it can be found or is it automatically detected by Jersey?
If the subclass is automatically detected what happens if I have multiple subclasses of ResourceConfig?
Is the purpose of ResourceConfig the same as the web.xml file? If so what happens if I have both in my project? Does one of them take precedence over the other?
Standard JAX-RS uses an Application as its configuration class. ResourceConfig extends Application.
There are three main ways (in a servlet container) to configure Jersey (JAX-RS):
With only web.xml
With both web.xml and an Application/ResourceConfig class
With only an Application/ResourceConfig class annotated with #ApplicationPath.
With only web.xml
It is possible to configure the application in a standard JAX-RS way, but the following is specific to Jersey
<web-app>
<servlet>
<servlet-name>jersey-servlet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.mypackage.to.scan</param-value>
</init-param>
</servlet>
...
<servlet-mapping>
<servlet-name>jersey-servlet</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
...
</web-app>
Since Jersey runs in a servlet container, it is only right that the Jersey application runs as a servlet. The Jersey Servlet that handles incoming requests is the ServletContainer. So here we declare it as the <servlet-class>. We also configure an <init-param> telling Jersey which package(s) to scan for our #Path and #Provider classes so it can register them.
Under the hood, Jersey will actually create a ResourceConfig instance, as that's what it uses to configure the application. Then it will register all the classes that it discovers through the package scan.
With both web.xml and Application/ResourceConfig
If we want to programmatically configure our application with an Application or ResourceConfig subclass, we can do so with one change to the above web.xml. Instead of setting an init-param to scan for packages, we use an init-param to declare our Application/ResourceConfig subclass.
<servlet>
<servlet-name>jersey-servlet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.example.JerseyApplication</param-value>
</init-param>
<servlet-mapping>
<servlet-name>jersey-servlet</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
</servlet>
package com.example;
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
packages("com.abc.jersey.services");
}
}
Here, we configure the init-param javax.ws.rs.Application with the fully qualified name of our ResourceConfig subclass. And instead of using the init-param that tells Jersey which package(s) to scan, we just use the convenience method packages() of the ResourceConfig.
We could also use the methods register() and property() to register resources and providers, and to configure Jersey properties. With the property() method, anything that can be configured as an init-param, can also be configured using the property() method. For instance instead of calling packages(), we could do
public JerseyApplication() {
property("jersey.config.server.provider.packages",
"com.mypackage.to.scan");
}
With only Application/ResourceConfig
Without a web.xml, Jersey needs a way for us to provide the servlet-mapping. We do this with the #ApplicationPath annotation.
// 'services', '/services', or '/services/*'
// is all the same. Jersey will change it to be '/services/*'
#ApplicationPath("services")
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
packages("com.abc.jersey.services");
}
}
Here with the #ApplicationPath, it's just like if we configured the servlet mapping in the web.xml
<servlet-mapping>
<servlet-name>JerseyApplication</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
When using only Java code for configuration, there needs to be some way for Jersey to discover our configuration class. This is done with the use of a ServletContanerInitializer. This is something that was introduced in the Servlet 3.0 Specification, so we cannot use "Java only" configuration in earlier servlet containers.
Basically what happens is that the implementor of the initializer can tell the servlet container what classes to look for, and the servlet container will pass those classes to the initializer onStartup() method. In Jersey's implementation of the initializer, Jersey configures it to look for Application classes and classes annotated with #ApplicationPath. See this post for further explanation. So when the servlet container starts the application, Jersey's initializer will get passed our Application/ResourceConfig class.
What things can I do inside the subclass of ResourceConfig
Just look at the javadoc. Its mostly just registration of classes. Not much else you need to do with it. The main methods you will be using are the register(), packages(), and property() methods. The register() method lets you manually register classes and instances of resources and providers manually. The packages() method, discussed earlier, lists the package(s) you want Jersey to scan for #Path and #Provider classes and register them for you. And the property() method allows you to set some configurable properties 1.
The ResourceConfig is just a convenience class. Remember, it extends Application, so we could even use the standard Application class
#ApplicationPath("/services")
public class JerseyApplication extends Application {
private final Set<Class<?>> classes;
private final Set<Object> singletons;
public JerseyApplication() {
// configure in constructor as Jersey
// may call the getXxx methods multiple times
this.classes = new HashSet<>();
this.classes.add(MyResource.class);
this.singletons = new HashSet<>();
this.singletons.add(new MyProvider());
}
#Override
public Set<Class<?>> getClasses() {
return this.classes;
}
#Override
public Set<Object> getSingletons() {
return this.singletons;
}
#Override
public Map<String, Object> getProperties() {
final Map<String, Object> properties = new HashMap<>();
properties.put("jersey.config.server.provider.packages",
"com.mypackage.to.scan");
return properties;
}
}
With a ResourceConfig, we would just do
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
register(MyResource.class);
register(new MyProvider());
packages("com.mypackages.to.scan");
}
}
Aside from being more convenient, there are also a few thing under the hood that help Jersey configure the application.
An SE Environment
All the examples above assume you are running in an installed server environment, e.g. Tomcat. But you can also run the app in an SE environment, where you run an embedded server and start the app from a main method. You will sometimes see these examples when searching around for info, so I want to show what that looks like, so that if you ever do come across this, you are not surprised and know how it differs from your setup.
So sometimes you will see an example like
ResourceConfig config = new ResourceConfig();
config.packages("com.my.package");
config.register(SomeFeature.class);
config.property(SOME_PROP, someValue);
What is most likely happening here is that the example is using an embedded server, like Grizzly. The rest of the code to start the server might be something like
public static void main(String[] args) {
ResourceConfig config = new ResourceConfig();
config.packages("com.my.package");
config.register(SomeFeature.class);
config.property(SOME_PROP, someValue);
String baseUri = "http://localhost:8080/api/";
HttpServer server = GrizzlyHttpServerFactory
.createHttpServer(URI.create(baseUri), config);
server.start();
}
So in this example, there is a standalone server being started and the ResourceConfig is used to configure Jersey. The different here and from previous examples is that in this example, we are not extending the ResourceConfig, but instead just instantiating it. It wouldn't be any different if we were to do
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
packages("com.my.package");
register(SomeFeature.class);
property(SOME_PROP, someValue);
}
}
HttpServer server = GrizzlyHttpServerFactory
.createHttpServer(URI.create(baseUri), new JerseyConfig());
Say you were going through some tutorial and it showed a configuration for a standalone app where they instantiate the ResourceConfig. But you are running your app in an installed servlet container and have been using the earlier configuration where you are extending the ResourceConfig. Well now you know what the difference is and what changes you need to make. I've seen people do some really weird stuff because they didn't understand this difference. For example I saw someone instantiating a ResourceConfig inside a resource class. So this is why I added this extra little piece; so you don't make the same mistake.
Footnotes
1. There are a number of different configurable properties. The link to the ServerProperties are just some general properties. There are also different properties related to specific features. The documentation should mention these properties in the section of the docs related to that feature. For a complete list of all configurable properties, you can look at all the Jersey constants and look for the ones where the string value starts with jersey.config. If you are using a web.xml, then you would use the string value as the init-param param-name. If you are using Java config (ResourceConfig), then you would call property(ServerProperties.SOME_CONF, value)

Autowired object is null in Rest controller when deployed on JBoss EAP

I am using Springboot and RESTEasy to create a small webapp, in my Controller class I am doing #Autowire for my Dao class. Whenever I deploy the code, the dao reference variable always ends up with null value. I have used #Component for controller and in mail Application class I have used #SpringBootApplication and at my dao class also I have added #Repository and #Service.
Please give some suggestions where exactly i am doing wrong?
Note: Works fine if I run it as a standalone Springboot app. But this issue occurs when deploy in JBoss server.
Code format is displayed below: While debugging, at line , List<DataDto> dataList = dao.findData(); always dao is null, because of which API call fails.
#Component
#Path("/")
public class apiController {
#Autowired
private ApiDao dao;
public void setApiDao(ApiDao dao) {
this.dao = dao;
}
#GET
#Path("/getData")
#Produces(MediaType.APPLICATION_JSON)
public List<DataDto> getDetails(){
List<DataDto> dataList = dao.findData();
return logList;
}
}
Dao class code is as below:
#Repository
#Service
public class ApiDao {
private final Logger log = LoggerFactory.getLogger(ApiDao.class);
private JdbcTemplate jdbcTemplate;
#Autowired
public ApiDao(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public List<SystemEntity> findData() throws SystemException{
return entityList;
}
}
And for configuration i have used below code and in pom.xml added required dependencies:
#Component
#ApplicationPath("/rest/")
public class JaxrsApplication extends Application {
}
The Problem
JBoss provides inbuilt support for RESTEasy. So in this case the apiController is initialized twice:
Once by Spring
Once by JBoss.
The autowiring happens under the hood in the instance initialized by spring but when a call is triggered to the apiController it is handled by the instance initialized by JBoss.
Solution
Disable JBoss from initializing RESTEasy Controllers. In your spring boot application create a web.xml under src/main/webapp/WEB-INF and add the following context parameters:
<context-param>
<param-name>resteasy.scan</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>resteasy.scan.providers</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>resteasy.scan.resources</param-name>
<param-value>false</param-value>
</context-param>

Register spring bean as an apache camel route builder with java config

apache camel documentation describes how to register a route builder with #Component and SpringRouteBuilder and then jumps to the xml code to do
<camelContext xmlns="http://camel.apache.org/schema/spring">
<!-- and then let Camel use those #Component scanned route builders -->
<contextScan/>
</camelContext>
How can I do the same with java config? I've got
package x.y.camel;
#Component
public class MyRouteBuilder extends SpringRouteBuilder {...}
and
#EnableWebMvc
#EnableAutoConfiguration
#ComponentScan(basePackages = {"x.y"})
public class Application implements WebApplicationInitializer {
#Bean
public SpringCamelContext camelContext(ApplicationContext applicationContext) throws Exception {
SpringCamelContext camelContext = new SpringCamelContext(applicationContext);
return camelContext;
}
The component is picked up by spring and created, that part is fine. I can register the route by camelContext.addRoutes(new MyRouteBuilder());. The only bit is missing is how to tell camel context to pick up the route if it's managed as a spring bean.
Your approach does not work, because you don't create your camel context with the CamelContextFactoryBean. This is where the logic is hidden that looks for Spring Bean Camel Routes in your classpath.
The easiest solution to the problem is to add a xml-based Spring context configuration that references this factory bean!
Alternatively, you can try calling the factory bean from your Application class (see this link: FactoryBeans and the annotation-based configuration in Spring 3.0), but calling a factory bean from a #Configuration class is tricky, because they are both part of mechanisms that are not build for compatibility. Especially, since CamelContextFactoryBean is also implementing InitialisingBean.
It turns out I was pretty close to the solution. All I had to do is to add a ComponentScan annotation on my CamelConfiguration class that I already had.
#Configuration
#ComponentScan("x.y.camel")
public class CamelConfig extends CamelConfiguration {
}
And then remove public SpringCamelContext camelContext(ApplicationContext applicationContext) from my Application class.
That's it - the RouteBuilder is picked up automatically.

init a spring bean from web.xml

I am updating an existing Java EE web application that uses Spring.
In my web.xml, there is a servlet defined as follows:
<servlet>
<display-name>My Example Servlet</display-name>
<servlet-name>MyExampleServlet</servlet-name>
<servlet-class>com.example.MyExampleServlet</servlet-class>
</servlet>
now, in this class I need to add an #Autowite annotation:
class MyExampleServlet extends HttpServlet {
#Autowired (required = true)
MyExampleBean myExampleBean;
[...]
}
the problem is that MyExampleBean is initialized by the Application Server
(in my case, weblogic.servlet.internal.WebComponentContributor.getNewInstance...)
so, Spring is not aware of that, and Spring does not have a chance to wire "myExampleBean".
How to solve that?
that is, how I need to modify web.xml or MyExampleServlet so that MyExampleServlet gets the reference to myExampleBean?
A possibility would be to add this init code inside MyExampleServlet,
but it requires a reference to servletContext. How to get a reference to servletContext?
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);
myExampleBean = (MyExampleBean) context.getBean("myExampleBean");
I see, HttpServlet/GenericServlet has a getServletContext() method,
(and the application server calls first the servlet's init(ServletConfig config), and config contains a reference to servletContext).
See http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/GenericServlet.html
The code modified:
class MyExampleServlet extends HttpServlet {
MyExampleBean myExampleBean;
#Override
public void init() throws ServletException {
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
myExampleBean = (MyExampleBean) context.getBean("myExampleBean");
}
[...]
}
in your application context xml, you need something like
<bean id="myExampleBean" class="path/to/myExampleBean">

Resources