JAVA 注解(Annotation):从原理到实战应用

JAVA 注解(Annotation):从原理到实战应用

JAVA 注解(Annotation):从原理到实战应用

在这里插入图片描述

1.1 本章学习目标与重点

💡 掌握注解的核心概念与分类,理解注解在Java开发中的核心价值。
💡 熟练使用JDK内置注解,掌握自定义注解的定义、解析与使用流程。
💡 掌握注解的元注解配置方式,理解不同元注解对自定义注解的约束作用。
💡 结合反射机制实现注解的实战应用,掌握注解在框架开发中的核心用法。
⚠️ 本章重点是 自定义注解的开发流程注解与反射结合的实战应用,这是Java高级开发与框架设计的必备技能。

1.2 注解的核心概念与价值

1.2.1 什么是注解

💡 注解(Annotation) 是Java 5引入的一种特殊标记,它可以在编译期、类加载期、运行时被读取,并执行相应的处理逻辑。注解本身不直接影响代码的执行逻辑,而是通过元数据的方式为程序提供额外信息,这些信息可以被编译器、虚拟机或自定义的注解处理器解析和使用。

注解的本质是一个继承了 java.lang.annotation.Annotation 接口的特殊接口,我们定义的每一个注解,最终都会被编译器生成对应的接口实现类,供程序在运行时调用。

1.2.2 注解的核心价值

在传统Java开发中,我们需要通过配置文件(如XML)来描述程序的元数据信息,而注解的出现,让元数据可以直接嵌入到代码中,实现了代码与配置的一体化。注解的核心价值主要体现在以下几个方面:

  1. 简化配置:替代XML等外部配置文件,减少配置文件的数量,降低维护成本。
  2. 增强代码可读性:元数据与代码紧密结合,开发者可以直接在代码中看到配置信息。
  3. 编译期检查:部分注解可以在编译期进行语法检查,提前发现潜在问题。
  4. 框架开发基石:是Spring、MyBatis等主流框架的核心技术,用于实现依赖注入、AOP、ORM映射等功能。

1.2.3 注解的分类

根据注解的使用范围和生命周期,我们可以将注解分为以下三类:

分类标准具体类型特点典型示例
JDK内置注解基本注解用于修饰代码元素(类、方法、属性等)@Override@Deprecated@SuppressWarnings
元注解注解的注解用于修饰自定义注解,约束注解的使用范围和生命周期@Target@Retention@Documented@Inherited
自定义注解业务注解开发者根据业务需求自行定义的注解,用于实现特定功能@RequestMapping@Autowired@Test

✅ 核心结论:注解是一种元数据标记,本身不执行任何逻辑,需要通过注解处理器(如反射、APT工具)解析后,才能发挥实际作用。

1.3 JDK内置注解详解

JDK提供了三个最基础的内置注解,用于辅助代码开发,这三个注解也是我们日常开发中使用频率最高的注解。

1.3.1 @Override:重写检查注解

💡 作用:用于标记方法是重写自父类或接口的方法,编译器会检查该方法的签名是否与父类完全一致,如果不一致则编译报错。
⚠️ 注意事项:该注解只能修饰方法,且只能用于重写场景,不能用于重载。

