Spring AOP, аспект пользовательской аннотации, импортированной из внешнего jar, поскольку зависимость не выполняется

Я работаю над проектом A, где добавляю аспекты вокруг AdminController для проверки этих URL-адресов при вызове, но у меня есть все пользовательские аннотации в отдельном репозитории B, который я добавил в качестве внешнего jar в A в качестве формы зависимости.

Ниже приведены файлы проекта B, в которых я определил собственные аннотации.

Проект Б

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CustomAuth {

}
@Component
@Aspect
public class AuthAspect {

    @Before(value = "@annotation(com.company.services.annotations.CustomAuth)")
    public void doBefore(final JoinPoint joinPoint) {
          System.out.println("Validating the admin url");
    }

    @Around(value = "@annotation(com.company.services.annotations.CustomAuth)")
    public Object doAuthorize(final ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("During this");
        long start = System.currentTimeMillis();
        Object proceed = proceedingJoinPoint.proceed(); // Continue with the method execution
        long executionTime = System.currentTimeMillis() - start;
        System.out.println(proceedingJoinPoint.getSignature() + " executed in " + executionTime + "ms");
        return proceed;
    }
}

pom.xml из B

  <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>${aspectj.version}</version>
        </dependency>
  </dependencies>
  <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

Ниже приведен набор файлов, которые у меня есть в проекте A, где находится AdminController.

Админконтроллер.java

@RestController
@RequestMapping("/{version}/admin")
public interface AdminController {

    @CustomAuth
    @GetMapping(value = "/node/status",
            produces = {MediaType.APPLICATION_JSON})
    void getStatus();

  }

pom.xml от A (наследовать зависимость от B)

   <dependencies> 
     <dependency>
            <groupId>com.company.service</groupId>
            <artifactId>filter</artifactId>
            <version>0.0.18</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-context</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-aop</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.aspectj</groupId>
                    <artifactId>aspectjweaver</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.2.12.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.7</version>
        </dependency>
    </dependencies>
    <plugins>
      <plugin>
          <groupId>org.codehaus.mojo</groupId>
          <artifactId>aspectj-maven-plugin</artifactId>
          <configuration>
                <aspectLibraries>
                    <aspectLibrary>
                       <groupId>com.company.service</groupId>
                       <artifactId>filter</artifactId>
                    </aspectLibrary>
                </aspectLibraries>
             </configuration>
         </plugin>
     <plugins>

Основной файл SpringBoot

@Configuration
@SpringBootApplication
@EnableAspectJAutoProxy
@ComponentScan(value = {"com.company"})
@EntityScan({"com.company"})
public class SpringBootApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootApplication.class, args);
    }
}

В этой конфигурации я не могу выполнять переплетение времени загрузки для аспекта пользовательской аннотации. Есть идеи, почему это не работает или чего мне здесь не хватает?

Вы ничего не добавили для переплетения во время загрузки, так почему это должно работать? Вы не добавили @EnableLoadTimeWeaving, чтобы включить его, и не добавили специализированный Java-агент. ВЫ включили прокси, которые не будут работать, поскольку метод не является общедоступным. Кроме того, ваш SpringBootApplication должен иметь только аннотацию @SpringBootApplication (при условии, что она находится в пакете com.company), все остальное не требуется.

M. Deinum 14.08.2024 08:52

@M.Deinum Я не могу аспектировать свою пользовательскую аннотацию на контроллере. Это основная проблема. Это из-за переплетения времени загрузки, как я видел во многих других местах, где его использование не является стандартной практикой.

user2594 14.08.2024 09:05

Вы не используете плетение во время загрузки, так почему вы так думаете? Проблема здесь в том, что ваш метод не является общедоступным.

M. Deinum 14.08.2024 09:06

@M.Deinum Для интерфейса все методы по умолчанию являются общедоступными. Я тоже пытался сделать то же самое, но безуспешно. Это похоже на то, что динамический прокси-сервер JDK не может вызвать этот аспект.

user2594 14.08.2024 09:34

Аннотации не наследуются, они должны быть в фактической реализации.

M. Deinum 14.08.2024 09:36

@M.Deinum Я считаю, что это все еще возможно, поскольку АОП ставит условие для этой аннотации. Если это какой-либо метод, абстрактный или неабстрактный, мы можем придать ему аспект. Но спасибо за ваши комментарии. Все еще похоже на то, что мне не хватает зависимости или ее отладки.

user2594 14.08.2024 09:57

