JAvaはコードを優雅にする方法--カスタム注釈
5690 ワード
一、注釈とは何か
JAvaでは、注釈は2つ、メタ注釈とカスタム注釈に分けられます.@Autowired、@Overrideなど、カスタム注釈としてよく使用されます.
二、javaのメタ注釈
注釈を記述する注釈として理解できます.これらのメタ注釈を除いて、すべての注釈はカスタム注釈です.@Document:javaドキュメントに注記情報を追加するかどうかを示す @Target:注釈がどこで使用されるかを示します. ElementType.CONTRUCTOR:コンストラクタを記述するための ElementType.FIELD:メンバー変数、オブジェクト、属性(enumインスタンスを含む) ElementType.LOCAL_VARABLE:局所変数 を記述する ElementType.METHOD:記述方法 ElementType.PACKAGE:パケットを記述するための ElementType.PARAMETER:パラメータを記述するための ElementType.TYPE:クラス、インタフェース(注釈タイプを含む)またはenum宣言 を記述するために使用される
@Retention:注釈のライフサイクルを定義します. RetentionPolicy.SOURCE:コンパイル時に破棄されます.バイトコードは書き込みません.@Override,@SuppressWarningsはこのような注釈に属します. RetentionPolicy.CLASS:クラスのロード時に破棄されます.バイトコードファイルの処理に役立ちます.注記デフォルトでは、この方法が使用されます. RetentionPolicy.RUNTIME:常に破棄されず、実行期間もこの注釈を保持するため、反射メカニズムを使用してこの注釈情報を読み取ることができます.
@Inherited:コメントとサブクラスの関係を定義 は、マークされたタイプが継承されていることを示すマーク注記です.@Inherited修飾を使用したannotationタイプがclassに使用される場合、このannotationはclassのサブクラスに使用されます.
三、カスタム注釈
カスタム注記作成規則: Annotation型は@interfaceと定義され、すべてのAnnotationはjava.lang.Annotationというインタフェースを自動的に継承し、他のクラスやインタフェースを継承することはできません. パラメータメンバーはpublicまたはデフォルト(default)の2つの反問権修飾 のみを使用できます.パラメータメンバーは、8つの基本データ型とString、Enum、Class、annotationsなどのデータ型、およびこれらのタイプの配列しか使用できません. クラスメソッドとフィールドの注釈情報を取得するにはjavaの反射技術によりAnnotationオブジェクトを取得する必要があり、それ以外に注釈オブジェクトを取得する方法はない .
四、注釈実装:アクセスログを記録する
4.1 pomファイル
4.2注釈をカスタマイズ
このクラスでは、注記の2つのプロパティが定義されています.1つ目はname、2つ目はSpel式です.
4.3うどん
ここでは主にaspectjのクラスライブラリで反射を実現し,注釈属性を取得し,Spel式を解析し,最後にhandle法でログの印刷出力を実現する.
4.4注釈の使用
ここでidExpressionはSpel式であり,「#id」は取得方法におけるidという局所変数を表す.
urlへのアクセス:
ログは次のように印刷されます.
JAvaでは、注釈は2つ、メタ注釈とカスタム注釈に分けられます.@Autowired、@Overrideなど、カスタム注釈としてよく使用されます.
二、javaのメタ注釈
注釈を記述する注釈として理解できます.これらのメタ注釈を除いて、すべての注釈はカスタム注釈です.
三、カスタム注釈
カスタム注記作成規則:
四、注釈実装:アクセスログを記録する
4.1 pomファイル
org.springframework.boot
spring-boot-starter-web
org.aspectj
aspectjweaver
1.8.9
org.apache.commons
commons-lang3
com.google.guava
guava
30.1-jre
org.springframework.boot
spring-boot-starter-test
test
4.2注釈をカスタマイズ
/**
* @Author: KD
* @Date: 2021/1/1 1:02
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TheLog {
/**
*
*
* @return
*/
public String name();
/**
* id
*
* @return
*/
public String idExpression();
}
このクラスでは、注記の2つのプロパティが定義されています.1つ目はname、2つ目はSpel式です.
4.3うどん
/**
* @Author: KD
* @Date: 2021/1/1 1:02
*/
@Aspect
@Component
public class TheAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(TheAspect.class);
@Autowired
HttpServletRequest request;
@Around("@annotation(com.example.zhujie.anno.TheLog)")// TheLog
public Object log(ProceedingJoinPoint pjp) throws Exception {
Method method = ((MethodSignature)pjp.getSignature()).getMethod();
TheLog theLog = method.getAnnotation(TheLog.class);
Object response = null;
try {
//
response = pjp.proceed();
} catch (Throwable throwable) {
throw new Exception(throwable);
}
if (StringUtils.isNotEmpty(theLog.idExpression())) {
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(theLog.idExpression());
EvaluationContext context = new StandardEvaluationContext();
//
Object[] args = pjp.getArgs();
//
LocalVariableTableParameterNameDiscoverer discoverer
= new LocalVariableTableParameterNameDiscoverer();
String[] parameterNames = discoverer.getParameterNames(method);
// context
if (parameterNames != null) {
for (int i = 0; i < parameterNames.length; i++) {
context.setVariable(parameterNames[i], args[i]);
}
}
// resp context ,
if (response != null) {
context.setVariable(
CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, response.getClass().getSimpleName()),
response);
}
// ,
String itemId = String.valueOf(expression.getValue(context));
//
handle(theLog.name(), itemId);
}
return response;
}
private void handle(String name, String theId) {
//
LOGGER.info("theType = " + name + ",theId = " + theId);
}
}
ここでは主にaspectjのクラスライブラリで反射を実現し,注釈属性を取得し,Spel式を解析し,最後にhandle法でログの印刷出力を実現する.
4.4注釈の使用
/**
* @Author: KD
* @Date: 2021/1/1 12:41
*/
@Controller
public class TestController {
@GetMapping("test")
@ResponseBody
@TheLog(name="test1",idExpression="#id")
public String test(String id){
return id;
}
}
ここでidExpressionはSpel式であり,「#id」は取得方法におけるidという局所変数を表す.
urlへのアクセス:
localhost:8080/test?id=123123
ログは次のように印刷されます.
2021-01-01 13:43:38.157 INFO 52624 --- [nio-8080-exec-1] com.example.zhujie.anno.TheAspect : theType = test1,theId = 123123