@Around @Aspect in the same package only works with @DependsOn

蓝咒 提交于 2019-12-21 20:12:04

问题


Please see the updates below.


I have a Spring Boot application where I accept TCP/IP connections:

   public MyClass implements InitializingBean {
   @Override
    public void afterPropertiesSet() throws Exception {

        try (ServerSocket serverSocket = new ServerSocket(port)) {

            while (true) {

                Socket socket = serverSocket.accept();                   
                new ServerThread(socket).start();
            } 
        }
    }

    ...

    private class ServerThread extends Thread {
            @Override
            public void run() {
                try (InputStream input = socket.getInputStream();
                     OutputStream output = socket.getOutputStream()) {

                     // Read line from input and call a method from service:
                     service.myMethod(lineConvertedToMyObject);

                } catch {
                    ...
                }
            }
    }

}

Now this works fine, as it is. But when I introduce AspectJ to myMethod:

@Aspect
@Component
public class MyServiceAspect {

    private static final Logger logger = LoggerFactory.getLogger(MyServiceAspect.class);

    @Around(value = "execution(* com.package.to.MyService.myMethod(..))")
    public MyObject rules(ProceedingJoinPoint joinPoint) throws Throwable {

        long startTime = System.currentTimeMillis();

        MyObject obj = (MyObject) joinPoint.proceed();

        logger.debug("Took {} milliseconds", System.currentTimeMillis() - startTime);

        return obj;
    }
}

service.myMethod is not called and the thread is blocked. What am I missing?

Update:

So here's the deal: MyService, MyServiceImpl and MyServiceAspect are all in the same package. Moving MyServiceAspect into another package made it work.

Does this ring a bell for anyone? Happy to award the bounty to anyone explaining this behavior. Thanks!

Update 2:

Yet another solution: Adding @DependsOn(value = {"myServiceAspect"}) on top of MyServiceImpl again resolves the issue, still wondering why though.


回答1:


Actual problem

As it was described by Alexander Paderin >> in his answer to the related question >> infinite loop in the afterPropertiesSet() was the thread blocker, since control wasn't return back to Spring in this case.

1. Working example with your samples (not actual after question edit)

Code samples you've provided do not contain issues directly, AspectJ declaration is fine.

First of all, please let me share working example: spring-aspectj-sockets. It is based on Spring 5.1.0 and AspectJ 1.9.1 (currently latest versions) and uses your samples, works independent of the location/package of MyServiceAspect.


2. Issue explanation

2.1. Intro

The most possible thread blocker in your samples is a call to ServerSocket.accept(), javadocs for this method says:

Listens for a connection to be made to this socket and accepts it. The method blocks until a connection is made.

There are 2 correct ways of handling accept():

  1. To initialize connection first, e.g.:

    serverSocket = new ServerSocket(18080);
    clientSocket = new Socket("127.0.0.1", 18080); // initializing connection
    Socket socket = serverSocket.accept(); // then calling accept()
    
  2. Set up timeout to wait for acceptance:

    serverSocket = new ServerSocket(18080);
    serverSocket.setSoTimeout(5000); // 5 seconds timeout
    Socket socket = serverSocket.accept(); // then calling accept()
    

    NOTE: If within 5 seconds there will be no connections, accept() will throw exception, but will not block the thread

2.2. Assumption

I assume that you are using 1-st approach and somewhere you have a line which initializes the connection, i.e. clientSocket = new Socket("127.0.0.1", 18080);.

But it is called (e.g. if static declarations are used):

  • After serverSocket.accept() in case MyServiceAspect is located in the same package and
  • Before - in case MyServiceAspect is located in some other place

3. Debugging

I'm not sure if this is needed, have doubts because of bounty's description, let me cover this quickly just in case.

You can debug your application using Remote Debugging - it will cover aspects, child threads, services, etc. - you will only need to:

  1. Run Java with specific arguments like it is described in this question >>
  2. And connect to the specified debug port using IDE (steps for Eclipse are described in the same question)


来源:https://stackoverflow.com/questions/52517497/around-aspect-in-the-same-package-only-works-with-dependson

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!