快轉到主要內容

annotation 與 AOP

·1970 字·4 分鐘·
PolloChang
作者
PolloChang
我是一隻雞

範例程式完整專案:

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)記錄組件

原始碼
#

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
 * 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,會執行

原始碼
#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/*
 * 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
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
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
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
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

1
2
3
4
5
6
7
8
9
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
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
package work.pollochang.example.ex2

import work.pollochang.annotation.Test1

class Example2Service {

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

參考資料
#