annotation 與 AOP

2024-04-13 工作雜記 java AOP

範例程式完整專案:

Java 基本內置 annotation

@Override

重寫父層的方法

@Deprecated

表示該方法再為雷會被棄用

@SuppressWarnings

主要的用處就是忽略警告信息

規定 annotation 可以放在哪裡

類別

  • ElementType.TYPE : 能修飾類、接口、枚舉、注解
  • ElementType.FIELD : 能修飾字段、枚舉的常量
  • ElementType.METHOD : 能修飾方法
  • ElementType.PARAMETER : 能修飾方法參數
  • ElementType.CONSTRUCTOR : 能修飾構造函數
  • ElementType.LOCAL_VARIABLE : 能修飾局部變量
  • ElementType.ANNOTATION_TYPE : 能修飾注解 (元注解就是此種)
  • ElementType.PACKAGE : 能修飾包
  • ElementType.TYPE_PARAMETER: (java8)類型參數聲明
  • ElementType.TYPE_USE: (java8)使用類型
  • ElementType.MODULE: (java9)模組聲明
  • ElementType.RECORD_COMPONENT: (java16)記錄組件

原始碼

/*
 * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package java.lang.annotation;

/**
 * The constants of this enumerated class provide a simple classification of the
 * syntactic locations where annotations may appear in a Java program. These
 * constants are used in {@link java.lang.annotation.Target Target}
 * meta-annotations to specify where it is legal to write annotations of a
 * given type.
 *
 * <p>The syntactic locations where annotations may appear are split into
 * <em>declaration contexts</em>, where annotations apply to declarations, and
 * <em>type contexts</em>, where annotations apply to types used in
 * declarations and expressions.
 *
 * <p>The constants {@link #ANNOTATION_TYPE}, {@link #CONSTRUCTOR}, {@link
 * #FIELD}, {@link #LOCAL_VARIABLE}, {@link #METHOD}, {@link #PACKAGE}, {@link
 * #MODULE}, {@link #PARAMETER}, {@link #TYPE}, and {@link #TYPE_PARAMETER}
 * correspond to the declaration contexts in JLS 9.6.4.1.
 *
 * <p>For example, an annotation whose interface is meta-annotated with
 * {@code @Target(ElementType.FIELD)} may only be written as a modifier for a
 * field declaration.
 *
 * <p>The constant {@link #TYPE_USE} corresponds to the type contexts in JLS
 * 4.11, as well as to two declaration contexts: class and interface
 * declarations (including annotation declarations) and type parameter
 * declarations.
 *
 * <p>For example, an annotation whose interface is meta-annotated with
 * {@code @Target(ElementType.TYPE_USE)} may be written on the class or
 * interface of a field (or within the class or interface of the field, if it
 * is a nested or parameterized class or interface, or array class), and may
 * also appear as a modifier for, say, a class declaration.
 *
 * <p>The {@code TYPE_USE} constant includes class and interface declarations
 * and type parameter declarations as a convenience for designers of
 * type checkers which give semantics to annotation interfaces. For example,
 * if the annotation interface {@code NonNull} is meta-annotated with
 * {@code @Target(ElementType.TYPE_USE)}, then {@code @NonNull}
 * {@code class C {...}} could be treated by a type checker as indicating that
 * all variables of class {@code C} are non-null, while still allowing
 * variables of other classes to be non-null or not non-null based on whether
 * {@code @NonNull} appears at the variable's declaration.
 *
 * @author  Joshua Bloch
 * @since 1.5
 * @jls 9.6.4.1 @Target
 * @jls 4.1 The Kinds of Types and Values
 */
public enum ElementType {
    /** Class, interface (including annotation interface), enum, or record
     * declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation interface declaration (Formerly known as an annotation type.) */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE,

    /**
     * Module declaration.
     *
     * @since 9
     */
    MODULE,

    /**
     * Record component
     *
     * @jls 8.10.3 Record Members
     * @jls 9.7.4 Where Annotations May Appear
     *
     * @since 16
     */
    RECORD_COMPONENT;
}

annotation 生命週期: @Retention

類別

  • RetentionPolicy.SOURCE: 不會編譯進去class
  • RetentionPolicy.CLASS: 會編譯進去class,但是不會執行
  • RetentionPolicy.RUNTIME: 會編譯進去class,會執行

原始碼

/*
 * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package java.lang.annotation;

/**
 * Annotation retention policy.  The constants of this enumerated class
 * describe the various policies for retaining annotations.  They are used
 * in conjunction with the {@link Retention} meta-annotation interface to
 * specify how long annotations are to be retained.
 *
 * @author  Joshua Bloch
 * @since 1.5
 */
public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

Spring AOP

  • 環境: grails 5.3.5

使用注入

  • grails-app/conf/spring/resources.groovy
package spring

import work.pollochang.aop.ExampleInterceptor

// Place your Spring DSL code here
beans = {
    /*
     * Spring AOP 設定
     */
    xmlns aop: "http://www.springframework.org/schema/aop"
    // 初始化攔截器
    aspectBean(ExampleInterceptor)
    aop.config("proxy-target-class": true) {
    }

}

AOP 程式片段

  • work.pollochang.aop.ExampleInterceptor.groovy
package work.pollochang.aop

import org.aspectj.lang.annotation.AfterReturning
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before
import org.springframework.stereotype.Component

/**
 * 範例攔截器
 * 使用 Spring AOP
 *
 * @doc https://docs.spring.io/spring-framework/docs/4.3.15.RELEASE/spring-framework-reference/html/aop.html
 */
@Aspect
@Component
//先不要使用 @Slf4j 會出現兩次
class ExampleInterceptor {

    /**
     * 攔截 package
     */
    @Before("execution(* work.pollochang.example.ex1.*.*(..))")
    static void beforeMethodExecution() {
        println "這個是指定 package 攔截: 執行方法之前"
    }

    /**
     * 攔截 package
     */
    @AfterReturning(pointcut = "execution(* work.pollochang.example.ex1.*.*(..))", returning = "result")
    static void afterMethodExecution(Object result) {
        println "這個是指定 package 攔截: 執行方法之後"
    }

    /**
     * 攔截 指定 annotation
     */
//    @Before("@annotation(org.springframework.transaction.annotation.Transactional)")
    @Before("@annotation(work.pollochang.annotation.Test1)")
    void test() {
        println "這個是使用 annotation 攔截"
    }
}

執行程式範例

指定 package 攔截

  • work.pollochang.example.ex1.ExampleService.groovy
package work.pollochang.example.ex1


/**
 * 範例 Service
 */
class ExampleService {

    /**
     * 範例執行方法
     */
    void doSomething() {
        println "Doing something..."
        // 模擬程式操作
        Thread.sleep(1000)
        println "Done!"
    }
}

指定 annotation

  • work.pollochang.annotation.Test1.java

這邊先建立一個 annotation

package work.pollochang.annotation;

import java.lang.annotation.*;

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Test1 {
}
  • work.pollochang.example.ex2.Example2Service.groovy
package work.pollochang.example.ex2

import work.pollochang.annotation.Test1

class Example2Service {

    /**
     * 範例執行方法
     */
    @Test1
    void doSomething() {
        println "Doing something..."
        // 模擬程式操作
        Thread.sleep(1000)
        println "Done!"
    }
}

參考資料