I am having a bit of trouble integrating spring-kafka with spring-boot. I am using spring boot v2.1 with spring-kafka v2.2 (which should be compatible according to the matrix).
I have seen multiple similar questions but none of them fixes my problem.
The error from the logs:
***************************
APPLICATION FAILED TO START
***************************
Description:
An attempt was made to call the method org.springframework.kafka.listener.AbstractMessageListenerContainer.getContainerProperties()Lorg/springframework/kafka/listener/config/ContainerProperties; but it does not exist. Its class, org.springframework.kafka.listener.AbstractMessageListenerContainer, is available from the following locations:
jar:file:/C:/Users/Ali/.m2/repository/org/springframework/kafka/spring-kafka/2.2.0.RELEASE/spring-kafka-2.2.0.RELEASE.jar!/org/springframework/kafka/listener/AbstractMessageListenerContainer.class
It was loaded from the following location:
file:/C:/Users/Ali/.m2/repository/org/springframework/kafka/spring-kafka/2.2.0.RELEASE/spring-kafka-2.2.0.RELEASE.jar
Action:
Correct the classpath of your application so that it contains a single, compatible version of org.springframework.kafka.listener.AbstractMessageListenerContainer
2022-06-28 13:21:16,716 INFO [,,,] [main] ThreadPoolTaskExecutor[shutdown]: Shutting down ExecutorService 'applicationTaskExecutor'
My dependency in the pom:
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
My code:
#Component
public class MyListenerComponent {
#KafkaListener(topics="myTopic")
public void Listen(MyModelClass obj) {
//do stuff (nothing complicated, basic java stuff)
}
}
My Application:
#Configuration
#SpringBootApplication
#EnableKafka
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
I can't seem to find examples/samples dating back to v2.2.
I am not using any other listeners or containers like JMS or MQ, so there should be no conflicts (seen a similar question where RabbitMQ was causing conflicts).
The error only seems to happen when I use the KafkaListener annotation, Is there a fix or alternative way to deal with listeners?
In any case; those versions are no longer supported; even commercially https://spring.io/projects/spring-boot#support and https://spring.io/projects/spring-kafka#support let alone OSS.
The root cause is definitely a mis-matched version because that class (ContainerProperties) was moved from config to listener in 2.2.
An attempt was made to call the method org.springframework.kafka.listener.AbstractMessageListenerContainer.getContainerProperties()Lorg/springframework/kafka/listener/config/ContainerProperties; but it does not exist. Its class, org.springframework.kafka.listener.AbstractMessageListenerContainer, is available from the following locations:
Whatever is calling getContainerProperties() was compiled against an earlier version.
Related
I am developing a module with spring boot in my backend where i need to use Redis through GCP Memory Store. I have been searching in forum and even the "oficial documentation" about memory store but i cannot understand how to connect to memory store with my spring boot app.
I found a google code lab but they use a Compute Engine VM to install spring boot and then save and retrieve information from memory store. So i tried to do it like that in my local spring boot but it didnt work because throws an error saying:
Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 10.1.3.4
the codelab i mentioned earlier says that you only have to add this line to your application.properties:
spring.redis.host=10.1.3.4
as well as the annotation #EnableCaching in the main class and #Cachable annotation in the controller method where you try to do something with redis.
the method looks like this:
#RequestMapping("/hello/{name}")
#Cacheable("hello")
public String hello(#PathVariable String name) throws InterruptedException {
Thread.sleep(5000);
return "Hello " + name;
}
i dont know what else to do. Notice that i am new on this topic of redis and memory store.
Anyone can give me some guidance on this please?
thanks in advance
codelab url: https://codelabs.developers.google.com/codelabs/cloud-spring-cache-memorystore#0
See this documentation on how to setup Memorystore Redis instance.
Included in the documentation is how you can connect and test your Memorystore instance from different computing environments.
There's also a step by step guide on how SpringBoot can use Redis to cache with annonations.
Add the Spring Data Redis starter in your pom.xml if you're using Maven for your project setup.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Add this configuration in your application.properties file:
spring.redis.host=<MEMORYSTORE_REDIS_IP>
# Configure default TTL, e.g., 10 minutes
spring.cache.redis.time-to-live=600000
Turn on caching capability explicitly with the #EnableCaching annotation:
#SpringBootApplication
#EnableCaching
class DemoApplication {
...
}
Once you configured the Spring Boot with Redis and enabled caching, you can use the #Cacheable annotation to cache return values.
#Service
class OrderService {
private final OrderRepository orderRepository;
public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
#Cacheable("order")
public Order getOrder(Long id) {
orderRepository.findById(id);
}
}
I have a spring boot app that I upgraded from v2.2.x to now be v2.4.3.
I saw in their documentation that there is a new actuator endpoint of /startup, however it does not exist when I start my app.
There is no special requirement according to their documentation here
I am using spring-boot-admin-starter-client v2.4.3 which provides spring-boot-actuator v2.4.3, and i even have management.endpoint.startup.enabled=true in my application.properties file.
Has anyone else used this version of spring boot and gotten this actuator enpoint to work?
You need to tweak startup configuration:
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(DemoApplication.class);
app.setApplicationStartup(new BufferingApplicationStartup(1000));
app.run(args);
}
}
In application.properties:
management.endpoints.web.exposure.include=startup
If you want to visualize startup events check out this tool I made some months ago https://spring-boot-startup-analyzer.netlify.app/ (look at the configuration instructions as you need to enable CORS on this endpoint)
May be you are using BootstrapApplicationListener which build the application context again but ignores the previous applicationStartup, so it sets the default, this is a bug in spring-cloud-context:3.0.0
I'm trying to add Spring security to an existing Spring MVC project. I'm using this as a guide:
http://docs.spring.io/spring-security/site/docs/current/guides/html5//hellomvc.html
However, I can't get the project to display the login screen. I copied SecurityConfig.java and MessageSecurityWebApplicationInitializer.java verbatim, when I turn boot logging to DEBUG, I see this:
o.s.b.c.e.ServletContextInitializerBeans : Created Filter initializer for bean 'springSecurityFilterChain'; order=2147483647, resource=class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]
Which suggests that MessageSecurityWebApplicationInitializer is never being looked at. Sure enough, if I create a default constructor and set a breakpoint, it's never getting hit.
Interestingly, SecurityConfig.configureGlobal is called, which seems like the call that should be setting up the login screen.
So what steps need to happen to make MessageSecurityWebApplicationInitializer do its thing? I'm still trying to understand how Spring handles dependency injection, etc.--what about this class declaration should cause this to get picked up during boot (I would have expected some sort of annotation):
public class MessageSecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
}
I can't share much other code unfortunately, but this is the Application file:
#ComponentScan(basePackages={"..."})
#EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class, SpringBootWebSecurityConfiguration.class})
#Configuration
public class Application extends SpringBootServletInitializer {
/**
* The main() method is required by the framework.
*
* #param args
* #throws IOException
*/
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
The one thing that the sample has that this project doesn't is the MessageWebApplicationInitializer class, but to me it looks like that functionality should be picked up by my Application class.
Thanks!
You must add annotations #Configuration and #EnableWebSecurity to your MessageSecurityWebApplicationInitializer and take care that its picked up by spring. Than it should work.
So it turns out the problem was these lines in my gradle build:
compile(group: "org.springframework.boot", name: "spring-boot-starter-actuator", version: "1.2.3.RELEASE")
compile(group: "org.springframework.boot", name: "spring-boot-starter-web", version: "1.2.3.RELEASE")
compile(group: "org.springframework.boot", name: "spring-boot-starter-test", version: "1.2.3.RELEASE")
compile(group: "org.springframework.boot", name: "spring-boot-starter-jdbc", version: "1.2.3.RELEASE")
It would be great if anyone could shed some insight into why these lines would break the security setup.
I have two small apps, one uses spring-boot-starter-amqp, other uses spring-data-hadoop-boot. I can run them separately without any problems.
When I join them together, app start fails with exception: org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
My main class is pretty much generic and it works fine for both of them separately:
#PropertySource("file:conf/app.properties")
#SpringBootApplication
public class Job {
public static void main(String[] args) throws Exception {
SpringApplication.run(Job.class, args);
}
}
I am at lost here. AFAIK #SpringBootApplication contains all annotations needed, including auto configuration and components scanning. I've had no need to configure web environment as I am not using it. Why do I need to do it when both dependencies are in class path, and how do I fix it?
UPDATE
I dug a little bit in the Spring Boot code. Main problem is that SpringApplication.deduceWebEnvironment() automatically detects what kind of environment should be configured based on existence of certain classes in class path.
For web environment two classes are being checked. When both of them are in class path, web environment is detected which requires proper configuration, obviously.
javax.servlet.Servlet
org.springframework.web.context.ConfigurableWebApplicationContext
spring-boot-starter-amqp:1.3.1.RELEASE contains ConfigurableWebApplicationContext, and spring-data-hadoop-boot:2.3.0.RELEASE-cdh5 contains Servlet (in native Hadoop libs).
Now, when run alone, one of above classes is missing in both cases, which results in web environment not being set.
But when I use both of them - both classes can be found. Web environment is detected, false positive, and it requires configuration, which I am not able (and don't want) to provide.
So question now is - can I force non web environment, even when I have those classes in class path? Or is there any other way to solve the issue? (other than excluding them from Gradle dependencies)
Solved.
Following this question: How to prevent spring-boot autoconfiguration for spring-web?
I run application as follows.
#PropertySource("file:conf/app.properties")
#SpringBootApplication
public class Job {
public static void main(String[] args) throws Exception {
new SpringApplicationBuilder(Job.class).web(false).run(args);
}
}
Answers to above question also suggested to use property spring.main.web_environment=false or annotation #EnableAutoConfiguration(exclude = WebMvcAutoConfiguration.class). Both solutions haven't worked for me. Only programmatic solution works in my case.
We're using Spring Boot with its Jersey Starter and deploy it as a WAR, programmatically deployed into another application's embedded Tomcat.
After our application startup, in some environments, a mapping conflict occurs and is logged as follows:
o.g.j.s.i.JerseyServletContainerInitializer : Mapping conflict. A Servlet registration exists with same mapping as the Jersey servlet application, named com.vidal.pmsi.config.PmsiResourceConfiguration, at the servlet mapping, /*.
The resource configuration is as follows:
#ApplicationPath("/")
#ExposedApplication
#Component
public class PmsiResourceConfiguration extends ResourceConfig {
public PmsiResourceConfiguration() {
packages("com.vidal.pmsi.api");
packages("com.vidal.pmsi.config");
property(ServerProperties.BV_DISABLE_VALIDATE_ON_EXECUTABLE_OVERRIDE_CHECK, true);
property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
}
}
As far as I understand, Spring Boot Jersey Starter will register a 'jerseyServlet'-named servlet mapping to '/*'.
In some environments, Jersey's own JerseyServletContainerInitializer will trigger after SpringApplication startup, failing to register PmsiResourceConfiguration because of the existing jerseyServlet mapping.
This is a problem because of our own open-source library that tries (and crashes at) getting the context path at startup:
// compile-time generated Linkers.java
#WebListener
#Generated("fr.vidal.oss.jax_rs_linker.LinkerAnnotationProcessor")
public final class Linkers implements ServletContextListener {
private static String contextPath = "";
private static String applicationName = ApplicationName.get();
#Override
public void contextInitialized(ServletContextEvent sce) {
//applicationName = FQCN of PmsiResourceConfiguration
contextPath = ContextPaths.contextPath(sce.getServletContext(), applicationName);
}
// [...]
}
// ContextPaths.java
public static String contextPath(ServletContext servletContext, String registeredKey) {
// registeredKey is therefore the FQCN of PmsiResourceConfiguration
String mappedPath = stripWildcard(servletContext.getServletRegistration(registeredKey).getMappings().iterator().next());
return servletContext.getContextPath() + mappedPath;
}
The last snippet of code will fail as there is no mapping for the registered resource configuration class (there is only one for 'jerseyServlet' key).
This does not fail when there isn't any mapping conflict reported.
Why?
I was running my head against a similar problem where I have a Spring Boot Application with a Jersey JAX-RS Webservice. Everything worked fine when using the embeddedTomcat but it went to hell when I tried deploying the war on a regular Tomcat of the same version (Tomcat8).
The problem is that by default the embeddedTomcat does not scan for ServletContainerInitializer in jar files, yet the regular one does and that conflicted with the ServletContainer/Config that Spring sets up.
Apart from excluding the jar containing the JerseyServletContainerInitializer I found an option to tell tomcat to filter out this particular ServletContainerInitializer (SCI). Setting the containerSciFilter attribute on the context helped:
<Context containerSciFilter="JerseyServletContainerInitializer">
...
</Context>
I did not define any SCI in my META-INF/services but the jar that contains the JerseySCI has defined it and it was on the right path to be found by Tomcat.
Considering that this was the closest matchinb question and without an answer I don't repost my question and try to answer this one as I believe that the cause is the same.