利用Spring的Aop机制、自定义注解和反射实现代码功能增强

本文介绍了如何结合Spring的AOP机制、自定义注解和反射来实现代码功能增强。首先,阐述了AOP的概念及其在业务流程中的作用,然后讲解了注解作为元数据在代码中的应用。接着,讨论了Java反射的原理和常用API,虽然反射增加了程序的灵活性,但可能导致性能下降和代码可读性的降低。随后,通过一个具体的demo演示了如何定义自定义注解、创建切面,并在controller和service中应用,以展示代码增强的实际效果。最后,提出这种实现方式可用于创建自定义缓存或日志记录等更多功能。

一、预备知识的简单介绍:

(1)AOP:它是Spring为我们提供的一个十分有用的机制,AOP采用称为“横切”的技术,把一些与业务代码不是强相关的功能独立出来,从而形成一个“切面”,并且我们把这个“切面”切到业务流程的某个位置,以实现业务增强。
(2)注解:它是一种能被添加到java代码中的元数据,类、方法、变量、参数和包都可以用注解来修饰。注解对于它所修饰的代码并没有直接的影响。通俗来说,注解就是一个标签,我们可以用@interface来写一个自定义的注解。
(3)反射:在运行状态中,对应任意一个类,都能知道这个类的所有属性和方法;对于任意一个对象,都能调用它任意的方法和属性。这种动态获取的信息及动态调用对象方法的功能成为JAVA语言的反射。反射可以是程序更加灵活,但是同时会对性能造成一定的影响,降低代码的可读性。以下是反射常用的API:

方法名返回值参数描述
Class.forName(String)类的元信息当前类的具体位置
类.getClass()类的元信息
getDeclareds()当前类所有属性
setAccessible(true)设置当前属性(private)可见true或false
getMethods()当前类所有方法
invoke(obj)通过反射执行方法类的元信息
getAnnotation(class)获取注解需获取注解的class

二、具体实现:

这里我写了一个小的demo来实现所谓的代码功能增强。首先我们先定义一个自定义注解,代码如下:

@Retention(RetentionPolicy.RUNTIME)//表示注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
@Target(ElementType.METHOD)//表示此注解是写在方法上的,写在其他地方会报错
public @interface MyAnnotation {
    String param() default "默认值";//不传就写默认值
}

接着,我们写一个切面,代码如下:

@Aspect
@Component
public class TestAspect {
    /**
     * 表示加了@MyAnnotation注解的方法都会来这里先执行
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("@annotation(annotion.test.anno.MyAnnotation)")
    public Object testMyAnnotation(ProceedingJoinPoint pjp) throws Throwable {
        //=============前置处理=============

        //=============正在打了这个注解的方法的处理=============
        Object result = pjp.proceed();//这里是被切的方法真正执行的地方
        //=============后置处理=============
        //拿到方法返回的结果
        String res = (String) result;
        //拿到方法的入参
        Object[] objs = pjp.getArgs();
        //拿到被切的方法的类对象
        Class<?> clazz = pjp.getTarget().getClass();
        //拿到被切的方法的类对象中指定的方法
        Method method = clazz.getMethod("getBehavior",String.class);
        //通过反射去拿到方法上的注解
        MyAnnotation myAnnotation  = method.getAnnotation(MyAnnotation.class);
        //把结果处理一下并返回
        return objs[0]+res + myAnnotation.param();
    }
}

最后,我们写一个controller和service来测试一下结果,代码如下:
(1)service代码:

@Service
public class UserService {
    //这个注解的参数可以随意定义
    @MyAnnotation(param = "洗浴中心!")
    public String getBehavior(String userName) {
        //userName这里没有用到,被切面代码的反射拿到了
        //这个Behavior,行为类是我自己定义的哦
        Behavior behavior = new Behavior();
        //模拟设置行为
        behavior.setBehaviorBame("走向了");
        return behavior.getBehaviorBame();
    }
}

(2)controller代码:

@Controller
@RequestMapping("/behavior")
public class TestController {
    @Autowired
    private UserService userService;
    
    @RequestMapping("/test")
    public String test() {
        System.out.println(userService.getBehavior("张三"));
        return "成功!";
    }
}

以下是结果:
在这里插入图片描述
至此,我们就完成一个代码增强的小demo!同样的,按照这种思路,我们可以做很多事,比如自定义缓存注解,自定义记录日志注解等等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值