java注解是怎么生效的?

注解的产生

简介

注解(也被称为元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。

注解在一定程度上是在把元数据与源代码文件结合在一起,而不是保存在外部文档中这一大的趋势之下所催生的。

java SE5引入了注解。
其实这也就是,增加了工作的效率,同样加大了代码的耦合度。

也是,工作效率和代码耦合度,二者不可能都能顾及到,找到一个最佳的契合就好。鱼和熊掌不可兼得呀。

java内置注解

java.lang中的标准注解:

  • @Override,表示当前的方法定义将覆盖超类中的方法。
  • @Deprecated,如果程序员使用了注解为它的元素,那么编译器会发出警告信息
  • @SuppressWarnings,关闭不当的警告信息。

另外四种专门负责新注解的创建(元注解):

注解解释
@Target 表示该注解可以用于生么地方。可能的ElementType参数包括:
CONSTRUCTOR:构造器的声明
FIELD:域声明
LOCAL_VARIABLE:局部变量声明
METHOD:方法声明
PACKAGE:包声明
PARAMETER:参数声明
TYPE:类、接口(包括注解类型)或enum声明
@Retention表示需要在什么级别保存该注解信息.可选的RetentionPolicy参数包括:
SOURCE:注解将被编译器丢弃
CLASS:注解在class文件中可用,但会被vm丢弃
RUNTIME:VM将在运行期也保留注解,因此可以通过反射机制读取注解的信息
@Documented将此注解包含在Javadoc中
@Inherited允许子类继承父类中的注解

自定义注解

一般地,注解使用的一套流程是这样的

在这里插入图片描述

只进行注解的创建和使用,显然是无效的.必须要进行注解处理,否则就是无根之水.

处理注解

Java SE5 扩展了反射机制的API,同时还提供了一个外部工具apt来处理解析带有注解的Java源代码.

这里我只找到两种处理注解的方式,如果谁有更好的,更多麻烦评论告诉我谢谢.

第一种 spring容器的aop+反射

import com.ql.entity.LoginUser;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @author qinlei
 * @email qlanto_147@163.com
 * @date 2020/11/21 11:23
 */
@Aspect
@Component
public class InjectRealNameAspect {

    /**
     * 切入点
     */
    @Pointcut("@annotation(com.ql.aspect.InjectRealName)")
    public void injectPointCut() {

    }

    /**
     * 环绕模式
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("injectPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        //获取调用方法传入的参数
        Object[] args = point.getArgs();
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        InjectRealName injectRealName = method.getAnnotation(InjectRealName.class);
        //第一个参数
        //第一个参数必须是需要操作的实体类
        int methodType = injectRealName.method();
        //通过shiro获取当前操作人信息
        // LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        //此处直接给出
        LoginUser sysUser = new LoginUser("qlanto");
        
        //0更新 1修改
        if(methodType == 0){
            InjectRealNameAspect.setPrivateField(args[0],"createBy",sysUser.getRealname());
        }else{
            InjectRealNameAspect.setPrivateField(args[0],"updateBy",sysUser.getRealname());
        }
        //执行方法
        Object result = point.proceed();
        return result;
    }

    /**
     * 设置私有成员的值
     * @param instance
     * @param fieldName
     * @param value
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static void setPrivateField(Object instance, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
        Field field = instance.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(instance, value);
    }


}

第二种 注解处理器+JAVA SPI+反射

目录结构图
spi 扩展processor注解处理机制
javax.annotation.processing.Processor内容

com.ql.processor.InjectProcessor

继承AbstractProcessor,重写

import com.google.auto.service.AutoService;
import org.jeecg.modules.demo.test.aspect.InjectRealName;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 * @author qinlei
 * @email qlanto_147@163.com
 * @date 2020/11/21 14:21
 */

//@AutoService(Processor.class)
public class InjectProcessor extends AbstractProcessor {
    private Types typeUtils;
    private Elements elementUtils;
    private Filer filer;
    private Messager messager;
    static{
        System.out.println("InjectProcessor start...");
    }

    /**
     * 注解处理器初始化
     */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        filer = processingEnv.getFiler();
        messager = processingEnv.getMessager();
        elementUtils = processingEnv.getElementUtils();
        messager = processingEnv.getMessager();
    }

    /**
     *  处理注解
     * @param arg0
     * @param arg1
     * @return
     */
    @Override
    public boolean process(Set<? extends TypeElement> arg0,
                           RoundEnvironment arg1) {
        try {
            for (Element element : arg1.getElementsAnnotatedWith(InjectRealName.class)) {
                //做很多的校验...
                
                //进行处理
            }
        }catch (Exception e){

        }
        return false;
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> annotataions = new LinkedHashSet<String>();
        annotataions.add(InjectRealName.class.getCanonicalName());
        return annotataions;
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }
}

请注意 上面代码有个注解@AutoService,他是谷歌的自动生成META-INF/services/***这个文件的

PS:这个@AutoService这个注解源码也是使用的SPI实现的processor!

maven地址:

		<dependency>
			<groupId>com.google.auto.service</groupId>
			<artifactId>auto-service</artifactId>
			<version>1.0-rc1</version>
			<optional>true</optional>
		</dependency>

使用这个注解也可以.

PS:做到这里,我在一直提示

java: 服务配置文件不正确, 或构造处理程序对象javax.annotation.processing.Processor: Provider ****.processor.InjectProcessor not found时抛出异常错误

至今还没解决,如果大家有方法,请评论告知我,谢谢 了!

另外,大家可以参考这个文章,来实现第二种:

https://www.race604.com/annotation-processing

好了,我继续去找为什么报错的原因了…

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qlanto

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值