一、基本概念

1、自定义注解

自定义注解我们必须了解四个元注解,什么是元注解?元注解指作用于注解之上的元数据或者元信息,简单通俗的讲,元注解就是注解的注解 .

Documented与Inherited是典型的标识性注解,也就是说在注解内部并没有成员变量,没有成员变量的注解称为标识注解

Documented

指明拥有这个注解的元素可以被javadoc此类的工具文档化。这种类型应该用于注解那些影响客户使用带注释的元素声明的类型。如果一种声明使用Documented进行注解,这种类型的注解被作为被标注的程序成员的公共API 。

Inherited

指明该注解类型被自动继承。如果用户在当前类中查询这个元注解类型并且当前类的声明中不包含这个元注解类型,那么也将自动查询当前类的父类是否存在Inherited元注解,这个动作将被重复执行知道这个标注类型被找到,或者是查询到顶层的父类。

具体请查看:https://blog.csdn.net/ab411919134/article/details/81252516

Retention

指明在什么级别显示此注解

Retention主要的参数类型包括以下几种:

RetentionPolicy.SOURCE 注解存在于源代码中,编译时会被抛弃

RetentionPolicy.CLASS 注解会被编译到class文件中,但是JVM会忽略

RetentionPolicy.RUNTIME JVM会读取注解,同时会保存到class文件中

Target

指明该类型的注解可以注解的程序元素的范围

Target主要的参数类型包括以下几种:

ElementType.TYPE 用于类,接口,枚举但不能是注解

ElementType.FIELD 作用于字段,包含枚举值

ElementType.METHOD 作用于方法,不包含构造方法

ElementType.PARAMETER 作用于方法的参数

ElementType.CONSTRUCTOR 作用于构造方法

ElementType.LOCAL_VERIABLE 作用于本地变量或者catch语句

ElementType.ANNOTATION_TYPE 作用于注解

ElementType.PACKAGE 作用于包

2、@ControllerAdvice 注解

在spring 3.2中,新增了@ControllerAdvice 注解,可以用于定义@ExceptionHandler、@InitBinder、@ModelAttribute,并应用到所有@RequestMapping中

二、完整示例

1、工程结构

2、pom.xml

<?xml version="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.0</modelVersion> <groupId>com.aop.demo</groupId>
<artifactId>aop-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--spring切面aop依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies> </project>

3、新建启动类

package com.aop.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; /**
* @author Administrator
* @date 2018/08/18
*/
@SpringBootApplication
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}

4、自定义异常类

package com.aop.demo.exception;

/**
* @author Administrator
* @date 2018/08/18
*/
public class OperateException extends RuntimeException{ public Integer errorCode;
public String errorMessage; public OperateException(Integer errorCode, String errorMessage){
this.errorCode = errorCode;
this.errorMessage = errorMessage;
} public Integer getErrorCode() {
return errorCode;
} public void setErrorCode(Integer errorCode) {
this.errorCode = errorCode;
} public String getErrorMessage() {
return errorMessage;
} public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
}

5、自定义异常处理类,使用了@ControllerAdvice,来捕捉全局异常

package com.aop.demo.exception;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody; import java.util.HashMap;
import java.util.Map; /**
* @author Administrator
* @date 2018/08/18
*/
@ControllerAdvice
public class MyExceptionHandler {
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Map<String,Object> exceptionProcess(Exception e){
Map<String,Object> map = new HashMap<String, Object>();
if(e instanceof OperateException){
OperateException myException = (OperateException) e;
System.out.println(myException.getErrorCode()+": "+ myException.getErrorMessage());
map.put(myException.getErrorCode().toString(),myException.getErrorMessage());
return map;
}else {
System.out.println("");
map.put("505","系统级错误");
return map;
}
}
}

6、引入aop来处理方法,执行前,执行中,执行后的动作。这里只是在控制台打印信息

1)定义了一个切入点:logwrite(),对com.aop.demo.controller里面的所有方法有效

举例说明execution表达式:

任意公共方法的执行:

execution(public * *(..))

任何一个以“set”开始的方法的执行:

execution(* set*(..))

AccountService 接口的任意方法的执行:

execution(* com.xyz.service.AccountService.*(..))

定义在service包里的任意方法的执行:

execution(* com.xyz.service.*.*(..))

定义在service包和所有子包里的任意类的任意方法的执行:

execution(* com.xyz.service..*.*(..))

定义在pointcutexp包和所有子包里的JoinPointObjP2类的任意方法的执行:

execution(* com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))")

package com.aop.demo.aspect;

