Java注解

Java注解大家基本都用过,但实际怎么生效的就是另外一回事了。你去看源代码发现其实就是一个接口再添加两个注解就完事了。本质就是一个接口,那对应的实现在哪里,具体逻辑是什么样的,就找不到了。

Java注解一般来说常见的可以分为几类,一种是过去的Java EE也就是现在的Jarkatar的包里面的注解。这种你可以理解为是大家制定了一个规范,定义了接口,输入参数和返回参数这些。具体实现要看各自的框架怎么落实,比如说tomcat这些web服务器。这些注解比如说@PostConstruct,@Resource这些。

另外一个是框架的注解,使用最多的就是Spring的注解,@Component,@Autowire这些,是Spring定义的注解。

还有就是我们自己定义的注解,比如说我们定义一个注解,以下是一个自定义的注解

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

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME) // 必须为 RUNTIME,否则反射无法读取
public @interface MyAnnotation {
    String value() default "默认值";
    int priority() default 1;
}

但实际你定义这个注解,只是一个接口,只是指定了ElementType.METHOD,在方法上使用。RetentionPolicy.RUNTIME指定了反射。但你定义,怎么使用又是一回事。

public class DemoService {

    @MyAnnotation(value = "高优先级任务", priority = 10)
    public void doImportantTask() {
        System.out.println("执行高优先级任务...");
    }

    @MyAnnotation("普通任务")
    public void doNormalTask() {
        System.out.println("执行普通任务...");
    }

    public void unannotatedMethod() {
        System.out.println("无注解方法");
    }
}

我们在方法上使用这个注解,但是到这部还没有用,你用反射可以有两种方式,一个是动态代理和cglib

JDK动态代理(基于接口)

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class JdkProxyDemo {

    public static void main(String[] args) {
        DemoService target = new DemoService();
        
        // 创建代理对象
        DemoService proxy = (DemoService) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // 检查方法是否有注解
                        if (method.isAnnotationPresent(MyAnnotation.class)) {
                            System.out.println("前置处理...");
                        }
                        Object result = method.invoke(target, args);
                        if (method.isAnnotationPresent(MyAnnotation.class)) {
                            System.out.println("后置处理...");
                        }
                        return result;
                    }
                });

        proxy.doImportantTask(); // 触发代理逻辑
    }
}

cglib(基于类)
引入依赖

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CglibProxyDemo {

    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(DemoService.class);
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                if (method.isAnnotationPresent(MyAnnotation.class)) {
                    System.out.println("CGLIB 前置处理...");
                }
                Object result = proxy.invokeSuper(obj, args);
                if (method.isAnnotationPresent(MyAnnotation.class)) {
                    System.out.println("CGLIB 后置处理...");
                }
                return result;
            }
        });

        DemoService proxy = (DemoService) enhancer.create();
        proxy.doImportantTask();
    }
}

当然我们在项目中一般不会直接用动态代理(JDK或者cglib),我们一般用框架Spring框架自动化处理。

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

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME) // 必须为 RUNTIME,否则 AOP 无法读取
public @interface MyCustomAnnotation {
    String value() default "";
    int timeout() default 1000;
}
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component // 确保切面被 Spring 容器管理
public class MyAspect {

    // 环绕通知,匹配所有被 @MyCustomAnnotation 注解的方法
    @Around("@annotation(myAnnotation)") // 通过注解参数绑定
    public Object aroundAdvice(ProceedingJoinPoint joinPoint, MyCustomAnnotation myAnnotation) throws Throwable {
        // 获取注解参数值
        String value = myAnnotation.value();
        int timeout = myAnnotation.timeout();

        System.out.println("注解参数 value: " + value);
        System.out.println("注解参数 timeout: " + timeout);

        // 执行目标方法
        Object result = joinPoint.proceed();
        return result;
    }
}
import org.springframework.stereotype.Service;

@Service
public class MyService {

    @MyCustomAnnotation(value = "重要任务", timeout = 5000)
    public void doTask() {
        System.out.println("执行任务...");
    }
}

你可能感兴趣的:(java,python,开发语言)