@M.Deinum Spring AOP использует либо динамические прокси JDK, либо CGLIB для создания прокси для ваших целевых объектов. Согласно документации Spring, если ваша цель реализует хотя бы один интерфейс, будет использоваться динамический прокси-сервер JDK. Однако, если ваш целевой объект не реализует никаких интерфейсов, будет создан прокси-сервер CGLIB. Здесь он создаст прокси-сервер JDK, который реализует AdminController, а затем проксирует все вызовы к вашему bean-компоненту AdminServiceImpl, добавляя функциональные возможности аспекта, где это необходимо.

user2594 14.08.2024 10:01

Это не имеет ничего общего с интерфейсами, а связано с видимостью аннотаций. Пожалуйста, не пытайтесь объяснить, как работает Spring AOP (я знаю). Проблема всё равно в том, что дело не в классе, но удачи в начинаниях, если не верите на слово специалистам...

M. Deinum 14.08.2024 10:47

@M.Deinum Извиняюсь, если это звучит так. Кстати, это работает. Спасибо за ваш совет. Интерфейс - это проблема, с которой я столкнулся. И только сейчас понял, что смешивал две вещи. Изначально и в первую очередь я хотел использовать АОП, а не аспектJ. Если мы хотим применить его к интерфейсам, я думаю, нам нужно использовать его через интерфейс маркера.

user2594 14.08.2024 11:16

Если не использовать прокси, это может работать с переплетением времени компиляции (и/или времени загрузки, но в моем опыте это неприятно). AspectJ для АОП — это просто язык, поэтому у вас все еще есть AspectJ, но только в виде определений. Необходимость размещения аннотаций к реализации является ограничением АОП на основе прокси. Сам Spring работает с этим для своих собственных аннотаций, таких как @Transactional и т. д., но это встроено в перехватчики.

M. Deinum 14.08.2024 11:52

В поддержку того, что уже сказал @M.Deinum, я хочу упомянуть, что ваш подход «много (медицина) очень помогает» сочетает в себе не только 2, но и 3 типа АОП: Spring AOP, собственное плетение во время компиляции AspectJ (через AspectJ Maven) и встроенное переплетение времени загрузки AspectJ (которое, как вы сказали, вы хотите использовать). В каждом из них есть способы заставить это работать. Просто примите решение, каким оно должно быть, и тогда, возможно, кто-нибудь поможет вам решить вашу проблему.

kriegaex 14.08.2024 13:59

@M.Deinum Пожалуйста, проверьте эту ссылку, чтобы увидеть пользовательские аннотации, примененные к интерфейсу.

user2594 15.08.2024 08:53

Что явно устанавливает inherited в true, что означает, что он будет сканировать иерархию. Что невозможно при использовании простых @Aspect и @POintcut. Добиться этого можно только без использования аннотаций. Теряется преимущество обычного способа предоставления аспектов. Spring внутри использует тот же обходной путь.

M. Deinum 15.08.2024 09:29

@M.Deinum Спасибо за ваши идеи. Без использования унаследованной аннотации. Есть ли способ применить пользовательскую аннотацию ко всем методам класса? Я хотел добавить рекомендации по аспектам ко всем методам класса обслуживания администратора. Если я добавляю пользовательскую аннотацию на уровне класса, она не применяется ко всем его методам. Но индивидуальное применение метода работает абсолютно нормально.

user2594 15.08.2024 10:41

Добавление его в класс должно помочь, однако оно будет применяться только к методам этого класса, а не к методам расширенных классов.

M. Deinum 15.08.2024 10:42

Но это другой вопрос.

M. Deinum 15.08.2024 10:43

@M.Deinum Если мы будем использовать AspectJ вместо Spring AOP, это может сработать. AspectJ не использует прокси, он быстрее, мощнее и прекрасно интегрируется со Spring.

user2594 15.08.2024 11:03

Это применимо только в том случае, если вы используете полноценный аспектj, означающий время загрузки или переплетение времени компиляции. Если вы используете его так же, как здесь, то он все еще использует прокси. Поскольку используется только язык (выражения pointcut)

M. Deinum 15.08.2024 11:10

@M.Deinum Большое спасибо за понимание этого вопроса, я добавил ответ на этот вопрос согласно вашему предложению.

user2594 15.08.2024 20:15
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
19
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема здесь не в AspectJ или AOP, а в JVM. В Java аннотации к

  • интерфейсы,
  • методы или
  • другие аннотации

никогда не наследуются

  • реализация классов,
  • переопределяющие методы или
  • классы с использованием аннотированных аннотаций.

Наследование аннотаций работает только от классов к подклассам, но только если тип аннотации, используемый в суперклассе, содержит метааннотацию @Inherited.

Другие вопросы по теме