import com.aop.demo.controller.MyController;
import com.aop.demo.exception.MyExceptionHandler;
import com.aop.demo.model.LogWrite;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
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.lang.reflect.Method; /**
* @author Administrator
* @date 2018/08/20
*/
@Aspect
@Component
public class HttpAspect { @Autowired
private MyExceptionHandler myExceptionHandler; @Pointcut("execution(public * com.aop.demo.controller.*.*(..))")
public void logwrite(){ } @Before("logwrite()")
public void doBefore(JoinPoint joinPoint){
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
System.out.println("===========================以下是Aspect的Before方法的执行结果==========================");
//url
System.out.println("url="+request.getRequestURL());
//method
System.out.println("method="+request.getMethod());
//ip
System.out.println("id="+request.getRemoteAddr());
//获取类名和方法名
System.out.println("class_method="+joinPoint.getSignature().getDeclaringTypeName() + "," + joinPoint.getSignature().getName());
//args[]
System.out.println("args="+joinPoint.getArgs()); for (Method method: MyController.class.getDeclaredMethods()) {
if(method.getName().equals(joinPoint.getSignature().getName())){
LogWrite logWrite = method.getAnnotation(LogWrite.class);
if(logWrite!=null){
System.out.println("Found LogWrite:"+logWrite.user()+" "+logWrite.action() +"处理中");
}
}
}
} @Around("logwrite()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object result = null;
try {
result = proceedingJoinPoint.proceed();
return result;
} catch (Exception e) {
System.out.println("===========================以下是Aspect的doAround方法捕捉到的异常==========================");
for (Method method: MyController.class.getDeclaredMethods()) {
if(method.getName().equals(proceedingJoinPoint.getSignature().getName())){
LogWrite logWrite = method.getAnnotation(LogWrite.class);
if(logWrite!=null){
System.out.println("Found LogWrite:"+logWrite.user()+" "+logWrite.action() +"处理失败");
}
}
}
return myExceptionHandler.exceptionProcess(e);
}
} @AfterReturning(pointcut = "logwrite()",returning = "object")//打印输出结果
public void doAfterReturing(JoinPoint joinPoint,Object object){
System.out.println("===========================以下是Aspect的doAfterReturing方法的执行结果==========================");
for (Method method: MyController.class.getDeclaredMethods()) {
if(method.getName().equals(joinPoint.getSignature().getName())){
LogWrite logWrite = method.getAnnotation(LogWrite.class);
if(logWrite!=null){
System.out.println("Found LogWrite:"+logWrite.user()+" "+logWrite.action() +"处理完成");
}
}
}
System.out.println("response="+object.toString());
}
}

7、自定义注解

package com.aop.demo.model;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
* @author Administrator
* @date 2018/08/18
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogWrite { public String user() default "adming"; public String action() default "create";
}

8、controller

package com.aop.demo.controller;

import com.aop.demo.exception.OperateException;
import com.aop.demo.model.LogWrite;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; /**
* @author Administrator
* @date 2018/08/18
*/
@RestController
@RequestMapping("/test")
public class MyController { @RequestMapping(value = "/aopsuccess",method = RequestMethod.GET)
@LogWrite(user = "boshen",action = "excute aopsuccess")
public String testSucces(){
return "aopsuccess excute success";
} @RequestMapping(value = "/aoperror/{flag}",method = RequestMethod.GET)
@LogWrite(user = "boshen",action = "excute aoperror")
public String testError(@PathVariable String flag){
if(flag.equals("A")){
throw new OperateException(1001,"发生业务错误");
}
return "testError excute success";
}
}

说明:MyController类里面使用了自定义注解:@LogWrite,在HttpAspect 类里面,获取注解的内容得到user和action,打印到控制台上

9、用postman执行

控制台如下:

