在Spring框架的
@Autowired依赖注入、Hibernate的ORM映射、JUnit的测试用例管理场景中,注解与反射技术已成为Java生态的核心基础设施。通过自定义注解结合反射机制,开发者能够实现动态权限校验、日志追踪、参数校验等复杂业务逻辑。本文将以权限控制系统为例,完整演示从注解定义到反射解析的全流程实现。
使用
@interface关键字定义注解时,需通过元注解控制其行为。以下是一个权限校验注解的完整定义:
java1import java.lang.annotation.*;23@<"www.anshan.gov.cn.qmwty.cn"><"www.nanchong.gov.cn.qmwty.cn">Target(ElementType.METHOD) // 限定注解作用于方法4@Retention(RetentionPolicy.RUNTIME) // 运行时通过反射获取5@Documented // 包含在Javadoc中6public @interface RequiresPermission {7 String[] value() default {}; // 权限标识数组8 boolean required() default true; // 是否强制校验9}
ElementType枚举指定注解应用范围,包括
TYPE(类)、
FIELD(字段)、
PARAMETER(参数)等10种类型。例如
@Target({METHOD, CONSTRUCTOR})表示注解可同时用于方法和构造器。RetentionPolicy.SOURCE<"www.fushun.gov.cn.qmwty.cn">仅在源码阶段保留(如Lombok的
@Getter),
CLASS保留至编译后(默认值),
RUNTIME<"www.benxi.gov.cn.qmwty.cn">允许运行时反射访问(Spring的
@Controller)。通过反射API获取方法上的
@RequiresPermission注解并解析其属性:
java1import java.lang.reflect.Method;23public class PermissionChecker {4 <"www.fuxin.gov.cn.qmwty.cn"><"www.wenzhou.gov.cn.qmwty.cn"><"www.dandong.gov.cn.qmwty.cn"> public static void check(Object target, String methodName) throws Exception {5 // 1. 获取目标类的Class对象6 Class<?> clazz = target.getClass();7 8 // 2. 获取指定方法对象(含参数类型匹配)9 Method method = clazz.getMethod(methodName);10 11 // 3. 判断方法是否包含目标注解12 if (method.isAnnotationPresent(RequiresPermission.class)) {13 // 4. 获取注解实例14 RequiresPermission permission = method.getAnnotation(RequiresPermission.class);15 16 // 5. 解析注解属性17 String[] requiredRoles = permission.value();18 boolean isRequired = permission.required();19 20 // 6. 执行权限校验逻辑(示例)21 if (isRequired && !currentUserHasRoles(requiredRoles)) {22 throw new SecurityException("权限不足");23 }24 }25 }26 27 private static boolean currentUserHasRoles(String[] roles) {28 // 实际项目中需集成Spring Security等权限框架29 return true; 30 }31}
Method对象缓存至
ConcurrentHashMap,避免重复反射调用。clazz.getDeclaredMethods()获取所有方法后批量检查注解。Proxy.newProxyInstance<"www.liaoyang.gov.cn.qmwty.cn">)实现AOP拦截,减少反射调用次数。假设系统存在以下权限需求:
deleteUser操作(需
ADMIN权限)updateProfile<"www.guiyang.gov.cn.qmwty.cn">操作(需
USER权限)java1public class UserService {2 @RequiresPermission({"ADMIN"})3 public void deleteUser(Long userId) {4 System.out.println("删除用户: " + userId);5 }6 7 @RequiresPermission({"USER"})8 public void updateProfile(String newName) {9 System.out.println("更新用户名为: " + newName);10 }11}
java1public class Main {2 public static void main(String[] args) throws Exception {3 <"www.lanzhou.gov.cn.qmwty.cn"><"www.haikou.gov.cn.qmwty.cn"> <"www.nanchang.gov.cn.qmwty.cn"> UserService service = new UserService();4 5 // 模拟管理员调用6 try {7 PermissionChecker.check(service, "deleteUser");8 service.deleteUser(1001L);9 } catch (SecurityException e) {10 System.err.println("管理员操作失败: " + e.getMessage());11 }12 13 // 模拟普通用户调用14 try {15 PermissionChecker.check(service, "updateProfile");16 service.updateProfile("张三");17 } catch (SecurityException e) {18 System.err.println("普通用户操作失败: " + e.getMessage());19 }20 }21}
@Repeatable注解实现同一方法的多次权限标注。defaultRole属性,未显式标注时使用默认值。PermissionDeniedException<"www.shaoxing.gov.cn.qmwty.cn">并集成全局异常处理器。通过
@Around切面拦截所有标注
@RequiresPermission<"www.jiaxing.gov.cn.qmwty.cn">的方法:
java1@Aspect2@Component3public class PermissionAspect {4 @Around("@annotation(permission)")5 public Object checkPermission(ProceedingJoinPoint joinPoint, RequiresPermission permission) throws Throwable {6 String[] requiredRoles = permission.value();7 if (!currentUserHasRoles(requiredRoles)) {8 throw new PermissionDeniedException("无权访问");9 }10 return joinPoint.proceed();11 }12}
通过反射修改注解属性值(需注意JVM限制):
java1public class AnnotationModifier {2 <"www.tonghua.gov.cn.qmwty.cn"><"www.songyuan.gov.cn.qmwty.cn"> <"www.baishan.gov.cn.qmwty.cn"> public static void modifyAnnotation(Method method, String newValue) {3 try {4 // 获取注解代理实例5 RequiresPermission annotation = method.getAnnotation(RequiresPermission.class);6 7 // 通过反射修改底层Map(JDK内部实现,不推荐生产环境使用)8 InvocationHandler handler = Proxy.getInvocationHandler(annotation);9 Field memberValuesField = handler.getClass().getDeclaredField("memberValues");10 memberValuesField.setAccessible(true);11 Map<String, Object> memberValues = (Map<String, Object>) memberValuesField.get(handler);12 memberValues.put("value", new String[]{newValue});13 } catch (Exception e) {14 throw new RuntimeException("修改注解失败", e);15 }16 }17}
自定义注解与反射的结合为Java程序提供了强大的元编程能力,但需注意以下原则:
SecurityManager限制反射对敏感类的访问。在Spring Security、Quarkus等现代框架中,注解与反射已成为实现声明式编程的核心手段。掌握这一技术组合,开发者能够构建出更灵活、可扩展的企业级应用。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/19545/viewspace-3100802/ ,如需转载,请注明出处,否则将追究法律责任。