Spring Boot Tomcat deployment - spring

I am having issue with deploying spring boot application in Tomcat 8. I am getting the error below while starting application.
java.lang.IllegalStateException: Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml!
our webinitializer
public class SpringWebMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SecurityConfiguration.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] {WebMvcConfiguration.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}}

I fixed my own problem by changing my web fertilizer to
public class SpringWebMvcInitializer extends AbstractSecurityWebApplicationInitializer {
// nothing here
}
reference -
http://www.mkyong.com/spring-security/spring-security-hello-world-annotation-example/

Related

Spring MVC - Dispatcher Servlet can't find any page

I do really simple demo web app using Spring mvc, Java class annotations and .jsp instead of .html.
When I start Tomcat on localhost - I always get 404 error. Where do I do mistake?
Config.class
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.mylov.springsecurity.demo.config")
public class Config {
//Define bean for ViewResolver
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/view/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
Dispatcher Servlet Initialization
public class DispatcherServletInit extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{Config.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
Controller
#Controller
public class DemoController {
#GetMapping({"", "/"})
public String showHome() {
return "home";
}
}
Project Structure:
You need to scan packages under demo package. So Spring will find your Controllers and Config classes. But now you point to only config. So package 'controller' won't be scan.
Try to do this:
#ComponentScan(basePackages = "com.mylov.springsecurity.demo")
Try providing the mapping as below so that all url's are mapped with the servlet:
public class DispatcherServletInit extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{Config.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/*"};
}
}
Also change the base packages to as below so that the controller class is also picked up for component scanning :
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.mylov.springsecurity.demo")
public class Config {
..........
}

spring boot,Where's the Root WebApplicationContext and Servlet WebApplicationContext

I use spring-boot-starter-web 1.5.17.I can't find any auto configuration about build Root WebApplicationContext and Servlet WebApplicationContext.
When not use spring boot,we need do this
public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{SecurityAdminConfig.class, DataSourceConfig.class, JavaConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{WebMvcConfig.class};
}
//controller、service
I know WebMvcAutoConfiguration do a lot of spring MVC configuration,but i can't find about auto build Root WebApplicationContext and Servlet WebApplicationContext.
public abstract class AbstractAnnotationConfigDispatcherServletInitializer
extends AbstractDispatcherServletInitializer {
#Override
protected WebApplicationContext createRootApplicationContext() {
Class<?>[] configClasses = getRootConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) {
AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
rootAppContext.register(configClasses);
return rootAppContext;
}
else {
return null;
}
}
#Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext servletAppContext = new AnnotationConfigWebApplicationContext();
Class<?>[] configClasses = getServletConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) {
servletAppContext.register(configClasses);
}
return servletAppContext;
}
protected abstract Class<?>[] getRootConfigClasses();
protected abstract Class<?>[] getServletConfigClasses();
}
How can know this beans go Root WebApplicationContext or Servlet WebApplicationContext?
image here
There is, by default, a single application context in a Spring Boot web (or otherwise) application. It is created by SpringApplication when your application starts.
The right way to do it would be this:
public class App {
public static void main(String[] args) {
new SpringApplicationBuilder()
.parent(ParentConfig.class).web(WebApplicationType.NONE)
.child(WebConfig.class).web(WebApplicationType.SERVLET)
.sibling(RestConfig.class).web(WebApplicationType.SERVLET)
.run(args);
}
}
I have taken it from here:
However, it is still not clear why by default everything is in the same context..
Also, I am not sure if that's fine that other beans created by WebMvcAutoconfiguration will be shared across all child contexts.

How can I run jobs after spring beans is initialized?

I am working on Spring 4 mvc and hibernate
I want to run code on the server startup that will use the get data from the database then do some business logic
where can I put my code I tried to put the code
org.springframework.web.servlet.support.AbstractDispatcherServletInitializer.onStartup(ServletContext)
but I was not able to use #Autowired variables
public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Autowired
TaskDAO task;
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { SpringRootConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { SpringWebConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
task.getAllTasks()
// TODO Auto-generated method stub
super.onStartup(servletContext);
}
}
You are not able to autowire variables because your class is not managed by spring. So annotate your class with #Component annotation.
Then you can define a method that will do your logic (for example onStartup method) and annotate it with the #PostConstruct annotation as explained in this answers.
How to call a method after bean initialization is complete?
It will execute the method after the beans initialization.
This could be your class:
#Component
public class WebInitializer{
#Autowire
TaskDAO task;
#PostConstruct
private void onStartup(){
task.getAllTasks();
// Do whatever you want
}
}

Spring Profiles not recognized in a Web Application

I'm trying to implement Spring Profiles to load a specific class implementation based on the profile specified. The profile to use is specified as a property (spring.profiles.active) within a properties file included in the classpath.
Source here: https://github.com/overattribution/spring-profile-test
public interface MyService {
public void doSomething();
}
#Service
#Profile("preprod")
public class MyServicePreProdImpl implements MyService {
private final Logger LOG = LoggerFactory.getLogger(MyServicePreProdImpl.class);
#Override
public void doSomething() {
LOG.debug("Doing something in " + MyServicePreProdImpl.class.getName());
}
}
#Service
#Profile("prod")
public class MyServiceProdImpl implements MyService {
private final Logger LOG = LoggerFactory.getLogger(MyServiceProdImpl.class);
#Override
public void doSomething() {
LOG.debug("Doing something in " + MyServiceProdImpl.class.getName());
}
}
However, I'm getting the following error:
No qualifying bean of type [com.example.profileservice.MyService] found for dependency.
What am I missing?
UPDATE 1:
I'm manually setting the active profile during web application initialization, but I'm still getting the "No qualifying bean found" error. Changes can be seen here: https://github.com/overattribution/spring-profile-test/commit/09175a10b28ea8e5a08b43ad1416431bcf094c9d
Ok I got it to work. Profiles need to be set within the root context (as opposed to servlet context) during web application initialization. I have done so in my WebAppInitializer class like so:
https://github.com/overattribution/spring-profile-test/blob/f895a8bc67dc1f6ba2fcedb58b73a19cc5cf8cf7/src/main/java/com/example/config/WebAppInitializer.java
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
/**
* Overriding to include setting active profile.
*/
#Override
protected WebApplicationContext createRootApplicationContext() {
Class<?>[] configClasses = getRootConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) {
AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
String[] activeProfiles = getActiveProfiles();
rootAppContext.getEnvironment().setActiveProfiles(activeProfiles);
rootAppContext.register(configClasses);
return rootAppContext;
}
else {
return null;
}
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] {
ApplicationConfig.class
};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] {
WebMvcConfig.class
};
}
#Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
return new Filter[] {characterEncodingFilter};
}
protected String[] getActiveProfiles() {
PropertySource propertySource = null;
try {
propertySource = new ResourcePropertySource("classpath:application.properties");
String profilesString = (String) propertySource.getProperty(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME);
return profilesString.split(",");
} catch (IOException e) {
throw new ResourceAccessException("application.properties is not available on the classpath");
}
}
}
A profile is a named logical grouping that may be activated programmatically via ConfigurableEnvironment.setActiveProfiles(java.lang.String...) or declaratively through setting the spring.profiles.active property, usually through JVM system properties, as an environment variable, or for web applications as a Servlet context parameter in web.xml.
I would say that it is not possible to specify active profile as a property within your properties file unless you use Spring Boot that also enables you to set the active profile in application.properties file.
Try to use one of the options above.

