目录
- 面试题:
- 1、你肯定知道spring,那说说aop的全部通知顺序?
-
- 2.springboot或springboot2对aop的执行顺序影响?
-
- 3.说说你使用aop中碰到的坑?
Aop的常用注解:
@Before:前置通知:目标方法之前执行
@After:后置通知:目标方法之后执行(始终执行)
@AfterReturning:返回后通知:执行方法结束前执行(异常不执行)
@AfterThrowing:异常通知:出现异常时执行
@Around:环绕通知:环绕目标方法执行
创建springboot项目
pom--->切换springboot版本:Spring4+springboot1.5.9/Spring5+springboot2.3.3
- "1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0modelVersion>
-
- <groupId>com.lwzgroupId>
- <artifactId>springboot_aopartifactId>
- <version>1.0-SNAPSHOTversion>
-
- <parent>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-parentartifactId>
- <version>1.5.9.RELEASEversion>
-
- parent>
-
- <properties>
- <java.version>1.8java.version>
- properties>
-
- <dependencies>
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starterartifactId>
- dependency>
- <dependency>
- <groupId>org.aspectjgroupId>
- <artifactId>aspectjweaverartifactId>
- dependency>
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-testartifactId>
- <scope>testscope>
- dependency>
- dependencies>
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-maven-pluginartifactId>
- plugin>
- plugins>
- build>
- project>
切面编程,切面类
- package com.lwz.aop;
-
- import org.aspectj.lang.ProceedingJoinPoint;
- import org.aspectj.lang.annotation.After;
- import org.aspectj.lang.annotation.AfterReturning;
- import org.aspectj.lang.annotation.AfterThrowing;
- import org.aspectj.lang.annotation.Around;
- import org.aspectj.lang.annotation.Aspect;
- import org.aspectj.lang.annotation.Before;
- import org.springframework.stereotype.Component;
-
- @Aspect
- @Component
- public class MyAspect {
-
- @Before("execution(public int com.lwz.service.impl.CalcServiceImpl.*(..))")
- public void beforeNotify() {
- System.out.println("******@Before我是前置通知");
- }
-
- @After("execution(public int com.lwz.service.impl.CalcServiceImpl.*(..))")
- public void afterNotify() {
- System.out.println("******@@After我是后置通知");
- }
-
- @AfterReturning("execution(public int com.lwz.service.impl.CalcServiceImpl.*(..))")
- public void afterReturningNotify() {
- System.out.println("******@AfterReturning我是返回后通知");
- }
-
- @AfterThrowing("execution(public int com.lwz.service.impl.CalcServiceImpl.*(..))")
- public void afterThrowingNotify() {
- System.out.println("******@AfterThrowing我是异常通知");
- }
-
- @Around("execution(public int com.lwz.service.impl.CalcServiceImpl.*(..))")
- public Object aroundNotify(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
- Object retValueObject = null;
- System.out.println("我是环绕通知之前AAA");
- retValueObject = proceedingJoinPoint.proceed();
- System.out.println("我是环绕通知之后BBB");
- return retValueObject;
- }
- }
业务类
- package com.lwz.service;
-
- public interface CalcService {
- public int div(int x, int y);
- }
实现类
- package com.lwz.service.impl;
-
- import org.springframework.stereotype.Service;
-
- import com.lwz.service.CalcService;
-
- @Service
- public class CalcServiceImpl implements CalcService {
-
- @Override
- public int div(int x, int y) {
- int result = x / y;
- System.out.println(" ======>CalcServiceImpl被调用了,计算结果:" + result);
- return result;
- }
-
- }
测试类
- package com.lwz;
-
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.boot.SpringBootVersion;
- import org.springframework.boot.test.context.SpringBootTest;
- import org.springframework.core.SpringVersion;
- import org.springframework.test.context.junit4.SpringRunner;
-
- import com.lwz.service.CalcService;
-
- @SpringBootTest
- @RunWith(SpringRunner.class)
- public class AopTest {
-
- @Autowired
- private CalcService calcService;
-
- @Test
- public void testAop() {
- System.out.println(
- "spring版本:" + SpringVersion.getVersion() + "\t SpringBoot版本:" + SpringBootVersion.getVersion());
- calcService.div(5, 3);
- // calcService.div(5, 0);
- }
- }
pom--->切换springboot版本:Spring4+springboot1.5.9/Spring5+springboot2.3.3正常系和异常系进行测试
Spring4运行结果:
- 正常系运行结果:
- . ____ _ __ _ _
- /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
- ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
- \\/ ___)| |_)| | | | | || (_| | ) ) ) )
- ' |____| .__|_| |_|_| |_\__, | / / / /
- =========|_|==============|___/=/_/_/_/
- :: Spring Boot :: (v1.5.9.RELEASE)
- spring版本:4.3.13.RELEASE SpringBoot版本:1.5.9.RELEASE
- 我是环绕通知之前AAA
- ******@Before我是前置通知
- ======>CalcServiceImpl被调用了,计算结果:1
- 我是环绕通知之后BBB
- ******@@After我是后置通知
- ******@AfterReturning我是返回后通知
- 异常系运行结果:
- . ____ _ __ _ _
- /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
- ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
- \\/ ___)| |_)| | | | | || (_| | ) ) ) )
- ' |____| .__|_| |_|_| |_\__, | / / / /
- =========|_|==============|___/=/_/_/_/
- :: Spring Boot :: (v1.5.9.RELEASE)
-
- spring版本:4.3.13.RELEASE SpringBoot版本:1.5.9.RELEASE
- 我是环绕通知之前AAA
- ******@Before我是前置通知
- ******@@After我是后置通知
- ******@AfterThrowing我是异常通知
-
- java.lang.ArithmeticException: / by zero
spring4 aop正常顺序:@Before-->@After-->@AfterReturning
spring4 aop异常顺序:@Before-->@After-->@AfterThrowing
- 相当于:
- try {
- //@Before
- //method.invoke(args);
- //@AfterReturning
- } catch (Exception e) {
- //@AfterThrowing
- }finally {
- //@After
- }
Spring5运行结果:
- 正常系运行结果:
- . ____ _ __ _ _
- /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
- ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
- \\/ ___)| |_)| | | | | || (_| | ) ) ) )
- ' |____| .__|_| |_|_| |_\__, | / / / /
- =========|_|==============|___/=/_/_/_/
- :: Spring Boot :: (v2.3.3.RELEASE)
- spring版本:5.2.8.RELEASE SpringBoot版本:2.3.3.RELEASE
- 我是环绕通知之前AAA
- ******@Before我是前置通知
- ======>CalcServiceImpl被调用了,计算结果:1
- ******@AfterReturning我是返回后通知
- ******@@After我是后置通知
- 我是环绕通知之后BBB
- 异常系运行结果:
- . ____ _ __ _ _
- /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
- ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
- \\/ ___)| |_)| | | | | || (_| | ) ) ) )
- ' |____| .__|_| |_|_| |_\__, | / / / /
- =========|_|==============|___/=/_/_/_/
- :: Spring Boot :: (v2.3.3.RELEASE)
-
- spring版本:5.2.8.RELEASE SpringBoot版本:2.3.3.RELEASE
- 我是环绕通知之前AAA
- ******@Before我是前置通知
- ******@AfterThrowing我是异常通知
- ******@@After我是后置通知
-
- java.lang.ArithmeticException: / by zero
spring5 aop正常顺序:@Before-->@AfterReturning-->@After
spring5 aop异常顺序:@Before-->@AfterThrowing-->@After
系统运行一段时间,发现系统运行比较慢,想知道是哪些方法执行时间比较慢?或者为了性能调优?
每个方法的开头和结尾加代码处理记录打印时间,代码就会显得过于冗余,我们使用SpringAOP使用注解的方式来解决。
创建SpringBoot项目
pom
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-webartifactId>
- dependency>
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-aopartifactId>
- dependency>
定义注解
- package com.lwz.study.aop;
-
- import java.lang.annotation.*;
-
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface ExecTime {
- //描述
- String desc() default "";
- }
定义切面类
- package com.lwz.study.aop;
-
- import lombok.extern.slf4j.Slf4j;
- import org.aspectj.lang.ProceedingJoinPoint;
- import org.aspectj.lang.Signature;
- import org.aspectj.lang.annotation.Around;
- import org.aspectj.lang.annotation.Aspect;
- import org.aspectj.lang.annotation.Pointcut;
- import org.aspectj.lang.reflect.MethodSignature;
- import org.springframework.stereotype.Component;
-
- import java.lang.annotation.Annotation;
- import java.lang.reflect.Method;
-
- @Slf4j
- @Aspect
- @Component
- public class ExecTimeAspect {
-
- //切点
- @Pointcut("@annotation(com.lwz.study.aop.ExecTime)")
- private void execTimeAspect(){}
-
- @Around("execTimeAspect()")
- public
T around(ProceedingJoinPoint pjp) throws Throwable { - Long startTime = System.currentTimeMillis();
- Object[] args = pjp.getArgs();
- T result;
- Method methodClass;
- try {
- result = (T)pjp.proceed(args);//执行方法
- }finally {
- long endTime = System.currentTimeMillis();
- Signature signature = pjp.getSignature();
- String methodName = signature.getName();
- Class> targetClass = pjp.getTarget().getClass();
- Class[] parameterTypes = ((MethodSignature) pjp.getSignature()).getParameterTypes();
- methodClass = targetClass.getMethod(methodName, parameterTypes);
- Annotation[] annotations = methodClass.getAnnotations();
- for (Annotation annotation : annotations){
- Class extends Annotation> aClass = annotation.annotationType();
- String simpleName = aClass.getSimpleName();
- if("ExecTime".equals(simpleName)){
- ExecTime timeConsume = (ExecTime) annotation;
- String desc = timeConsume.desc();
- log.info(desc+"[{}] 执行耗时:{}ms",methodName,endTime-startTime);
- break;
- }
- }
- }
- return result;
- }
- }
controller
- @RestController
- @RequestMapping("/")
- public class LogController {
-
- @Autowired
- private LogService logService;
-
- @RequestMapping("/test")
- public Map
test(HttpServletRequest request){ - Map
map = new HashMap<>(); - logService.initData("数据信息");
- return map;
- }
-
- }
service
- public interface LogService {
- void initData(String data);
- }
serviceImpl
- @Service
- public class LogServiceImpl implements LogService {
-
- @ExecTime(desc = "LogServiceImpl")
- @Override
- public void initData(String data) {
- System.out.println("data"+data);
- }
-
- }
测试结果打印出信息:
.....LogServiceImpl[initData] 执行耗时:18ms
其他同上面项目
- package com.lwz.study.aop;
-
- import java.lang.annotation.*;
-
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface LogInfo {
-
- //描述
- String desc() default "";
-
- }
- package com.lwz.study.aop;
-
- 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;
-
- @Aspect
- @Component
- public class LogAspect {
-
- //切点
- // @Pointcut("execution(* com.*.controller..*.*(..))")
- @Pointcut("@annotation(com.lwz.study.aop.LogInfo)")
- private void logAspect(){}
-
- @Around("logAspect()")
- public Object log(ProceedingJoinPoint pjp) throws Throwable {
-
- System.out.println("Log....Start");
- //运行目标方法
- Object object = pjp.proceed();
-
- System.out.println("Log....End");
- //最后返回目标方法
- return object;
- }
-
- }
再小的努力,乘以365都很明显!
一个程序员最重要的能力是:写出高质量的代码!!
有道无术,术尚可求也,有术无道,止于术。
无论你是年轻还是年长,所有程序员都需要记住:时刻努力学习新技术,否则就会被时代抛弃!