Use tomcat instead of netty for rscket - spring-boot

I want to leverage on servlets and filters so I want to use tomcat and, in general, servlet 3.1 to handle the communication.
I tried to do the following:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-rsocket</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-reactor-netty</artifactId>
</exclusion>
</exclusions>
It works bringing up a tomcat but I lost the endpoint!
Here's what I do to register it:
spring.rsocket.server:
transport: websocket
mapping-path: /topics
and:
#Configuration
public class RSocketConfig {
#Bean
public Mono<RSocketRequester> rSocketRequester(
RSocketStrategies rSocketStrategies,
RSocketProperties rSocketProps) {
return RSocketRequester.builder()
.rsocketStrategies(rSocketStrategies)
.connectWebSocket(getURI(rSocketProps));
}
private URI getURI(RSocketProperties rSocketProps) {
return URI.create(String.format("ws://localhost:%d%s",
rSocketProps.getServer().getPort(), rSocketProps.getServer().getMappingPath()));
}

Related

log4j2 java classes do not load application.properties entries with spring boot

I am using log4j2(log4j-core and log4j-api) with Spring boot 2.2.0.RELEASE. I want to masking sensitive data inmy json payload in the logs. I have written a custom LogMaskingConverter which extends LogEventPatternConverter.
#Plugin(name = "LogMaskingConverter", category = "Converter")
#ConverterKeys({ "spi", "trscId" })
#Configuration
public class LogMaskingConverter extends LogEventPatternConverter {
#Value("${maskingFields}")
private String maskingFields;
protected LogMaskingConverter(String name, String style) {
super(name, style);
}
public static LogMaskingConverter newInstance(String[] options) {
return new LogMaskingConverter("spi", Thread.currentThread().getName());
}
#Override
public void format(LogEvent event, StringBuilder outputMessage) {
........
}
private String mask(String message) {
....
}
The problem is that the maskingFields does not get loaded from the application properties file.I read that log4j2 gets loaded before spring boot. Hence I have renamed my xml to log4j2-spring.xml so that spring boot is the first to intialise and load all the properties before it gets read via LogMaskingConverter.
Also below are my pom.xml dependencies related to log4j2
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
To summarise below code does not fetch any values:
#Value("${maskingFields}")
private String maskingFields;

Spring boot 2 reactive web websocket conflict with datarest

I'm using spring boot 2 to create a project and use websocket using reactive web dependency. My application is worked correctly until I add datarest dependency. after I add datarest dependency application give
' failed: Error during WebSocket handshake: Unexpected response code: 404
is any way to resolve this conflict?.
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.integration/spring-integration-file -->
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-file</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
WebSocketConfiguration
#Configuration
public class WebSocketConfiguration {
#Bean
public IntegrationFlow fileFlow(PublishSubscribeChannel channel, #Value("file://${HOME}/Desktop/in") File file) {
FileInboundChannelAdapterSpec in = Files.inboundAdapter(file).autoCreateDirectory(true);
return IntegrationFlows.from(
in,
p -> p.poller(pollerFactory -> {
return pollerFactory.fixedRate(1000);
})
).channel(channel).get();
}
#Bean
#Primary
public PublishSubscribeChannel incomingFilesChannel() {
return new PublishSubscribeChannel();
}
#Bean
public WebSocketHandlerAdapter webSocketHandlerAdapter() {
return new WebSocketHandlerAdapter();
}
#Bean
public WebSocketHandler webSocketHandler(PublishSubscribeChannel channel) {
return session -> {
Map<String, MessageHandler> connections = new ConcurrentHashMap<>();
Flux<WebSocketMessage> publisher = Flux.create((Consumer<FluxSink<WebSocketMessage>>) fluxSink -> {
connections.put(session.getId(), new ForwardingMessageHandler(session, fluxSink));
channel.subscribe(connections.get(session.getId()));
}).doFinally(signalType -> {
channel.unsubscribe(connections.get(session.getId()));
connections.remove(session.getId());
});
return session.send(publisher);
};
}
#Bean
public HandlerMapping handlerMapping(WebSocketHandler webSocketHandler) {
SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
handlerMapping.setOrder(10);
handlerMapping.setUrlMap(Collections.singletonMap("/ws/files", webSocketHandler));
return handlerMapping;
}
}
spring-boot-starter-data-rest brings spring-boot-starter-web as a transitive dependency (so basically Spring MVC). This makes Spring Boot configure your application as a Spring MVC web application.
Spring Data REST does not currently support Spring WebFlux (see this issue for more information on that).
Your only choice is to remove the Spring Data REST dependency, as you can't have both Spring MVC and Spring WebFlux in the same Spring Boot application.

How to configure netty in spring boot 2

By default spring web flux uses netty which is single threaded event loop. How to configure spring boot so that a thread will be created for each core.
Thanks,
Lokesh
As described in the Spring Boot reference documentation, you can customize the Reactor Netty web server with a NettyServerCustomizer.
Here's an example with Spring Boot 2.1:
#Component
public class MyNettyWebServerCustomizer
implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {
#Override
public void customize(NettyReactiveWebServerFactory factory) {
factory.addServerCustomizers(new EventLoopNettyCustomizer());
}
}
class EventLoopNettyCustomizer implements NettyServerCustomizer {
#Override
public HttpServer apply(HttpServer httpServer) {
LoopResources loopResources = LoopResources.create(...);
return httpServer.runOn(loopResources);
}
}
You can change your dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!-- Exclude the Tomcat dependency -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Use Jetty instead -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
https://docs.spring.io/spring-boot/docs/current/reference/html/howto-embedded-web-servers.html

Spring boot not able to recognize JSP

I have configured Spring Boot using annotations.
I have the following files
1)AppStarter class for configuring spring boot
#Configuration
#EnableAutoConfiguration
#PropertySource(value = "classpath:app.properties", ignoreResourceNotFound = true)
#ComponentScan(basePackages = "com.sample.config")
public class AppStarter extends SpringBootServletInitializer{
#Value("${server.contextPath}")
private String contextPath;
#Value("${server.port:8080}")
private String port;
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean
public EmbeddedServletContainerFactory servletContainer() {
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
factory.setPort(Integer.valueOf(port));
factory.setContextPath(contextPath);
factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notfound.html"));
return factory;
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(AppStarter.class);
}
public static void main(String[] args) {
SpringApplication.run(AppStarter.class, args);
}
}
2)WebConfig class
#Configuration
#ComponentScan(basePackages = {"com.sample.rest"})
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter
{
#Bean
public static PropertySourcesPlaceholderConfigurer properties()
{
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
Resource[] resources = new ClassPathResource[]{new ClassPathResource("app.properties")};
configurer.setLocations(resources);
configurer.setIgnoreUnresolvablePlaceholders(true);
return configurer;
}
#Bean
public InternalResourceViewResolver viewResolver()
{
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/pages/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
3)app.properties
core_pool_size = 100
max_pool_size = 600
queue_capacity = 160
server.port=8080
spring.view.prefix: /WEB-INF/pages/
spring.view.suffix: .jsp
4)UserController class
#Controller
public class UserController extends AbstractController {
#RequestMapping(value = "/user/add")
public String user()
{
return "adduser";
}
}
5)pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>1.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>1.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.hateoas</groupId>
<artifactId>spring-hateoas</artifactId>
<version>0.16.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
</dependency>
<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer</artifactId>
<version>5.5.1</version>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
<exclusion>
<artifactId>org.slf4j</artifactId>
<groupId>slf4j-log4j12</groupId>
</exclusion>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<scope>provided</scope>
</dependency>
<!--Spring boot test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>1.2.0.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>4.3.7.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector-java.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
6)adduser.jsp which is in webapp/WEB_INF/pages folder
When I try to access my jsp through localhost:8080/sample/user/add i get :
org.springframework.web.servlet.PageNotFound | No mapping found for HTTP request with URI [/sample/WEB-INF/pages/adduser.jsp] in DispatcherServlet with name 'dispatcherServlet'
Can anyone could provide any help on this issue?
You configured: spring.view.prefix: /WEB-INF/jsp/
But your folder is: webapp/WEB_INF/pages
/jsp vs, /pages
You need to change one of them, so that they match!
Second: you need to request the url (That is written at your controller but not the path of the jsp!
So use:
localhost:8080/<yourAppName>/user/add instead of /sample/WEB-INF/pages/adduser.jsp
to use localhost:8080/samples/user/add, you would need to change the controller code to this,
#Controller
#RequestMapping("/samples")
public class UserController extends AbstractController {
#RequestMapping(value = "/user/add")
public String user()
{
return "adduser";
}
}
It looks like you have an embedded Tomcat container configured. JSP pages are not supported when Tomcat is embedded. http://docs.spring.io/spring-boot/docs/1.2.1.RELEASE/reference/htmlsingle/#boot-features-jsp-limitations
Try this:
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}