代码实操
/** * @Override 注解使用示例 */classParentClass{publicvoidsayHello(){System.out.println("父类的sayHello方法");}}classChildClassextendsParentClass{// 使用@Override标记该方法是重写自父类@OverridepublicvoidsayHello(){System.out.println("子类重写的sayHello方法");}// 错误示例:方法签名与父类不一致,编译报错// @Override// public void sayHello(String name) {// System.out.println("Hello " + name);// }}publicclassOverrideDemo{publicstaticvoidmain(String[] args){ParentClass child =newChildClass(); child.sayHello();// 输出:子类重写的sayHello方法}}

1.3.2 @Deprecated:过时标记注解

💡 作用:用于标记类、方法、属性等元素已过时,不推荐使用。编译器会对使用该元素的代码发出警告,提示开发者更换新的API。
⚠️ 注意事项:该注解标记的元素仍然可以使用,但存在被移除的风险,建议开发者使用替代方案。

代码实操
/** * @Deprecated 注解使用示例 */publicclassDeprecatedDemo{// 标记该方法已过时@DeprecatedpublicstaticvoidoldMethod(){System.out.println("这个方法已经过时了,请使用newMethod替代");}// 新的替代方法publicstaticvoidnewMethod(){System.out.println("这是新的推荐方法");}publicstaticvoidmain(String[] args){// 使用过时方法,编译器会发出警告oldMethod();// 使用推荐方法newMethod();}}

1.3.3 @SuppressWarnings:抑制警告注解

💡 作用:用于抑制编译器产生的特定类型警告,让代码编译时不再输出警告信息。
⚠️ 注意事项:该注解需要传入参数,指定要抑制的警告类型,常用参数有 unchecked(抑制未检查转换警告)、deprecation(抑制过时元素警告)、all(抑制所有警告)。

代码实操
importjava.util.ArrayList;importjava.util.List;/** * @SuppressWarnings 注解使用示例 */publicclassSuppressWarningsDemo{publicstaticvoidmain(String[] args){// 抑制未检查转换警告@SuppressWarnings("unchecked")List<String> list =newArrayList();// 原始类型ArrayList,默认会产生警告 list.add("Hello Annotation");System.out.println(list.get(0));// 抑制过时方法警告@SuppressWarnings("deprecation")voidtest(){DeprecatedDemo.oldMethod();// 调用过时方法,不会产生警告}test();}}

✅ 核心结论:JDK内置注解主要用于代码检查和提示,帮助开发者写出更规范的代码,提升代码质量。

1.4 元注解详解

元注解是用于修饰自定义注解的注解,JDK提供了四个标准元注解,它们分别从不同维度约束自定义注解的行为。

1.4.1 @Target:注解目标约束

💡 作用:指定自定义注解可以修饰的代码元素类型,如类、方法、属性等。
⚠️ 注意事项:如果不指定 @Target,则该注解可以修饰所有类型的代码元素。

@Target 的参数是一个 ElementType 枚举数组,常用枚举值如下:

枚举值可修饰的代码元素
TYPE类、接口、枚举
METHOD方法
FIELD属性(成员变量)
PARAMETER方法参数
CONSTRUCTOR构造方法
LOCAL_VARIABLE局部变量
ANNOTATION_TYPE注解

1.4.2 @Retention:注解生命周期约束

💡 作用:指定注解的生命周期,即注解在哪个阶段有效。
⚠️ 注意事项:这是自定义注解必须指定的元注解,否则注解默认在编译期就会被丢弃,无法在运行时通过反射获取。

@Retention 的参数是一个 RetentionPolicy 枚举值,三种枚举值对应注解的三个生命周期:

枚举值生命周期特点适用场景
SOURCE源码阶段注解仅存在于源码中,编译成字节码后被丢弃编译器检查,如 @Override
CLASS字节码阶段注解存在于源码和字节码中,类加载时被丢弃类加载器处理,如字节码增强
RUNTIME运行时阶段注解存在于源码、字节码和运行时,可通过反射获取框架开发,如Spring注解

1.4.3 @Documented:文档生成标记

💡 作用:指定该注解会被 javadoc 工具提取到API文档中。
⚠️ 注意事项:默认情况下,注解不会出现在API文档中,添加该元注解后,注解信息会被包含在文档里。

1.4.4 @Inherited:注解继承标记

💡 作用:指定该注解可以被子类继承,如果父类使用了该注解,子类会自动继承该注解。
⚠️ 注意事项:该注解仅对类级别注解有效,对方法、属性等注解无效。

代码实操:元注解使用示例
importjava.lang.annotation.*;/** * 自定义注解 + 元注解使用示例 * 该注解用于标记类的作者信息 */// 该注解只能修饰类@Target(ElementType.TYPE)// 注解在运行时有效,可通过反射获取@Retention(RetentionPolicy.RUNTIME)// 注解信息会被javadoc提取@Documented// 注解可以被子类继承@Inheritedpublic@interfaceAuthor{// 注解属性:作者姓名,必填Stringname();// 注解属性:作者邮箱,可选,默认值为空字符串Stringemail()default"";}

✅ 核心结论:元注解是自定义注解的规则约束器,通过元注解可以精准控制自定义注解的使用范围和生命周期。

1.5 自定义注解的开发流程

自定义注解是注解开发的核心,掌握自定义注解的定义、使用和解析流程,是实现注解驱动开发的关键。

1.5.1 步骤1:定义自定义注解

定义自定义注解的语法格式与定义接口类似,只是在 interface 关键字前加了一个 @ 符号。注解中可以定义属性,属性的定义方式与接口方法类似,支持指定默认值。

语法格式
[元注解]public@interface 注解名称 {// 注解属性定义 属性类型 属性名()[default 默认值];}
代码实操:定义两个常用自定义注解
importjava.lang.annotation.*;/** * 注解1:用于标记业务日志,记录方法的操作信息 */@Target(ElementType.METHOD)// 仅修饰方法@Retention(RetentionPolicy.RUNTIME)// 运行时有效public@interfaceLog{// 操作描述Stringdesc();// 操作类型,默认值为"OTHER"Stringtype()default"OTHER";}/** * 注解2:用于标记数据校验,校验方法参数的合法性 */@Target(ElementType.PARAMETER)// 仅修饰方法参数@Retention(RetentionPolicy.RUNTIME)// 运行时有效public@interfaceValidate{// 参数不能为空booleannotNull()defaulttrue;// 参数长度最小值,默认值为0intminLength()default0;}

1.5.2 步骤2:使用自定义注解

定义好自定义注解后,就可以在对应的代码元素上使用该注解,使用时需要为注解的必填属性赋值,可选属性可以使用默认值。

代码实操:使用自定义注解
/** * 自定义注解使用示例:用户服务类 */publicclassUserService{// 使用@Log注解标记方法,记录操作日志@Log(desc ="根据ID查询用户", type ="QUERY")publicStringgetUserById(// 使用@Validate注解标记参数,校验参数合法性@Validate(notNull =true, minLength =1)String userId){if(userId ==null|| userId.length()<1){return"参数不合法";}return"用户ID:"+ userId +",用户名:张三";}@Log(desc ="添加用户", type ="ADD")publicStringaddUser(@Validate(notNull =true, minLength =2)String username){if(username ==null|| username.length()<2){return"用户名长度不能小于2";}return"添加用户成功:"+ username;}}

1.5.3 步骤3:解析自定义注解

注解本身不会执行任何逻辑,必须通过注解解析器来读取注解信息,并执行相应的处理逻辑。在Java中,最常用的注解解析方式是反射机制

解析流程

① 获取目标类的 Class 对象。
② 获取目标方法或参数的注解对象。
③ 读取注解的属性值,执行自定义业务逻辑。

代码实操:反射解析自定义注解
importjava.lang.reflect.Method;importjava.lang.reflect.Parameter;/** * 注解解析器:解析@Log和@Validate注解 */publicclassAnnotationParser{/** * 解析@Log注解,输出方法操作日志 */publicstaticvoidparseLogAnnotation(Class<?> clazz){// 获取类中所有方法Method[] methods = clazz.getDeclaredMethods();for(Method method : methods){// 判断方法是否有@Log注解if(method.isAnnotationPresent(Log.class)){Log log = method.getAnnotation(Log.class);System.out.println("===== 方法操作日志 =====");System.out.println("方法名:"+ method.getName());System.out.println("操作描述:"+ log.desc());System.out.println("操作类型:"+ log.type());System.out.println("-----------------------");}}}/** * 解析@Validate注解,校验方法参数合法性 */publicstaticObjectinvokeAndValidate(Object obj,String methodName,Object... args)throwsException{// 获取目标方法Method method = obj.getClass().getDeclaredMethod(methodName,getParameterTypes(args));Parameter[] parameters = method.getParameters();// 校验参数for(int i =0; i < parameters.length; i++){Parameter param = parameters[i];if(param.isAnnotationPresent(Validate.class)){Validate validate = param.getAnnotation(Validate.class);Object arg = args[i];String paramName = param.getName();// 非空校验if(validate.notNull()&& arg ==null){thrownewIllegalArgumentException(paramName +" 不能为null");}// 长度校验if(arg instanceofString&&((String) arg).length()< validate.minLength()){thrownewIllegalArgumentException(paramName +" 长度不能小于"+ validate.minLength());}}}// 调用目标方法return method.invoke(obj, args);}// 获取参数类型数组privatestaticClass<?>[]getParameterTypes(Object... args){if(args ==null|| args.length ==0){returnnewClass[0];}Class<?>[] types =newClass[args.length];for(int i =0; i < args.length; i++){ types[i]= args[i].getClass();}return types;}// 测试方法publicstaticvoidmain(String[] args)throwsException{UserService userService =newUserService();// 解析@Log注解parseLogAnnotation(UserService.class);// 解析@Validate注解并调用方法System.out.println("正常调用:"+invokeAndValidate(userService,"getUserById","1001"));System.out.println("参数非法调用:"+invokeAndValidate(userService,"getUserById",""));}}

输出结果

===== 方法操作日志 ===== 方法名:getUserById 操作描述:根据ID查询用户 操作类型:QUERY ----------------------- ===== 方法操作日志 ===== 方法名:addUser 操作描述:添加用户 操作类型:ADD ----------------------- 正常调用:用户ID:1001,用户名:张三 Exception in thread "main" java.lang.IllegalArgumentException: arg0 长度不能小于1 

✅ 核心结论:自定义注解的开发流程是 定义 → 使用 → 解析,其中解析是核心步骤,反射是最常用的解析方式。

1.6 注解的高级应用场景

注解在Java开发中应用广泛,尤其是在框架开发和业务系统设计中,以下是几个典型的高级应用场景。

1.6.1 场景1:基于注解的AOP实现

💡 核心思想:通过注解标记需要增强的方法,结合动态代理实现AOP(面向切面编程),在方法执行前后添加通用逻辑(如日志、事务、权限校验)。

代码实操:注解+动态代理实现日志切面
importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;/** * 基于注解的AOP日志切面 */// 定义切面注解@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@interfaceLogAspect{}// 业务接口interfaceOrderService{@LogAspectvoidcreateOrder(String orderId);}// 业务实现类classOrderServiceImplimplementsOrderService{@OverridepublicvoidcreateOrder(String orderId){System.out.println("创建订单:"+ orderId);}}// 日志切面处理器classLogAspectHandlerimplementsInvocationHandler{privateObject target;publicLogAspectHandler(Object target){this.target = target;}@OverridepublicObjectinvoke(Object proxy,Method method,Object[] args)throwsThrowable{// 方法执行前:判断是否有@LogAspect注解if(method.isAnnotationPresent(LogAspect.class)){System.out.println("[前置日志] 方法 "+ method.getName()+" 开始执行,参数:"+ args[0]);}// 执行目标方法Object result = method.invoke(target, args);// 方法执行后if(method.isAnnotationPresent(LogAspect.class)){System.out.println("[后置日志] 方法 "+ method.getName()+" 执行完毕");}return result;}// 创建代理对象publicstatic<T>TcreateProxy(T target){return(T)Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(),newLogAspectHandler(target));}}// 测试类publicclassAnnotationAopDemo{publicstaticvoidmain(String[] args){OrderService orderService =newOrderServiceImpl();OrderService proxy =LogAspectHandler.createProxy(orderService); proxy.createOrder("ORDER_20260129");}}

输出结果

[前置日志] 方法 createOrder 开始执行,参数:ORDER_20260129 创建订单:ORDER_20260129 [后置日志] 方法 createOrder 执行完毕 

1.6.2 场景2:基于注解的ORM映射

💡 核心思想:通过注解标记实体类与数据库表的映射关系,结合反射实现自动生成SQL语句,简化数据库操作。

代码实操:注解实现ORM映射
importjava.lang.annotation.*;/** * 基于注解的ORM映射示例 */// 表映射注解@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@interfaceTable{Stringname();}// 字段映射注解@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@interfaceColumn{Stringname();Stringtype()default"VARCHAR";intlength()default255;}// 实体类@Table(name ="t_user")classUser{@Column(name ="user_id", type ="INT", length =10)privateInteger userId;@Column(name ="user_name", type ="VARCHAR", length =50)privateString userName;@Column(name ="age", type ="INT", length =3)privateInteger age;// 省略getter/setter方法publicIntegergetUserId(){return userId;}publicvoidsetUserId(Integer userId){this.userId = userId;}publicStringgetUserName(){return userName;}publicvoidsetUserName(String userName){this.userName = userName;}publicIntegergetAge(){return age;}publicvoidsetAge(Integer age){this.age = age;}}// ORM工具类:生成SQL语句classOrmUtil{publicstaticStringgenerateSelectSql(Class<?> clazz){// 获取表名Table table = clazz.getAnnotation(Table.class);if(table ==null){thrownewIllegalArgumentException("实体类未添加@Table注解");}String tableName = table.name();// 获取字段名StringBuilder columns =newStringBuilder();java.lang.reflect.Field[] fields = clazz.getDeclaredFields();for(java.lang.reflect.Field field : fields){Column column = field.getAnnotation(Column.class);if(column !=null){ columns.append(column.name()).append(",");}}// 移除最后一个逗号 columns.deleteCharAt(columns.length()-1);// 生成查询SQLreturn"SELECT "+ columns +" FROM "+ tableName;}publicstaticvoidmain(String[] args){System.out.println("生成的查询SQL:"+generateSelectSql(User.class));}}

输出结果

生成的查询SQL:SELECT user_id,user_name,age FROM t_user 

1.6.3 场景3:基于注解的单元测试

💡 核心思想:通过注解标记测试方法,测试框架自动识别并执行这些方法,实现自动化测试。这正是JUnit框架的核心实现原理。

代码实操:简化版JUnit框架
importjava.lang.annotation.*;importjava.lang.reflect.Method;/** * 简化版JUnit框架:基于注解的单元测试 */// 测试方法注解@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@interfaceTestCase{}// 测试类classMathTest{@TestCasepublicvoidtestAdd(){int result =1+2;assert result ==3:"加法测试失败";System.out.println("testAdd 测试通过");}@TestCasepublicvoidtestMultiply(){int result =2*3;assert result ==6:"乘法测试失败";System.out.println("testMultiply 测试通过");}// 非测试方法,不会被执行publicvoidnormalMethod(){System.out.println("这是普通方法,不会被测试");}}// 测试运行器classTestRunner{publicstaticvoidrun(Class<?> testClass)throwsException{Object obj = testClass.getDeclaredConstructor().newInstance();Method[] methods = testClass.getDeclaredMethods();int passCount =0;int failCount =0;for(Method method : methods){if(method.isAnnotationPresent(TestCase.class)){try{ method.invoke(obj); passCount++;}catch(Exception e){ failCount++;System.out.println(method.getName()+" 测试失败:"+ e.getCause().getMessage());}}}System.out.println("\n===== 测试结果 ======");System.out.println("总测试数:"+(passCount + failCount));System.out.println("通过数:"+ passCount);System.out.println("失败数:"+ failCount);}publicstaticvoidmain(String[] args)throwsException{TestRunner.run(MathTest.class);}}

输出结果

testAdd 测试通过 testMultiply 测试通过 ===== 测试结果 ====== 总测试数:2 通过数:2 失败数:0 

1.7 注解的优缺点与最佳实践

1.7.1 注解的优点

  1. 简化开发:减少冗余配置,提高开发效率。
  2. 增强代码可读性:元数据与代码紧密结合,一目了然。
  3. 提高代码灵活性:通过注解可以动态控制程序行为,无需修改核心代码。
  4. 框架友好:是现代Java框架的标配,便于集成主流框架。

1.7.2 注解的缺点

  1. 侵入性强:注解直接嵌入代码,修改注解需要修改源码。
  2. 可读性差:过多的注解会导致代码臃肿,影响阅读。
  3. 性能损耗:运行时注解需要通过反射解析,存在一定的性能开销。
  4. 调试困难:注解的逻辑在运行时执行,调试时难以跟踪。

1.7.3 注解的最佳实践

  1. 合理选择注解生命周期:仅在需要反射解析时使用 RUNTIME,否则使用 SOURCECLASS,减少性能损耗。
  2. 避免过度使用注解:不要用注解替代所有配置,对于经常变化的配置,建议使用外部配置文件。
  3. 做好注解文档:为自定义注解添加详细的JavaDoc注释,说明注解的作用和使用方式。
  4. 结合设计模式使用:如结合工厂模式、代理模式,实现注解的灵活解析和扩展。
  5. 优先使用成熟框架的注解:如Spring的 @Autowired@RequestMapping,避免重复造轮子。

1.8 实战案例:基于注解的权限校验框架

1.8.1 需求分析

💡 实现一个轻量级的权限校验框架,要求:

  1. 通过注解标记需要权限校验的方法。
  2. 支持指定方法所需的权限角色。
  3. 在方法执行前自动校验用户权限,无权限则抛出异常。
  4. 框架具备良好的扩展性,支持自定义权限校验逻辑。

1.8.2 代码实现

importjava.lang.annotation.*;importjava.lang.reflect.Method;importjava.util.Arrays;importjava.util.HashSet;importjava.util.Set;/** * 基于注解的权限校验框架 */// 权限校验注解@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public@interfaceRequiresPermission{// 所需权限角色String[]value();}// 用户上下文类:存储当前登录用户信息classUserContext{privatestaticThreadLocal<String> currentUser =newThreadLocal<>();privatestaticSet<String> userRoles =newHashSet<>();// 设置当前用户publicstaticvoidsetCurrentUser(String username,String... roles){ currentUser.set(username); userRoles.clear(); userRoles.addAll(Arrays.asList(roles));}// 获取当前用户角色publicstaticSet<String>getUserRoles(){return userRoles;}// 清除当前用户publicstaticvoidclear(){ currentUser.remove(); userRoles.clear();}}// 权限校验切面类classPermissionAspect{/** * 执行方法并校验权限 */publicstaticObjectinvoke(Object obj,String methodName,Object... args)throwsException{Method method = obj.getClass().getDeclaredMethod(methodName,getParameterTypes(args));// 权限校验if(method.isAnnotationPresent(RequiresPermission.class)){RequiresPermission annotation = method.getAnnotation(RequiresPermission.class);String[] requiredRoles = annotation.value();Set<String> userRoles =UserContext.getUserRoles();// 检查是否有匹配的角色boolean hasPermission =false;for(String role : requiredRoles){if(userRoles.contains(role)){ hasPermission =true;break;}}if(!hasPermission){thrownewSecurityException("无权限访问该方法,所需角色:"+Arrays.toString(requiredRoles));}}// 执行目标方法return method.invoke(obj, args);}privatestaticClass<?>[]getParameterTypes(Object... args){if(args ==null|| args.length ==0){returnnewClass[0];}Class<?>[] types =newClass[args.length];for(int i =0; i < args.length; i++){ types[i]= args[i].getClass();}return types;}}// 业务服务类classAdminService{@RequiresPermission({"ADMIN","SUPER_ADMIN"})publicStringdeleteUser(String userId){return"删除用户成功:"+ userId;}@RequiresPermission({"USER","ADMIN","SUPER_ADMIN"})publicStringqueryUser(String userId){return"查询用户信息:"+ userId;}}// 测试类publicclassPermissionFrameworkDemo{publicstaticvoidmain(String[] args)throwsException{AdminService adminService =newAdminService();// 测试1:管理员用户,拥有ADMIN角色UserContext.setCurrentUser("admin","ADMIN");System.out.println(PermissionAspect.invoke(adminService,"deleteUser","1001"));System.out.println(PermissionAspect.invoke(adminService,"queryUser","1001"));// 测试2:普通用户,只有USER角色UserContext.setCurrentUser("user","USER");System.out.println(PermissionAspect.invoke(adminService,"queryUser","1001"));try{PermissionAspect.invoke(adminService,"deleteUser","1001");}catch(Exception e){System.out.println(e.getCause().getMessage());}UserContext.clear();}}

输出结果

删除用户成功:1001 查询用户信息:1001 查询用户信息:1001 无权限访问该方法,所需角色:[ADMIN, SUPER_ADMIN] 

1.8.3 案例总结

✅ 这个权限校验框架综合运用了注解定义、反射解析、线程本地存储等技术,核心亮点如下:

  1. 使用 @RequiresPermission 注解标记需要权限校验的方法,配置简单。
  2. 通过 UserContext 存储当前用户角色,支持多线程环境。
  3. 利用反射解析注解,在方法执行前自动校验权限,无侵入性。
  4. 框架扩展性强,可通过修改 PermissionAspect 类实现自定义权限校验逻辑。

1.9 本章总结

  1. 注解是Java的一种元数据标记,本身不执行逻辑,需要通过解析器(反射、APT)处理后才能发挥作用。
  2. JDK内置注解用于代码检查,元注解用于约束自定义注解,自定义注解是业务开发的核心。
  3. 自定义注解的开发流程是 定义 → 使用 → 解析,反射是最常用的运行时解析方式。
  4. 注解是框架开发的基石,广泛应用于AOP、ORM、权限校验、单元测试等场景。
  5. 注解的优点是简化配置、增强可读性,缺点是侵入性强、有性能损耗,使用时需平衡利弊。
  6. 注解的最佳实践是“合理选择生命周期、避免过度使用、做好文档注释”,结合设计模式提升扩展性。

Read more

GitHub Copilot 三种模式详解:Ask、Agent、Edit

🌟 前言 GitHub Copilot作为AI编程助手的先驱,为开发者提供了三种不同的交互模式,每种模式都有其独特的优势和适用场景。本文将深入解析这三种模式的特点、使用场景以及如何选择合适的模式来提升开发效率。 📋 目录 * Ask模式:智能问答助手 * Agent模式:自主执行代理 * Edit模式:精准代码编辑 * 三种模式对比分析 * 实际应用场景 * 选择建议 * 总结 🤖 Ask模式:智能问答助手 核心特点 Ask模式是最基础的交互方式,它将GitHub Copilot变成了一个专业的编程顾问。这种模式专注于知识传递和问题解答。 * 🎯 主要功能: * 回答编程概念和技术问题 * 提供代码示例和最佳实践 * 解释复杂的技术概念 * 调试建议和错误分析 * 💡 交互特点: * 对话式交互界面 * 即时问答反馈 * 支持连续深入提问 * 不直接修改项目文件 典型使用场景 👨‍💻 开发者:什么是React的useEffect钩子? 🤖 Copilot:useEffect是Reac

By Ne0inhk
大模型+智能家居解决方案--小米MiLoco部署

大模型+智能家居解决方案--小米MiLoco部署

一、Miloco简介 小米推出了首个“大模型+智能家居”解决方案Xiaomi Miloco,全称为 Xiaomi Local Copilot(小米本地协同智能助手)。 https://gitee.com/xiaomi-miloco/xiaomi-miloco 1、GitHub地址 https://github.com/XiaoMi/xiaomi-miloco Miloco以米家摄像头为视觉信息源,以自研大语言模型MiMo-VL-Miloco-7B为核心,连接家中所有物联网(IoT)设备,框架面向所有人开源。MiMo-VL-Miloco-7B模型基于小米4月发布的MiMo模型调优而来,“天才少女”罗福莉最近加入的正是MiMo模型团队。 这很可能是智能家居的“ChatGPT时刻”,小米AIoT平台截至今年6月已连接的IoT设备数(不含智能手机、平板及笔记本计算机)达9.89亿台,数以亿计的米家摄像头、小爱音箱、台灯等设备都有望用上大模型。 从小米公布的Miloco页面来看,页面主视觉是一个类似于ChatGPT的聊天框,聊天框的左侧具有智能家居设备的导航栏,包括AI中心、模型管

By Ne0inhk
椭偏仪在AR光学薄膜制备中的应用:高折射率与膜厚测量

椭偏仪在AR光学薄膜制备中的应用:高折射率与膜厚测量

随着增强现实(AR)技术在消费电子、医疗及工业等领域的快速发展,市场对高性能光学元件的需求日益迫切。高折射率光学组件是实现设备轻薄化、扩大视场、提升沉浸感的关键。金属氧化物虽具有高折射率、高透过率和良好的稳定性,是理想材料,但其传统制造方法——如气相沉积工艺复杂、成本高昂,溶胶-凝胶法则需高温处理,易导致基板不匹配、表面缺陷等问题,严重制约了AR光学元件的规模化与低成本制造。Flexfilm全光谱椭偏仪可以非接触对薄膜的厚度与折射率的高精度表征,广泛应用于薄膜材料、半导体和表面科学等领域。 为突破这一瓶颈,研究团队研发了基于UV固化的金属氧化物前驱体技术。该技术通过精心设计的配方,可在低温(低至100°C)下形成无机涂层,其折射率可在1.30至2.35范围内精确调控。所得涂层具备原子级光滑表面、低光学损耗及优异的环境稳定性,不仅兼容多种基材与集成工艺,更为实现AR光学元件的高性能、低成本与规模化生产提供了切实可行的创新解决方案。 实验方法 通过系统调节前驱体组成、浓度、溶剂及反应条件,实现对薄膜折射率的精确控制。采用实验设计方法优化配方,确保薄膜高透明、低雾度。材料为无纳米颗粒体

By Ne0inhk

机器人、机械臂能听话,全靠这门被低估的神技:逆动力学

🧱 逆动力学核心概念与本质 逆动力学是已知机器人末端执行器的运动轨迹,求解各关节所需驱动力矩的过程,是机器人运动控制的关键技术之一。其技术本质是在复杂多体系统中解决"运动输入-动力学建模-力矩输出"的映射问题,为机器人的精准运动控制提供理论基础。 🔍 逆动力学核心算法原理 🔹 牛顿-欧拉法(Newton-Euler) * 核心思想:递归计算每个连杆的动力学信息,从末端执行器回溯到基座(正递归),再从基座计算到末端执行器(逆递归) * 优势:计算效率高,适合实时控制场景 * 适用场景:工业机器人、机械臂等多自由度运动系统 * 关键公式: * 正递归:计算各连杆的速度、加速度和惯性力 * 逆递归:计算各关节的驱动力矩 🔹 拉格朗日法(Lagrange) * 核心思想:基于能量守恒原理,建立系统的拉格朗日函数,通过对时间求导得到运动方程 * 优势:物理意义清晰,便于分析系统特性 * 适用场景:机器人动力学建模、轨迹规划等离线计算场景 * 关键公式:τ=M(q)q¨+C(q,

By Ne0inhk