why Spring boot AspectJ missed to trigger sometimes only - spring

I have Spring boot application AspectJ is configured to work async after one service returned data but this fails to triggers sometime only there is no error logs no warning, can this happen any time, please let me know if I have missed any conf?
Application code
#SpringBootApplication
#EnableAspectJAutoProxy
#EnableAsync
public class TitlesCompareUtilityApplication {
public static void main(String[] args) {
SpringApplication.run(TitlesCompareUtilityApplication.class, args);
}
}
Aspect code
#Aspect
#Component
public class DistributedLoggingAspect {
private static Logger log = LoggerFactory.getLogger(DistributedLoggingAspect.class);
#Async
#AfterReturning("execution(* com.mycomp.repo.TyRepository.findById(..))")
public void logAfterReturn(JoinPoint joinPoint) {
int id = (int) joinPoint.getArgs()[0];
log.info("logAfterReturn() is running! id:{}", id);
}
}

For technical reasons I find it highly unlikely, even next to impossible, that advice execution would sometimes be missed because when a public Spring bean/component method is called and an AOP proxy exists, this proxy will intercept the method call, unless you perform self-invocation (class-internal method call). Whether the advice is executed in the same or an asynchronous thread (if that is even possible), should not matter.
Instead, it is much more likely that due to the asynchronous nature of your application the log entries do not appear in the order you expect or that in a high-load scenario your logger buffer overruns (depending on your configuration) and log messages get lost before they can be written.

Related

unclear circular dependency with FeignClient and Spring boot

My springboot app was working fine untill I added the following class:
#Service
#RequiredArgsConstructor
public class AutoopsClientPostBootListener implements ApplicationListener<ContextRefreshedEvent>
{
private final IAutoOpsGnsFlowInitiator gnsFlowInitator;
#Override
public void onApplicationEvent(ContextRefreshedEvent event)
{
gnsFlowInitator.startClient(event);
}
}
For some odd reason after that, I get a circular dependency error stemming from
feign client dependent on AutoopsClientPostBootListener from above.
It happens becasue IAutoOpsGnsFlowInitiator is dependent on the feign client which depend on AutoopsClientPostBootListener. But FeignClient doesn't even have any members.. (feign auto generates it) so how can it be dependent on the Listener?!!
whats the problem??
Thanks for the help
So the problem was with ApplicationListener(no idea why).
Using #EventListener solved the problem.
#EventListener
public void onApplicationEvent(ContextRefreshedEvent event)
{
gnsFlowInitator.startClient(event);
}
The issue depends on the phase of your context, once your context is initialized or changes there is a call on refresh, so you event will be fired, if you need to execute your startClient once your context is fully initialized then you #EventListener will be trigger with ContextStartedEvent which is only called once your application context was fully initialized so feign is already loaded.
Hopefully this can be helpful.

How to intercept a single method using SpringBoot AOP

I'm trying to output a log message whenever the function someFunction() gets invoked.
This is my Aspect:
#Aspect
#Component
public class MyAspect {
private static final Logger LOGGER = Logger.getLogger(MyAspect.class.getName());
#Pointcut("execution(com.practice.AOP.someFunction())")
public void outputLogMessage() {
LOGGER.info("someFunction has been invoked");
}
}
The method i'm trying to intercept, someFunction(), is in the com.practice.AOP class. When I invoke it (shown below), my Advice (the log message) doesn't output, nor do I get an error. What am I doing wrong? Is Pointcut even the way to go?
#SpringBootApplication
public class AOP {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
someFunction();
}
public static void someFunction() {
//should invoke the log message
}
}
Spring AOP only works on Spring beans, and only on public instance methods of those spring beans invoked from the outside (i.e. this.publicMethod() style invocations will not work, as they are not going through the proxies that Spring AOP creates to advise your spring beans.
If that is not enough for you, for instance if you need to advise not just spring beans but non-spring managed code as well, or static methods like in your example, you will need to switch to native AspectJ support, either by compile time weaving, or by load time weaving.

Spring Cloud Stream Dispatcher has no subscribers

Spring Cloud Stream Dispatcher has no subscribers Error.
After a successful spring boot container start up we need to put few notification messages on a Kafka topic and several of our microservices does same function and for this reason we wrote a common jar that contains out put channel definitions and dispatch utils. And the functionality works as expected as long as we invoke the util right after the SpringApplication.run call.
Following is one of our microservices Application class sample.
#SpringBootApplication
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context =SpringApplication.run(Application.class, args);
context.getBean(SchedulerConsumerUtils.class).registerOrRestartConsumerJobs();
}
}
The above set up works as expected, however this puts unnecessary burden the developer to write the boiler template code on every microservice. So to avoid this, we wrote an Aspect implementation to do the same function, however with our aspect approach we are running into the following error.
org.springframework.context.ApplicationContextException: Failed to start bean 'outputBindingLifecycle'; nested exception is org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel 'schedulertestsvcs:dev:1180.scheduledJobExecutionResponseOutput'.; nested exception is org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
We tried several approaches like Spring SmartLifeCycle to get a handle on all Kafka Output/Input channel startup completion but all of them are running into the same error.
Following is our Aspect implementation on org.springframework.boot.SpringApplication.run(..)
#Aspect
#Component
public class SchedulerConsumerAspect {
#Autowired
protected ApplicationContext applicationContext;
#AfterReturning(value = "execution(* org.springframework.boot.SpringApplication.run(..))",returning = "result")
public void afterConsumerApplicationStartup(JoinPoint pjp, Object result) throws Throwable {
if(result!=null){
ConfigurableApplicationContext context=(ConfigurableApplicationContext) result;
if(context.containsBean("schedulerConsumerUtils")){
//For what ever reason the following call resulting in Dispatcher has no subscribers for channel error.
//TODO fix the above issue and enable the following call.
context.getBean(SchedulerConsumerUtils.class).registerOrRestartConsumerJobs();
}
}
}
}
During our debug sessions, we found out org.springframework.boot.SpringApplication.run(..) Aspect was called several times during the bootstrap process. First when the aspect was called we got result value as null, after some time spring boot calls the same aspect this time result is not null. Even after getting result not null there is no grantee the component is completely initialized that's why you see a check for context.containsBean("schedulerConsumerUtils"). However after the bean initialization we are seeing output channels are not completely bound.
What is the best way to get handle on Spring Cloud Stream Kafka output/input channel binding completion ?
Why the component invocation works fine in SpringBoot Application but not through Aspect? I struggled on this few days couldn't find the right solution. Any help greatly appreciated.
I followed the suggestion from this post Spring cloud stream - send message after application initalization and used the 3rd option ApplicationRunner. The first two options didn't work for me.
#Component
public class AppStartup implements ApplicationRunner {
#Autowired
protected ApplicationContext applicationContext;
#Override
public void run(ApplicationArguments args) throws Exception {
if(applicationContext!=null){
applicationContext.getBean(SchedulerConsumerUtils.class).registerOrRestartConsumerJobs();
}
}
}