Spring Boot/Spring Integration Servlet Context/DelegatingWebMvcConfiguration issue

I'm not sure the best way to word this issue, because I have no idea why this happens.
When I start up my Spring Boot application without the spring-integration-core jar, my app starts up fine. The second I add the spring-boot-starter-integration or any spring-integration-core library to my Maven pom file the servlet context is always null on my DelegatingWebMvcConfiguration class and I get the following error:
java.lang.IllegalArgumentException: A ServletContext is required to configure default servlet handling
After doing some debugging, I see the DelegatingWebMvcConfiguration class initialized before the EmbeddedWebApplicationContext sets the servlet context for my application, which makes sense why the servlet context is null for my DelegatingWebMvcConfiguration and set for all the other classes initialized with postProcessBeforeInitialization in ServletContextAwareProcessor. Simply removing the Spring Integration dependency fixes the issue, but I'd like to use Spring Integration in my Boot application.
My question is what would cause the DelegatingWebMvcConfiguration to be created before the EmbeddedWebApplicationContext can call prepareEmbeddedWebApplicationContext method.
Spring dependencies using Spring Boot 1.1.8.RELEASE:
org.springframework.boot
spring-boot-starter-web
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-solr</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.hateoas</groupId>
<artifactId>spring-hateoas</artifactId>
<version>0.16.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-rest-core</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-cassandra</artifactId>
<version>1.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.ldap</groupId>
<artifactId>spring-ldap-core</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>4.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>4.1.2.RELEASE</version>
</dependency>
My root configuration file:
#Configuration
#EnableAutoConfiguration
#EnableAsync
#EnableEntityLinks
#EnableSpringDataWebSupport
#ComponentScan
#PropertySource(value = "file:../application.properties",
ignoreResourceNotFound = true)
public class ApplicationInitializer extends SpringBootServletInitializer
implements EmbeddedServletContainerCustomizer {
public static void main(String[] args) throws Exception {
SpringApplication.run(ApplicationInitializer.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application){
return application.sources(ApplicationInitializer.class);
}
#Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.setContextPath(APPLICATION_ROOT_PATH);
}
// Global beans defined here
}
Update: After trying many different things, I found out after disabling my SchedulingConfigurer my app now starts. Here is my SchedulingConfigurer
#Configuration
#EnableScheduling
#EnableConfigurationProperties(SchedulingProperties.class)
public class SchedulingConfig implements SchedulingConfigurer {
//Inject Runnables and properties
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskScheduler());
// call taskRegistrar.addFixedRateTask with runnable and property rate value
}
#Bean(destroyMethod = "shutdown")
public Executor taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(Runtime.getRuntime().availableProcessors());
return taskScheduler;
}
}

Resources