注解简单来说就是配置,是特别的配置,之前常用的配置文件,可以用注解替换。然后通过反射去获取注解的信息。

如何定义一个注解

你在IDE中新建一个注解定义,是这样的结构的:

package com.nicchagil.exercise.springbootexercise.annotation;

public @interface MyFirstAnnotation {

}

然后大概有4个对上述结构加上一些配置,当然,这配置是以注解的形式添加的=_=!

此注解使用在哪里

此注解会应用的哪里,可通过如下配置:

保留在什么时候

保留到什么时候:

注解体现在文档中

@Documented

子类是否继承父类的注解

@Inherited

用反射获取注解的信息

我们先定义一个注解:

package com.nicchagil.exercise.springbootexercise.annotation;

import java.lang.annotation.Documented;
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)
@Documented
public @interface PojoPostProcessing { public Class targetClass(); public String[] whiteProperties(); }

使用注解,比如这里我设置到一个方法上:

	@PojoPostProcessing(targetClass=User.class, whiteProperties={"name"})
public List<User> selectXxx(String id) {
......
}

反射获取注解的信息:

	@Test
public void test() throws NoSuchMethodException, SecurityException, ClassNotFoundException {
Class clazz = Class.forName("com.nicchagil.exercise.springbootexercise.service.UserService"); Method method = clazz.getMethod("selectXxx", String.class); boolean isAnnotationPresent = method.isAnnotationPresent(PojoPostProcessing.class);
if (!isAnnotationPresent) {
return;
} PojoPostProcessing dpp = (PojoPostProcessing)method.getAnnotation(PojoPostProcessing.class);
this.logger.info("dpp : {}", dpp);
}

日志:

dpp : @com.nicchagil.exercise.springbootexercise.annotation.PojoPostProcessing(targetClass=class com.nicchagil.exercise.springbootexercise.mapper.entity.User, whiteProperties=[name])

在Spring AOP中解析注解,然后实体你注解需要做的业务

比如以下就是在Spring AOP中拦截到方法,通过JoinPoint获取反射的Method,然后看是否有指定注解,如果有注解,后面就是关于此注解要做的业务逻辑了:

package com.nicchagil.exercise.springbootexercise.aop;

import java.lang.reflect.Method;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration; import com.nicchagil.exercise.springbootexercise.annotation.PojoPostProcessing; @Aspect
@Configuration
public class ServiceControllerLogAop { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Pointcut("execution(* com.nicchagil.exercise.springbootexercise.service.*Service.*(..))")
public void myPointcut() {
} @AfterReturning("myPointcut()")
public void myBefore(JoinPoint joinPoint) {
/* 获取方法对象 */
Signature signature = joinPoint.getSignature();
if (signature == null && !(signature instanceof MethodSignature)) {
return;
} MethodSignature methodSignature = (MethodSignature)signature;
Method method = methodSignature.getMethod(); /* 是否有指定注解 */
boolean isAnnotationPresent = method.isAnnotationPresent(PojoPostProcessing.class);
if (!isAnnotationPresent) {
return;
} /* 获取注解信息 */
PojoPostProcessing dpp = (PojoPostProcessing)method.getAnnotation(PojoPostProcessing.class);
this.logger.info("dpp : {}", dpp);
} }

过滤注解方法的返回值的指定属性

将属性置空的工具类:

package com.nicchagil.exercise.springbootexercise.util;

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.core.MethodParameter; public class BeanClearUtils { private static Logger logger = LoggerFactory.getLogger(BeanClearUtils.class); public static void clearProperty(Object obj, String[] whiteProperty) {
List<PropertyDescriptor> clearList = BeanClearUtils.getClearProperty(obj.getClass(), whiteProperty); try {
for (PropertyDescriptor pd : clearList) {
MethodParameter mp = BeanUtils.getWriteMethodParameter(pd);
Method method = mp.getMethod();
method.invoke(obj, new Object[] {null});
}
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new RuntimeException("设置空属性失败", e);
}
} /**
* 获取需要清除的字段列表
*/
public static List<PropertyDescriptor> getClearProperty(Class<?> clazz, String[] whiteProperty) {
PropertyDescriptor[] allPropertyDescriptor = BeanUtils.getPropertyDescriptors(clazz); /* 需保留的字段 */
Set<String> whitePropertySet = new HashSet<String>(Arrays.asList(whiteProperty));
whitePropertySet.add("class"); // 此字段无须清除 /* 需清除的字段 */
List<PropertyDescriptor> clearList = new ArrayList<PropertyDescriptor>();
for (PropertyDescriptor propertyDescriptor : allPropertyDescriptor) {
if (!whitePropertySet.contains(propertyDescriptor.getName())) {
clearList.add(propertyDescriptor);
}
}
return clearList;
} }

定义注解:

package com.nicchagil.exercise.springbootexercise.annotation;

import java.lang.annotation.Documented;
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)
@Documented
public @interface PojoPostProcessing { public String[] whiteProperties(); }

处理注解逻辑:

package com.nicchagil.exercise.springbootexercise.aop;