===========================以下是Aspect的Before方法的执行结果==========================
url=http://10.111.131.11:8084/aop-test/test/aopsuccess
method=GET
id=10.111.131.11
class_method=com.aop.demo.controller.MyController,testSucces
args=[Ljava.lang.Object;@3b3ffba0
Found LogWrite:boshen excute aopsuccess处理中
===========================以下是Aspect的doAfterReturing方法的执行结果==========================
Found LogWrite:boshen excute aopsuccess处理完成
response=aopsuccess excute success

控制台如下:

===========================以下是Aspect的Before方法的执行结果==========================
url=http://10.111.131.11:8084/aop-test/test/aoperror/A
method=GET
id=10.111.131.11
class_method=com.aop.demo.controller.MyController,testError
args=[Ljava.lang.Object;@67ca9239
Found LogWrite:boshen excute aoperror处理中
===========================以下是Aspect的doAround方法捕捉到的异常==========================
Found LogWrite:boshen excute aoperror处理失败
1001: 发生业务错误
===========================以下是Aspect的doAfterReturing方法的执行结果==========================
Found LogWrite:boshen excute aoperror处理完成
response={1001=发生业务错误}

springboot aop+@interface实现日志记录的更多相关文章

  1. springboot AOP全局拦截日志记录

    @Aspect@Component@Slf4jpublic class WebLogAspect { @Pointcut("execution(public * com.we.control ...

  2. SpringBoot AOP处理请求日志处理打印

    SpringBoot AOP处理请求日志处理打印 @Slf4j @Aspect @Configuration public class RequestAopConfig { @Autowired pr ...

  3. 在SpringBoot中用SpringAOP实现日志记录功能

    背景: 我需要在一个SpringBoot的项目中的每个controller加入一个日志记录,记录关于请求的一些信息. 代码类似于: logger.info(request.getRequestUrl( ...

  4. spring aop 方法增加日志记录

    使用场景: 1:调用外部接口时需要记录出参和入参. 2:分布式系统之间,调用各个系统之间需要记录日志,一旦出现了问题也可以找得到元数据 一言不合,上代码: # 枚举类 package xxxxxxxx ...

  5. Springboot AOP写操作日志 GET POST

    pom.xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...

  6. 使用SpringBoot AOP 记录操作日志、异常日志

    平时我们在做项目时经常需要对一些重要功能操作记录日志,方便以后跟踪是谁在操作此功能:我们在操作某些功能时也有可能会发生异常,但是每次发生异常要定位原因我们都要到服务器去查询日志才能找到,而且也不能对发 ...

  7. 从壹开始前后端分离【 .NET Core2.0 +Vue2.0 】框架之十 || AOP面向切面编程浅解析:简单日志记录 + 服务切面缓存

    代码已上传Github+Gitee,文末有地址 上回<从壹开始前后端分离[ .NET Core2.0 Api + Vue 2.0 + AOP + 分布式]框架之九 || 依赖注入IoC学习 + ...

  8. Z从壹开始前后端分离【 .NET Core2.0/3.0 +Vue2.0 】框架之十 || AOP面向切面编程浅解析:简单日志记录 + 服务切面缓存

    本文梯子 本文3.0版本文章 代码已上传Github+Gitee,文末有地址 大神反馈: 零.今天完成的深红色部分 一.AOP 之 实现日志记录(服务层) 1.定义服务接口与实现类 2.在API层中添 ...

  9. 利用AOP与ToStringBuilder简化日志记录

    刚学spring的时候书上就强调spring的核心就是ioc和aop blablabla...... IOC到处都能看到...AOP么刚开始接触的时候使用在声明式事务上面..当时书上还提到一个用到ao ...

随机推荐

  1. Web服务器控件之button

    button有两种类型的按钮,一种是提交按钮,一种是命令按钮.只说命令按钮. 命令按钮事要使用两个属性,分别是CommandName和CommandArguement属性,当该按钮被点击时,将页面中的 ...

  2. CSS3 transition效果 360度旋转 旋转放大 放大 移动

    效果一:360°旋转 修改rotate(旋转度数) * { transition:All 0.4s ease-in-out; -webkit-transition:All 0.4s ease-in-o ...

  3. C++ 画星号图形——空心正方形(核心代码)

    //输出m行m列的空心正方矩形. int m;//m用来控制行列数. cout<<"请输入要打印的行列数n(n>=4):\n"; cin>>m; ;i ...

  4. java 向上转型 向下转型

    //父类 四边形 class Quadrangle{ public static void draw (Quadrangle q){ } } //子类  public class Parallelog ...

  5. 模板模式(C++) 【转】

    模板模式(template)在面向对象系统的设计和开发过程中,一定会有这样的情况:对于一些功能,在不同的对象身上展示不同的作用,但是功能的框架是一样的,这就是模板(template)模式的用武之地,我 ...

  6. OpenCV cv::Mat类

    using namespace cv; 1.Mat的声明: Mat m=Mat(rows, cols, type); Mat m=Mat(Size(width,height), type); type ...

  7. 实例化bean的三种方式

    简单的说 当获取bean时: 1.直接创建对象 2.不创建对象,直接调用factory-method指定的静态方法 3.先创建对象,再调用factory-method指点的非静态方法

  8. NT内存

    在NT/2K/XP中,操作系统利用虚拟内存管理技术来维护地址空间映像,每个进程分配一个4GB的虚拟地址空间.运行在用户态的应用程序,不能直接访问物理内存地址:而运行在核心态的驱动程序,能将虚拟地址空间 ...

  9. 使用设置报头x-Frame-Options限制iframe网页嵌套

    x-frame-options的出现一部分是为了防止一些别有用心的者制作钓鱼网站,现在支持的浏览器有一下: chrome 4.1.249.1042 firefox 3.6.9(1.9.2.9) IE ...

  10. MySQL查询性能优化一则

    公司有一套Web系统, 使用方反馈系统某些页面访问速度缓慢, 用户体验很差, 并且偶尔还会出现HTTP 502错误. 这是典型的服务器端IO阻塞引发的问题,通过对访问页面的程序逻辑进行跟踪,发现问题应 ...