предисловие
В последнее время появилось новое требование, заключающееся в том, чтобы отслеживать некоторые операции пользователей и записывать записи операций в базу данных.Прежде всего, я подумал об использовании фильтров Filter и Spring's Interceptor (перехватчик), оба из которых требуют сложной настройки (может use Проблема, решаемая кодом, никогда не используется), поэтому у меня возникла идея реализовать АОП на основе аннотаций и добавить аннотацию к отслеживаемому действию, отлично, приступим!
Создание пользовательских аннотаций
package com.asiainfo.annotation;
import java.lang.annotation.*;
/**
* @description: 自动以注解
* @author: Mr-box
* @create: 2019-05-23 10:00
**/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface EagleEye {
String desc() default "";
}
- Определите жизненный цикл аннотации как время выполнения
- Определите роль аннотаций для методов
- Аннотации маркеров можно документировать с помощью JavaDoc.
- Определите аннотацию как EagleEye
- Определите desc, чтобы описать модифицированный метод
Определение аспектов AOP
package com.asiainfo.aspect;
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 org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
/**
* @description: 定义AOP切面
* @author: Mr-box
* @create: 2019-05-23 10:00
**/
@Aspect
@Component
public class LogAspect {
// 定义切点
@Pointcut("@annotation(com.asiainfo.annotation.EagleEye)")
public void eagleEye() {
}
// 利用环绕增强来实现我们的功能
@Around("eagleEye()")
public Object surroundInform(ProceedingJoinPoint proceedingJoinPoint) {
System.out.println("环绕通知开始...");
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
System.out.println("请求路径 : " + request.getRequestURL());
System.out.println("请求方式 : " + request.getMethod());
System.out.println("方法名 : " + proceedingJoinPoint.getSignature().getName());
System.out.println("类路径 : " + proceedingJoinPoint.getSignature().getDeclaringTypeName());
System.out.println("参数 : " + Arrays.toString(proceedingJoinPoint.getArgs()));
try {
// 真实业务代码,这里是伪代码
Object o = proceedingJoinPoint.proceed();
System.out.println("方法环绕proceed,结果是 :" + o);
return o;
} catch (Throwable e) {
e.printStackTrace();
return null;
}
}
}
Использование аннотаций
- Добавьте аннотацию @EagleEye(desc = "test interface") к методу для достижения этой цели.
package com.asiainfo.action;
import com.asiainfo.annotation.EagleEye;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @description: 定义AOP切面
* @author: Mr-box
* @create: 2019-05-23 10:00
**/
@RestController
public class TestAction {
@EagleEye(desc = "测试接口")
@RequestMapping(value = "/sayHello")
public String test(String params)throws Exception{
System.out.println("参数:" + params);
return "hello "+ params;
}
}
начать тест
Вызов браузера:http://127.0.0.1:8081/aop-demo/sayHello?params=lalaОбратите внимание на вывод журнала:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.5.RELEASE)
2019-05-23 10:00 INFO 3183 --- [ main] com.asiainfo.SpringAopDemoApplication : Starting SpringAopDemoApplication on zhangdsdeiMac.local with PID 3183 (/Users/zhangds/Development/code/spring-aop-demo/target/classes started by zhangds in /Users/zhangds/Development/code/spring-aop-demo)
2019-05-23 10:00 INFO 3183 --- [ main] com.asiainfo.SpringAopDemoApplication : No active profile set, falling back to default profiles: default
2019-05-23 10:00 INFO 3183 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8081 (http)
2019-05-23 10:00 INFO 3183 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2019-05-23 10:00 INFO 3183 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.31]
2019-05-23 10:00 INFO 3183 --- [ main] o.a.c.c.C.[.[localhost].[/aop-demo] : Initializing Spring embedded WebApplicationContext
2019-05-23 10:00 INFO 3183 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 627 ms
2019-05-23 10:00 INFO 3183 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-05-23 10:00 INFO 3183 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8081 (http) with context path '/aop-demo'
2019-05-23 10:00 INFO 3183 --- [ main] com.asiainfo.SpringAopDemoApplication : Started SpringAopDemoApplication in 1.115 seconds (JVM running for 1.654)
2019-05-23 10:00 INFO 3183 --- [nio-8081-exec-1] o.a.c.c.C.[.[localhost].[/aop-demo] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2019-05-23 10:00 INFO 3183 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2019-05-23 10:00 INFO 3183 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 4 ms
请求路径 : http://127.0.0.1:8081/aop-demo/sayHello
请求方式 : GET
方法名 : test
类路径 : com.asiainfo.action.TestAction
参数 : [lala]
环绕通知开始...
参数:lala
方法环绕proceed,结果是 :hello lala
Суммировать
- Это более гибко, чем использование выражений выполнения для настройки pointcut, а выражения выполнения имеют определенные ограничения.
- Пользовательские аннотации более гибкие, но это лишь небольшая часть использования пользовательских аннотаций.