spring自定义注解
参考: https://blog.csdn.net/qq_37435078/article/details/90523309
简单查询
以Springboot
为例子, 做一个简单的MVC查询
controller层
:
package com.example.demo1.controller;
import com.example.demo1.annotation.Log;
import com.example.demo1.entity.User;
import com.example.demo1.sevice.UserService;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@RequestMapping("user/{id}")
public User findUser(@PathVariable("id") Integer id) {
return userService.findUserById(id);
}
}
Dao层
:
package com.example.demo1.dao;
import com.example.demo1.entity.User;
import org.springframework.stereotype.Component;
@Component
public class UserDao {
public User findUserById(Integer id) {
System.out.println("查询id为[" + id + "]的用户");
if(id > 10) {
return null;
}
User user = new User(id, "user-" + id);
System.out.println("返回的用户为[" + user.toString() + "]");
return user;
}
}
实体类:
package com.example.demo1.entity;
public class User {
private Integer id;
private String name;
public User() {
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public User(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Service层
package com.example.demo1.sevice;
import com.example.demo1.dao.UserDao;
import com.example.demo1.entity.User;
import org.springframework.stereotype.Service;
@Service
public class UserService {
private final UserDao userDao;
public UserService(UserDao userDao) {
this.userDao = userDao;
}
public User findUserById(Integer id) {
return userDao.findUserById(id);
}
}
直接访问 localhost:8080/user/6
得到
{
"id": 6,
"name": "user-6"
}
添加日志注释&修改参数和返回值
新建Log
注解
package com.example.demo1.annotation;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Log {
String value() default "";
}
这里注解类上的三个注解称为元注解,其分别代表的含义如下:
@Documented:注解信息会被添加到Java文档中
@Retention:注解的生命周期,表示注解会被保留到什么阶段,可以选择编译阶段、类加载阶段,或运行阶段
@Target:注解作用的位置,ElementType.METHOD表示该注解仅能作用于方法上
在对外接口上添加Log
注解
package com.example.demo1.controller;
import com.example.demo1.annotation.Log;
import com.example.demo1.entity.User;
import com.example.demo1.sevice.UserService;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@Log("日志测试")
@RequestMapping("user/{id}")
public User findUser(@PathVariable("id") Integer id) {
return userService.findUserById(id);
}
}
利用Spring AOP的切面类来处理具体的逻辑, 新建LogAspect
切面类
处理参数:
- 传入的id传给后端 id -1
- 返回给前端的VO.id + 1
package com.example.demo1.annotation;
import com.example.demo1.entity.User;
import org.aspectj.lang.JoinPoint;
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.springframework.stereotype.Component;
import javax.jws.soap.SOAPBinding;
@Component
@Aspect
public class LogAspect {
@Pointcut("@annotation(com.example.demo1.annotation.Log)")
private void pointcut(){}
@Around("pointcut() && @annotation(log)")
public Object advice(ProceedingJoinPoint joinPoint, Log log) {
System.out.println("["
+ joinPoint.getSignature().getDeclaringType().getSimpleName()
+ "][" + joinPoint.getSignature().getName()
+ "]-日志内容-[" + log.value() + "]");
Object result = null;
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
if(args[i] instanceof Integer) {
args[i] = (Integer)args[i] - 1;
break;
}
}
try{
result = joinPoint.proceed(args);
}catch (Throwable throwable) {
throwable.printStackTrace();
}
if(result instanceof User) {
User user = (User) result;
user.setId(user.getId() + 1);
return user;
}
return result;
}
}
其中@Pointcut
声明了切点(这里的切点是我们自定义的注解类)
@Before("pointcut() && @annotation(logger)") public void advice(KthLog logger) { System.out.println("--- Kth日志的内容为[" + logger.value() + "] ---"); }
如果用@Before注解,则进入实际方法前,执行
adivice
方法
@Around
注解:
@Around的作用
既可以在目标方法之前织入增强动作,也可以在执行目标方法之后织入增强动作;
可以决定目标方法在什么时候执行,如何执行,甚至可以完全阻止目标目标方法的执行;
可以改变执行目标方法的参数值,也可以改变执行目标方法之后的返回值; 当需要改变目标方法的返回值时,只能使用Around方法;
虽然Around功能强大,但通常需要在线程安全的环境下使用。因此,如果使用普通的Before、AfterReturing增强方法就可以解决的事情,就没有必要使用Around增强处理了。
————————————————
版权声明:本文为CSDN博主「咚咚大帝」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_41981107/article/details/85260765
joinPoint.getArgs()
用来获取加注解的方法的入参,获得入参之后,进行处理
result = joinPoint.proceed(args);
传入修改后的args
, 通过调用proceed()
方法,执行了实际的操作,并获取到了返回值
再对返回的result
进行处理,
测试: http://localhost:8080/user/6
打印台为: 可以看到 id -1
[UserController][findUser]-日志内容-[日志测试]
查询id为[5]的用户
返回的用户为[User{id=5, name='user-5'}]
返回给前台的页面为: 可以看到id不变, user - 1
{"id":6,"name":"user-5"}
这样就做出了对业务逻辑的增强
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 mym_74@163.com