@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"}) поверх MyServiceImpl снова решает проблему, хотя все еще интересно, почему.


person Hasan Can Saral    schedule 26.09.2018    source источник
comment
Возможно, я смогу объяснить это, если увижу полную картину: сборка Maven, конфигурация Sporing, аспект и код приложения. Мне нужно увидеть настоящие имена пакетов и полный код, а не поддельные пакеты и неполные методы с большим количеством .... Не могли бы вы опубликовать MCVE воспроизводите свою проблему на GitHub?   -  person kriegaex    schedule 29.09.2018


Ответы (1)


Актуальная проблема

Как это было описано Александром Падериным >> в его ответе на соответствующий вопрос >> бесконечный цикл в afterPropertiesSet() блокировал поток, поскольку управление не было возвращено обратно в Spring в этом случае.

1. Рабочий пример с вашими образцами (не актуален после редактирования вопроса)

Образцы кода, которые вы предоставили, не содержат ошибок напрямую, объявление AspectJ в порядке.

Прежде всего, позвольте мне поделиться рабочим примером: spring-aspectj-sockets. Он основан на Spring 5.1.0 и AspectJ 1.9.1 (последние на данный момент версии) и использует ваши образцы, работает независимо от расположения/пакета MyServiceAspect.


2. Объяснение проблемы

2.1. вступление

Наиболее возможный блокировщик потока в ваших примерах - это вызов ServerSocket.accept(), в javadocs для этого метода говорится:

Ожидает подключения к этому сокету и принимает его. Метод блокируется, пока не будет установлено соединение.

Есть 2 правильных способа обработки 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-й подход и где-то у вас есть строка, которая инициализирует соединение, то есть clientSocket = new Socket("127.0.0.1", 18080);.

Но он вызывается (например, если используются статические объявления):

  • После serverSocket.accept() в случае, если MyServiceAspect находится в том же пакете и
  • Раньше - на случай, если MyServiceAspect находится в другом месте

3. Отладка

Я не уверен, нужно ли это, есть сомнения из-за описания щедрости, позвольте мне быстро рассказать об этом на всякий случай.

Вы можете отлаживать свое приложение с помощью Удаленная отладка — она будет охватывать аспекты, дочерние потоки, службы и т. д. — вам нужно будет только:

  1. Запустите Java с определенными аргументами, как это описано в этом вопросе >>< /а>
  2. И подключитесь к указанному порту отладки с помощью IDE (шаги для Eclipse описаны в том же вопросе)
person marme1ad    schedule 30.09.2018
comment
P.S.: @hasan-can-saral, если это не поможет, не могли бы вы предоставить дополнительную информацию/примеры кода. - person marme1ad; 30.09.2018
comment
Спасибо за ответ, но я ищу решение своей конкретной проблемы, тогда как ваш ответ в основном ServerThread? Так что это крайне неактуально. Я пытаюсь воспроизвести проблему и опубликовать ее на GitHub. Вы видели обновление? Кроме того, нет никаких проблем с моей реализацией сокета. - person Hasan Can Saral; 01.10.2018
comment
@HasanCanSaral, спасибо за обновление, но информации по-прежнему недостаточно, неясно, как вы создаете экземпляр serverSocket на своей стороне из строки Socket socket = serverSocket.accept(); Позвольте мне тогда дождаться MCVE. - person marme1ad; 01.10.2018
comment
Пока я использовал все ваши образцы кода в своем примере, который работает независимо от пакета MyServiceAspect. - person marme1ad; 01.10.2018
comment
Обновил вопрос еще раз. Я инициализирую ServerSocket в методе afterPropertiesSet InitializingBean. - person Hasan Can Saral; 01.10.2018
comment
@HasanCanSaral, так что у вас может быть / будет здесь состояние гонки из-за serverSocket.accept() - он заблокирует поток до тех пор, пока не будет создан прослушиватель сокета. Как я писал ранее, добавьте serverSocket.setSoTimeout(1000); // 1 seconds timeout - он будет ждать секунду, чтобы установить соединение с прослушивателем сокета, затем перейдет к логике ServerThread, где создан экземпляр прослушивателя, а затем попытается принять еще раз. - person marme1ad; 01.10.2018
comment
Также вы можете просто проверить, является ли serverSocket.accept() причиной блокировки без отладки, просто добавив два вывода вокруг этой строки: System.out.println(1); Socket socket = serverSocket.accept(); System.out.println(2); - person marme1ad; 01.10.2018
comment
Я проверил, это не так. Я думаю, что это больше связано с черной магией Весны, чем с ServerSocket. Перемещение класса в другой пакет заставляет его работать. Если бы это было из-за состояния гонки или тайм-аута (чего я не могу, кстати, поскольку это сервер, и он выйдет, если не будет соединений в течение 1 с), перемещение пакетов не поможет. - person Hasan Can Saral; 01.10.2018
comment
Извините, поэтому показаны оба выхода (1 и 2), верно? - person marme1ad; 01.10.2018
comment
Правильно, независимо от того, работает аспект или нет. Я искренне думаю, что это не имеет никакого отношения к ServerSocket. - person Hasan Can Saral; 01.10.2018