Fundamentals 7 min read

Understanding Java Annotations and Custom Annotation Usage with Spring AOP

This article explains Java annotations, their purposes such as providing compiler metadata, generating code, runtime processing, and documentation, introduces built‑in and meta‑annotations, and demonstrates how to create and use custom annotations both via reflection and with Spring AOP for logging, including full code examples.

Full-Stack Internet Architecture
Full-Stack Internet Architecture
Full-Stack Internet Architecture
Understanding Java Annotations and Custom Annotation Usage with Spring AOP

Annotations are a form of metadata that can be applied to various code elements such as classes, fields, and methods, providing extra information without affecting program logic.

They serve several purposes: they give the compiler additional information (e.g., @Override, @Deprecated), can trigger code generation at compile time (e.g., Lombok), are processed at runtime to alter behavior (common in Spring), and can be used to generate documentation (e.g., @Documented).

The JDK includes built‑in annotations, and annotations that apply to other annotations are called meta‑annotations; there are five meta‑annotations.

Custom Annotations

Two simple examples illustrate annotation usage.

1. Reading annotation information via reflection.

package com.sample.core.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// Custom annotation with two attributes
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
    String value();
    String desc();
}

@MyAnnotation(value = "full-stack", desc = "欢迎来到编程世界")
public class MyClass {
}

public class AnnotationTest {
    public static void main(String[] args) {
        Class
myClass = MyClass.class;
        MyAnnotation myAnnotation = myClass.getAnnotation(MyAnnotation.class);
        System.out.println(myAnnotation.value());
        System.out.println(myAnnotation.desc());
    }
}

2. Spring AOP custom annotation for logging.

package com.fullstack.commerce.user.util;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyLog {
    // Log level
    String level();
}
package com.fullstack.commerce.user.util;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;

@Aspect
@Component
public class MyLogAspect {
    // Pointcut for methods annotated with @MyLog
    @Pointcut("@annotation(MyLog)")
    private void logPointCut() {}

    // Around advice to log before and after method execution
    @Around("logPointCut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String methodName = signature.getName();
        Method method = signature.getMethod();
        MyLog myLog = method.getAnnotation(MyLog.class);
        String level = myLog.level();
        System.out.println("方法名为:" + methodName + ",日志级别为:" + level);
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        System.out.println("方法的执行时间为:" + (System.currentTimeMillis() - start) + "毫秒。");
        return result;
    }
}
package com.fullstack.commerce.user.controller;

import com.fullstack.commerce.user.util.MyLog;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("hello")
public class HelloController {
    @GetMapping("test")
    @MyLog(level = "info")
    public String test() {
        return "Hello World";
    }
}

When the endpoint http://localhost:8080/hello/test is accessed, the console prints the method name, log level, and execution time, demonstrating how a custom annotation can centralize logging concerns.

The article focuses on using custom annotations to reduce boilerplate and improve maintainability, while noting that real‑world implementations may need additional enhancements based on specific business requirements.

BackendJavaaopReflectionSpringAnnotationsCustomAnnotation
Full-Stack Internet Architecture
Written by

Full-Stack Internet Architecture

Introducing full-stack Internet architecture technologies centered on Java

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.