Change main endpoint in Spring Data Rest (usind Spring Boot)

Im building a small application using Spring (Boot, Data, Data Rest).
I have some JpaRepositories that aumotatically are exported as Rest endpoints.
What i want to do is to change the base path from / to /api.
Now to list all people for example i do a GET to http://localhost:8080/people and i want the url to be http://localhost:8080/api/people.
I tried adding this config class but nothing happened (it seems that Spring Boot overrides this config):
public class SpringWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer{
#Override
protected Class<?>[] getRootConfigClasses()
{
return new Class<?>[] { Application.class};
}
#Override
protected Class<?>[] getServletConfigClasses()
{
return new Class<?>[] { RestExporterRestConfig.class, RepositoryRestMvcConfiguration.class };
}
#Override
protected String[] getServletMappings()
{
return new String[] { "/api/*" };
}
}
My Application.java:
#Configuration
#ComponentScan
#Import(RestExporterRestConfig.class)
#EnableJpaRepositories
#EnableAutoConfiguration
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
and RestExporterRestConfig:
#Configuration
public class RestExporterRestConfig extends RepositoryRestMvcConfiguration {
#Bean
public Validator validator() {
return new LocalValidatorFactoryBean();
}
#Override
protected void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener v) {
v.addValidator("beforeCreate", validator());
}
#Bean
#Qualifier
public DefaultFormattingConversionService defaultConversionService() {
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
conversionService.addConverter(StringToDate.INSTANCE);
return conversionService;
}
#Bean
public DomainClassConverter<?> domainClassConverter() {
return new DomainClassConverter<DefaultFormattingConversionService>(defaultConversionService());
}
}
Well i figured it out. SpringWebAppInitializer is not necesary in this case. I just added this code to Application.java:
#Bean
public ServletRegistrationBean dispatcherRegistration(DispatcherServlet dispatcherServlet) {
ServletRegistrationBean reg = new ServletRegistrationBean(dispatcherServlet);
reg.addUrlMappings("/api/*");
return reg;
}
I think this is the correct way to modify (add, change mappings, etc) servlets using Spring Boot.

Resources