一、预备知识的简单介绍:
(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!同样的,按照这种思路,我们可以做很多事,比如自定义缓存注解,自定义记录日志注解等等。

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

611

被折叠的 条评论
为什么被折叠?



