@Around @Aspect在同一个包中仅适用于@DependsOn
请参阅以下更新。
我有一个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 { ... } } } }
现在这样可以正常工作。 但是当我将AspectJ引入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
并阻止该线程。 我错过了什么?
更新:
所以这是交易: MyService
, MyServiceImpl
和MyServiceAspect
都在同一个包中。 将MyServiceAspect
移动到另一个包中使其工作。
这对任何人来说都响了吗? 很高兴将赏金奖励给任何解释此行为的人。 谢谢!
更新2:
另一个解决方案:在@DependsOn(value = {"myServiceAspect"})
添加@DependsOn(value = {"myServiceAspect"})
再次解决了这个问题,但仍然想知道为什么。
实际问题
正如Alexander Paderin >>在回答相关问题时所描述的那样>> afterPropertiesSet()
中的无限循环是线程阻塞,因为在这种情况下控制不会返回到Spring 。
1.样本的工作示例(问题编辑后不是实际的)
您提供的代码示例不直接包含问题, AspectJ声明也没问题。
首先,请让我分享工作示例: spring-aspectj-socket 。 它基于Spring 5.1.0和AspectJ 1.9.1 (目前是最新版本)并使用您的样本,独立于MyServiceAspect
的位置/包工作。
2.问题解释
2.1。 介绍
样本中最可能的线程阻止程序是对ServerSocket.accept()
的调用,此方法的javadocs说:
侦听对此套接字的连接并接受它。 该方法将阻塞,直到建立连接。
处理accept()
有两种正确的方法:
-
首先初始化连接,例如:
serverSocket = new ServerSocket(18080); clientSocket = new Socket("127.0.0.1", 18080); // initializing connection Socket socket = serverSocket.accept(); // then calling accept()
-
设置超时等待接受:
serverSocket = new ServerSocket(18080); serverSocket.setSoTimeout(5000); // 5 seconds timeout Socket socket = serverSocket.accept(); // then calling accept()
注意 :如果在5秒内没有连接,则
accept()
将抛出exception,但不会阻塞该线程
2.2。 假设
我假设您正在使用1-st方法,并且某处有一行初始化连接,即clientSocket = new Socket("127.0.0.1", 18080);
。
但它被调用(例如,如果使用静态声明):
- 在
serverSocket.accept()
,以防MyServiceAspect
位于同一个包中 - 之前 – 以防
MyServiceAspect
位于其他地方
3.调试
我不确定这是否需要,因为赏金的描述而有疑问,让我快速介绍一下以防万一。
您可以使用远程调试来调试应用程序 – 它将涵盖方面,子线程,服务等 – 您只需要:
- 使用特定参数运行Java ,如本问题中所述>>
- 并使用IDE连接到指定的调试端口( Eclipse的步骤在同一个问题中描述)