0

Here is my problem.

I have a class implements Runnable, and it is a daemon thread, which will be permanently alive during the application lifecycle.

Now I want to perform a function just like AOP enhancement to enhance this Runnable class.

It was quite easy to have that pointcut if the class is annotated with @Service or @Component. But now it is a class implememts the Runnable interface so I have not yet find any possible ways to do so without any intrusion to the original code.

Here below is my testing code:

this is the parent interface of my daemon thread

public interface MessageRunnable extends Runnable {
    void doConsume();
}



one of the working thread:

@Slf4j
public class MyDaemonThread implements MessageRunnable{
    @Override
    public void run() {
        log.info("now in run function,ready to call doConsume...");
        while(true){
            log.info("I m still alive...");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            doConsume();
        }
    }

    @Override
    public void doConsume() {
        log.info("doConsume was called...");
    }
}



And here is the simple test:

@Component
public class TestComponent {
    private MyDaemonThread testThread;
    @PostConstruct
    public void init(){
        if(testThread==null){
            testThread=new MyDaemonThread();
            new Thread(testThread).start();
        }
    }
}



After running the application.

I can see the log is printing well, but now if I want to add a function to print now I'm in the aspect method before the doConsume function was invoked, I don't have any idea to do so without any intrude to my source code, it is acceptable to add codes ,but no modifications were allowed at all.

I wonder if there is any possible ways to let spring handle this daemon thread, then it is easy to do an aspect point cut. Otherwise, I have to change the code to add a proxy method and an interceptor do achieve the goal....

william
  • 265
  • 4
  • 17
  • Are you willing to switch to native AspectJ in order to achieve your goal? Then you could do it with an aspect. – kriegaex Oct 11 '21 at 15:41
  • @kriegaex Thanks a lot. Yes, if there is no way to achieve my goal using AOP, it is acceptable to use any other ways instead of AOP. In this question, I just wonder if there is a way to my goal which will not lead to any code intrution to my original code. – william Oct 12 '21 at 01:13
  • AspectJ **is** an AOP framework, as the name implies. This is also why I said: _"Then you could do it with an aspect._" It is just much more powerful than the simple "AOP lite" solution Spring AOP, which is why the Spring manual itself recommends it for advanced use cases. Maybe you could do some basic reading there and then provide more feedback if you understand more, but are still having problems. – kriegaex Oct 12 '21 at 05:24
  • @kriegaex Thank you very much for your advise. I have my problem solved. By refactoring I have extract the public method into a component which is managed by spring, and then let the daemon threads to call the method from ```ApplicationContext``` by passing ```ApplicationContext``` into daemon threads when they were started. Then simple AOP will work. Though it took a lot of time to test my code, it was finnaly solved. – william Oct 15 '21 at 01:31
  • It is in a hurry job that day.... I will learn how to use AspectJ at the weekend and try to solve this problem again. – william Oct 15 '21 at 01:39

1 Answers1

0

First of all , MyDaemonThread instance is not a spring container managed bean. The code uses new keyword to create the instance. Spring AOP can only advise a spring bean.

Even if the MyDaemonThread is made a spring bean , it is not possible to advise doConsume() using Spring AOP with the current code ( OP mentions no modifications are allowed ).

From the reference documentation

Due to the proxy-based nature of Spring’s AOP framework, calls within the target object are, by definition, not intercepted.

R.G
  • 6,436
  • 3
  • 19
  • 28
  • Thank you very much for your answer. I know it is impossible to use AOP to achieve my goal. But do you have any idea if there is any way which will not lead to that much code intrution to achieve my goal? – william Oct 12 '21 at 01:18
  • @william the question was tagged with Spring AOP ( Spring framework's Aspect Oriented Programming) and I explained the Spring AOP limitation . You are sure to get an answer from kriegaex as he has offered a solution with AspectJ ( A more powerful AOP framework ) – R.G Oct 12 '21 at 03:01
  • Thank you very much for your advice! I have my problem solved in another way by passing ```ApplicationContext``` into daemon threads when they were started. After that the AOP can intercept the method. I will find out how to do with AspectJ later. – william Oct 15 '21 at 01:35
  • Good to know you resolved your issue. Do read through [this answer](https://stackoverflow.com/a/812540/4214241) to understand why having a dependency on Application Context is not a good practice. – R.G Oct 15 '21 at 03:25
  • I see... But how about extracting the ```doConsume``` method into a component, and then pass it into the daemon thread when the thread was started? ```ApplicationContext``` will then unused, but I think it is quite the same as passing ```ApplicationContext``` into the thread..... – william Oct 15 '21 at 09:05
  • Maybe I just don't know how to create a daemon thread and let spring manage it... I also read [how to inject a bean into thread](https://stackoverflow.com/questions/45297652/spring-not-injecting-a-bean-into-thread) but came with no idea. At the same time, I have found another way to achieve this goal just more properly. To use @Schedule to replace the ```while (true)``` block in ```MyDaemonThread```,the AOP works too. But still, I need to figure out how to use threads properly..... – william Oct 15 '21 at 09:12
  • Is it correct that only the spring managed classes' method can be advised by AOP? Which means only if I registered the class with @bean,@Component,@Service or else, then AOP will then be able to advise my expected methods? – william Oct 15 '21 at 09:26
  • To inject a component into the thread, is it correct to create an util class by implement ```ApplicationContextAware``` like this [solution](https://stackoverflow.com/questions/45297652/spring-not-injecting-a-bean-into-thread)? – william Oct 15 '21 at 09:43
  • 1. Spring AOP can only advise Spring cotainer managed bean. 2. AspectJ does not have this limitation 3. I am not completely sure about your requirement to comment on a solution. The best suggestion I can give will be to read through Spring documentation on threads , come up with a solution and share your code if you get stuck. – R.G Oct 15 '21 at 09:56