注解的产生
简介
注解(也被称为元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。
注解在一定程度上是在把元数据与源代码文件结合在一起,而不是保存在外部文档中这一大的趋势之下所催生的。
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 [email protected]
* @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 [email protected]
* @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
好了,我继续去找为什么报错的原因了…