Java 中的注解 annotation

注解的定义

也可以见 [[Secretpad 源码导读#注解的详细讲解|Secretpad 源码导读 > 注解的详细讲解]]

In the definition of @ApiResource, String code(); looks like a function declaration, but in the context of an annotation, it defines an attribute named code that accepts a String value. This is the standard syntax for declaring attributes within a Java annotation.

When you use the annotation, as in @ApiResource(code = ApiResourceCodeConstants.PRJ_LIST), you are not calling a function. Instead, you are assigning a value (ApiResourceCodeConstants.PRJ_LIST) to the code attribute of the @ApiResource annotation.

So, to clarify:

  • In the annotation definition (@interface): String code(); declares an attribute named code.

  • In the annotation usage (@ApiResource(...)): code = "..." assigns a value to that code attribute.

    It’s a syntactic quirk of Java annotations that the attribute declaration looks like a method signature.
    .

APO 与Spring boot 配置

Since the @secretpad-web/src/main/java/org/secretflow/secretpad/web/aop/InterfaceResourceAspect.java is an aspect. How does the aspect is configured in this spring-boot project? How does this aspect work? How does it know which thing should intercept? All of the requests or all of methods should intercept?

Excellent questions. You’re digging into the core of how Spring Boot and AOP work together, which is often described as “magic” but is actually a very well-defined process.

Let’s break it down.

1. How is the Aspect Configured? (The “Auto-Magic”)

In a modern Spring Boot project, you don’t need extensive XML configuration for AOP. The configuration is primarily done through annotations and auto-configuration.

  • Dependency: The project includes the spring-boot-starter-aop dependency (usually as a transitive dependency from starters like spring-boot-starter-web). This starter tells Spring Boot to enable AOP support.

  • @Aspect and @Component: The InterfaceResourceAspect class is annotated with both @Aspect and @Component.

    • @Aspect tells the Spring AOP framework that this class contains “advice” and “pointcuts” that should be woven into the application.
    • @Component makes the aspect itself a Spring bean, so it’s managed by the Spring container and can have other dependencies (like ApiResourceAuth) injected into it.

    That’s it for configuration. When the application starts, Spring scans for components, finds the InterfaceResourceAspect, recognizes it as an aspect, and automatically creates the necessary proxies to make it work.

    2. How Does It Work? (The Proxy Pattern)

    The “magic” behind AOP is a design pattern called the Proxy Pattern.

  1. When the application starts, Spring identifies all the beans that need to be intercepted by an aspect (in this case, any bean with a method annotated with @ApiResource).

  2. Instead of creating and injecting the original bean (e.g., your P2PProjectController), Spring creates a Proxy object that wraps your original controller.

  3. This proxy has the exact same methods as your controller, but it has the aspect’s logic (the “advice”) woven into it.

  4. When another part of your application calls a method on your controller, it’s actually calling the method on the proxy.

  5. The proxy then executes the aspect’s advice (the check method). Inside the advice, the aspect decides whether to call the original method on the real controller object (joinPoint.proceed()) or to block it (by throwing an exception).

    3. How Does It Know What to Intercept? (@Pointcut)

    This is the most crucial part of your question. The aspect does not intercept all requests or all methods. It’s very specific, and this is defined by the @Pointcut annotation.

    Look at this line in InterfaceResourceAspect.java:

    @Pointcut("@annotation(org.secretflow.secretpad.common.annotation.resource.ApiResource)")  
    

    This is a pointcut expression. It tells the AOP framework exactly where to apply the advice. Let’s break it down:

  • @annotation(...): This tells the aspect to target (or “cut” into) any method that is annotated with a specific annotation.

  • org.secretflow.secretpad.common.annotation.resource.ApiResource: This is the fully qualified name of the annotation.

    So, this pointcut expression means: “Intercept any method, in any Spring bean, that has the @ApiResource annotation.”

    4. The Advice Itself (@Around)

    The @Around annotation defines the code that runs when the pointcut is matched.

    @Around("pointCut() && args(data) && @annotation(apiResource)")  
    public Object check(ProceedingJoinPoint joinPoint, Object data, ApiResource apiResource) throws Throwable {    // ... permission checking logic ...    return joinPoint.proceed();  
    }  
    
  • @Around: This is a type of advice that “wraps” the original method call. It gives the aspect full control to run code before and after the method, and even to prevent the method from running at all.

  • pointCut(): This links the advice to the @Pointcut we defined above.

  • @annotation(apiResource): This is a clever trick. It not only helps match the pointcut but also captures the actual annotation instance from the method and makes it available as a parameter (apiResource) to the check method. This is how the aspect gets the code value by calling apiResource.code().

  • joinPoint.proceed(): This is the line that executes the original, intercepted method (e.g., listP2PProject). If this line is never called, the controller method never runs.


apo 中的pointcut

Of course. You’re asking the central question of AOP: “How do I specify where my aspect’s logic should run?” The answer is the pointcut.

The Concept of a Pointcut

Think of a Pointcut as a query or a predicate that selects a set of “join points”.

  • A Join Point is a well-defined point in the execution of a program. In Spring AOP, a join point is always the execution of a method.

  • A Pointcut is the expression that matches a collection of these join points. It’s the “WHERE” clause of AOP.

    So, if your entire application’s execution flow is a huge collection of method calls, a pointcut is a rule you write to select a specific subset of those method calls to which you want to apply your advice (your aspect’s logic).

    Pointcut Designators: Beyond @annotation

    Besides @annotation, Spring AOP provides a powerful set of “pointcut designators” (PCDs) to select join points. Here are the most common ones:

    1. execution() - The Workhorse

    This is the most common and powerful designator. It matches method execution join points based on a detailed signature pattern.

  • *Syntax:** execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)

  • ? indicates an optional part.

  • * is a wildcard for any single element.

  • .. is a wildcard for zero or more elements.

  • *Examples:**

  • Match any public method:

    @Pointcut("execution(public * *(..))")  
    ```*   Match any method in the `ProjectService`:  
    ```java  
    @Pointcut("execution(* org.secretflow.secretpad.service.ProjectService.*(..))")  
    ```*   Match any method in any class within the `web.controller` package:  
    ```java  
    @Pointcut("execution(* org.secretflow.secretpad.web.controller..*.*(..))")  
    ```    (Note the `..` after `controller` to match sub-packages).  
    
    #### 2. `within()` - Type-Based Matching  
    
    This selects all join points (method executions) within classes that match a certain type pattern. It's simpler than `execution` if you just want to target a whole class or package.  
    
  • *Examples:**

  • Match all methods in the P2PProjectController class:

    @Pointcut("within(org.secretflow.secretpad.web.controller.p2p.P2PProjectController)")  
    ```*   Match all methods in any class in the `service` package (and its sub-packages):  
    ```java  
    @Pointcut("within(org.secretflow.secretpad.service..*)")  
    

    3. args() - Argument-Based Matching

    This matches method executions where the arguments at runtime are instances of the given types.

  • *Examples:**

  • Match any method that takes a single String as its first parameter:

    @Pointcut("args(String, ..)")  
    ```*   Match any method that takes exactly one argument of type `CreateProjectRequest`:  
    ```java  
    @Pointcut("args(org.secretflow.secretpad.service.model.project.CreateProjectRequest)")  
    

    4. @within() - Annotation on Type

    This is similar to within(), but it matches any join point within a type that has a given annotation.

  • *Example:**

  • Match all methods in any class that is annotated with @RestController:

    @Pointcut("@within(org.springframework.web.bind.annotation.RestController)")  
    

    5. @target() - Annotation on Target Object’s Class

    This is slightly different from @within. It checks if the class of the target object being invoked has the given annotation. In most simple cases, it behaves like @within, but it can differ in complex proxying scenarios.

  • *Example:**

  • Match method executions where the target object’s class is annotated with @Service:

    @Pointcut("@target(org.springframework.stereotype.Service)")  
    

    6. bean() - Spring Bean Name

    This allows you to target a specific Spring bean by its name (its ID in the Spring container).

  • *Example:**

  • Match all methods on the Spring bean named projectServiceImpl:

    @Pointcut("bean(projectServiceImpl)")  
    

    Combining Pointcuts

    You can also combine these expressions using logical operators (&&, ||, !) to create very precise and powerful pointcuts.

    For example, you could intercept all public methods within the service layer that return a String:

    @Pointcut("execution(public String org.secretflow.secretpad.service..*.*(..))")  
    

    The InterfaceResourceAspect you saw uses this combination implicitly in the @Around advice: pointCut() && args(data) && @annotation(apiResource). This means “apply this advice where the pointCut() matches, AND where the method has arguments that can be bound to data, AND where the method has an annotation that can be bound to apiResource.”