Catch application stop event for Spring-boot application

Is there a clean way to detect when a spring-boot application is stopped and perform some action before? Kind of CommandLineRunner for stopping a service
Thanks in advance
Similar to ApplicationReadyEvent you can use ContextClosedEvent:
#Component
public class ContextClosedEventListener {
#EventListener(ContextClosedEvent.class)
public void onContextClosedEvent(ContextClosedEvent contextClosedEvent) {
System.out.println("ContextClosedEvent occurred at millis: " + contextClosedEvent.getTimestamp());
}
}
I've come up with this solution. If you have better one, feel free to share
#Component
public class PortalServiceLifeCycle implements CommandLineRunner {
static final Logger LOGGER = LoggerFactory.getLogger(PortalServiceLifeCycle.class);
#Override
public void run(String... arg0) throws Exception {
LOGGER.info("###START FROM THE LIFECYCLE###");
}
#PreDestroy
public void onExit() {
LOGGER.info("###STOP FROM THE LIFECYCLE###");
}
}
Don't know if you have resolve this problem perfectly. I meet this issue recently, and have got a solution that a little different.
Firstly, my Spring boot Application is a Tomcat embedded one. (The second method of this issue doesn't depends on the web structure. don't mad, my friend.) In this case, it's naturally to get the idea of catch the stop event by register a listener. I do it like this,
#WebListener
public class HelloListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("HelloListener contextInitialized");
}
#Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("HelloListener contextDestroyed");
}
}
and, at the same time, add the annotation #ServletComponentScan on your Application class.
Surely, there are some other ways to register a ServletContextListener, and once you registered it, you can get the stop event in the contextDestroyed function.
BUT, that don't match my issue very much. I must catch the stop event BEFORE the Spring Beans being destroyed. And here comes the second solution.
modify your application main method like the follow:
SpringApplication application = new SpringApplication(DemoApplication.class);
application.addListeners(new MyListener());
application.run(args);
and provide the defination of class MyListener:
class MyListener implements ApplicationListener<ContextClosedEvent>{
#Override
public void onApplicationEvent(ContextClosedEvent contextClosedEvent) {
// your code here
}
}
NOTE: the second solution has nothing to do with Tomcat or other web container. The ContextClosedEvent isn't introduced in the Spring document, but I found it in the source, it's very useful i think.
I will be very glad if this can help some one.
It depends what you want to do but one thing you could do is have a bean that implements SmartLifecycle and implement the stop method. Whenever the context is being stopped, you'd get a callback. Note that it does not necessarily means that the process is shutting down. If you want to invoke some code when that happens, I'd register a shutdown hook as Sven wrote in a comment.

Spring boot acitvemq keep receiver running periodically

I have configured a spring boot application which when run reads messages from the queue and processes them accordingly.
I also have configured the concurrency flag to run multiple such readers.
However in an ideal world i would like the receiver to keep running like a thread and keep checking for any messages.
My question is that whether there is any way i can configure this in spring boot or i have to fallback to using threading mechanism using executor or anything else.
Thanks,
- Vaibhav
I found a nice way from Spring Boot, the concurrency was of course taken case by concurrent attribute e.g.
#JmsListener(destination = "myqueue", concurrency="2-10")
However for the Thread part below was something which is a neat way:
#SpringBootApplication
#EnableAutoConfiguration(exclude={MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
#EnableJms
public class MyApplication implements CommandLineRunner{
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
#Override
public void run(String... arg0) throws Exception {
// TODO Auto-generated method stub
System.out.println("Joining Thread ctrl+c to bring down application");
Thread.currentThread().join();
}
}

Resources