同一包中的@Around @Aspect仅适用于@DependsOn

时间:2018-09-26 12:12:00

标签: java spring spring-boot aspectj aspect

请参阅下面的更新。


我有一个Spring Boot应用程序,可以接受TCP / IP连接:

   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 {
                    ...
                }
            }
    }

}

现在,它可以正常工作。但是,当我向myMethod介绍AspectJ时:

@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没有被调用,线程被阻塞。我想念什么?

更新

因此,要达成协议:MyServiceMyServiceImplMyServiceAspect都在同一个程序包中。将MyServiceAspect移到另一个软件包中即可。

这会给任何人敲钟吗?很高兴将赏金奖励给任何解释此行为的人。谢谢!

更新2:

另一种解决方案:在@DependsOn(value = {"myServiceAspect"})之上再添加MyServiceImpl可以解决此问题,但仍然想知道为什么。

1 个答案:

答案 0 :(得分:2)

实际问题

Alexander Paderin >>在对afterPropertiesSet()中相关question >>无限循环的回答中描述的是线程阻塞器,因为控制权没有返回到 Spring

1。您的样本的工作示例(问题编辑后不实际)

您提供的代码示例不直接包含问题, AspectJ 声明很好。

首先,请允许我分享工作示例:spring-aspectj-sockets。它基于 Spring 5.1.0 AspectJ 1.9.1 (当前最新版本),并且使用您的示例,可独立于MyServiceAspect的位置/程序包运行


2。问题说明

2.1。简介

示例中最可能的线程阻止程序是对ServerSocket.accept()的调用,该方法的javadocs说:

  

监听与此套接字建立的连接并接受它。 该方法将一直阻塞,直到建立连接为止。

有两种处理accept()的正确方法:

  1. 要首先初始化连接,例如:

    serverSocket = new ServerSocket(18080);
    clientSocket = new Socket("127.0.0.1", 18080); // initializing connection
    Socket socket = serverSocket.accept(); // then calling accept()
    
  2. 设置超时以等待接受:

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

    注意:如果在5秒钟内没有连接,accept()将引发异常,但不会阻塞线程

2.2。假设

我假设您使用的是1-st方法,并且在某处有一行用于初始化连接的行,即clientSocket = new Socket("127.0.0.1", 18080);

但是它被调用(例如,如果使用静态声明):

  • serverSocket.accept()位于同一包中的情况下,在MyServiceAspect之后,
  • 之前-如果MyServiceAspect位于其他地方

3。调试

我不确定是否需要这样做,由于悬赏的描述有疑问,让我快速介绍一下,以防万一。

您可以使用远程调试调试应用程序-它涵盖了方面,子线程,服务等。-您只需要:

  1. 使用特定参数运行 Java ,如本question >>
  2. 中所述
  3. 并使用IDE连接到指定的调试端口( Eclipse 的步骤在同一问题中进行了描述)