import java.lang.reflect.Method;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration; import com.nicchagil.exercise.springbootexercise.annotation.PojoPostProcessing;
import com.nicchagil.exercise.springbootexercise.util.BeanClearUtils; @Aspect
@Configuration
public class BeanPropertyFilterAop { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Pointcut("execution(* com.nicchagil.exercise.springbootexercise.service.*Service.*(..))")
public void myPojoPostProcessingPointcut() {
} @AfterReturning(value = "myPojoPostProcessingPointcut()", returning = "returnObject")
public void myAfter(JoinPoint joinPoint, Object returnObject) {
/* 获取方法对象 */
Signature signature = joinPoint.getSignature();
if (signature == null && !(signature instanceof MethodSignature)) {
return;
} MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod(); /* 是否有指定注解 */
boolean isAnnotationPresent = method.isAnnotationPresent(PojoPostProcessing.class);
if (!isAnnotationPresent) {
return;
} /* 获取注解信息 */
PojoPostProcessing dpp = (PojoPostProcessing) method.getAnnotation(PojoPostProcessing.class);
this.logger.info("dpp : {}", dpp); /* 只保留bean的指定属性值(其它属性值置空) */
logger.info("before bean : {}", returnObject);
BeanClearUtils.clearProperty(returnObject, dpp.whiteProperties());
logger.info("after bean : {}", returnObject);
} }

使用注解:

@PojoPostProcessing(whiteProperties={"name", "createTime"})

【Java基础】Java注解简单入门的更多相关文章

  1. Java基础-Java中23种设计模式之常用的设计模式

    Java基础-Java中23种设计模式之常用的设计模式 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.   一.设计模式分类 设计模式是针对特定场景给出的专家级的解决方案.总的来说设 ...

  2. Java基础-Java数据类型

    Java基础-Java数据类型 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.数据类型的作用 数据类型就是一组值,以及这一组值上的操作,数据类型可以决定数据的存储方式,取值范围 ...

  3. java基础---->java中正则表达式二

    跟正则表达式相关的类有:Pattern.Matcher和String.今天我们就开始Java中正则表达式的学习. Pattern和Matcher的理解 一.正则表达式的使用方法 一般推荐使用的方式如下 ...

  4. Java基础-Java中的堆内存和离堆内存机制

    Java基础-Java中的堆内存和离堆内存机制 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.

  5. Java基础-Java中的内存分配与回收机制

    Java基础-Java中的内存分配与回收机制 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一. 二.

  6. Java基础-Java中的并法库之重入读写锁(ReentrantReadWriteLock)

    Java基础-Java中的并法库之重入读写锁(ReentrantReadWriteLock) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在学习Java的之前,你可能已经听说过读 ...

  7. Java基础-Java中的并法库之线程池技术

    Java基础-Java中的并法库之线程池技术 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是线程池技术 二.

  8. Java基础-JAVA中常见的数据结构介绍

    Java基础-JAVA中常见的数据结构介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是数据结构 答:数据结构是指数据存储的组织方式.大致上分为线性表.栈(Stack) ...

  9. 【转载】JAVA基础:注解

    原文:https://www.cnblogs.com/xdp-gacl/p/3622275.html#undefined 一.认识注解 注解(Annotation)很重要,未来的开发模式都是基于注解的 ...

随机推荐

  1. UVA 1592 DataBase

    思路: 知识补充: ①make_pair和pair: /*pair是将2个数据组合成一个数据,当需要这样的需求时就可以使用pair,如stl中的map就是将key和value放在一起来保存.另一个应用 ...

  2. vue项目的搭建使用

    环境变量的安装 参考  环境变量详解 第一次搭建参考 参考  简单初始项目搭建 配置好环境变量的项目的搭建 新建一个new proproject, 查看工作目录vue是否存在    使用查看指令  v ...

  3. web前端知识大纲:系列一 js篇

    web前端庞大而复杂的知识体系的组成:html.css和 javascript           一.js           1.基础语法 Javascript 基础语法包括:变量声明.数据类型. ...

  4. Scrapy基础(二)————Scrapy的安装和目录结构

    Scrapy安装: 1,首先进入虚拟环境    2,使用国内豆瓣源进行安装,快! pip install -i https://pypi.douban.com/simple/ scrapy 3,特殊情 ...

  5. 数据库——MongoDB的安装

    1.进入到 /usr/local/ 目录: 1 cd /usr/local 2.安装必要插件 yum -y install gcc make gcc-c++ openssl-devel wget yu ...

  6. [CF961E] Tufurama

    Description: 有一天Polycarp决定重看他最喜爱的电视剧<Tufurama>.当他搜索"在线全高清免费观看Tufurama第3季第7集"却只得到第7季第 ...

  7. [模板][P4782]2-SAT

    Description: 有n个布尔变量\(x_1\)~\(x_n\),另有m个需要满足的条件,每个条件的形式都是"\(x_i\)为true/false或\(x_j\)为true/false ...

  8. shell脚本6--循环,比较

    for循环 for var in list; do commands;#使用变量$var done example: for i in {a..z}; do actions; done; 后者 for ...

  9. C++学习笔记46:模板与群体数据

    函数模板 创建一个通用功能的函数,支持多种不同的形参:简化重载函数的函数体设计: 语法形式 template <模板参数表> 函数定义:模板参数表的内容:类型参数:class(或typen ...

  10. python之对象(实例)

    1.对象是关于类而实际存在的一个例子,即实例 #类实例化得到g1这个实例 class Garen: camp='Demacia' def __init__(self,nickname,aggressi ...