Spring AOP 实现自定义注解的示例

自工作后,除了一些小项目配置事务使用过 AOP,真正自己写 AOP 机会很少,另一方面在工作后还没有写过自定义注解,一直很好奇注解是怎么实现他想要的功能的,刚好做项目的时候,经常有人日志打得不够全,经常出现问题了,查日志的才发现忘记打了,所以趁此机会,搜了一些资料,用 AOP + 自定义注解,实现请求拦截,自定义打日志,玩一下这两个东西,以下是自己完的一个小例子,也供需要的同学参考。

1. 注解如下:

package cn.bridgeli.demo.annotation;
 
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
/**
 * @author bridgeli
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {
    /**
     * 方法描述
     *
     * @return
     */
    String desc() default "";
}

2. 切面

package cn.bridgeli.demo.annotation;
 
import cn.bridgeli.utils.AuthorizeUtil;
import cn.bridgeli.entity.Principal;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
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;
 
/**
 * @author bridgeli
 * 1. 这是一个切面类
 */
@Aspect
@Component
@Slf4j
public class MyLogAspect {
 
    /**
     * 2. PointCut表示这是一个切点,@annotation表示这个切点切到一个注解上,后面带该注解的全类名
     * 切面最主要的就是切点,所有的故事都围绕切点发生
     * logPointCut()代表切点名称
     */
    @Pointcut("@annotation(cn.bridgeli.demo.annotation.MyLog)")
    public void logPointCut() {
    }
 
    /**
     * 3. 环绕通知
     *
     * @param joinPoint
     * @param myLog
     * @return
     */
    @Around(value = "logPointCut() && @annotation(myLog)", argNames = "joinPoint,myLog")
    public Object logAround(ProceedingJoinPoint joinPoint, MyLog myLog) {
        // 获取方法名
        String methodFullPathName = joinPoint.getTarget().getClass().getName() + "#" + joinPoint.getSignature().getName();
 
        // 获取参数
        String params = StringUtils.join(joinPoint.getArgs(), ";");
 
        Principal currentUser = AuthorizeUtil.getCurrentUser();
        log.info("当前登陆用户:" + (null == currentUser ? "" : currentUser.toString()) + ",进入 [ " + methodFullPathName + " ] 方法, 方法的描述:" + myLog.desc() + ",参数为:" + params);
 
        // 继续执行方法
        long startTime = System.currentTimeMillis();
        Object result = null;
        try {
            result = joinPoint.proceed();
        } catch (Throwable e) {
            log.error("切面执行报错,参数:" + params, e);
        }
        long elapsed = System.currentTimeMillis() - startTime;
 
        log.info("[ " + methodFullPathName + " ] 方法执行结束,返回值为:" + (null == result ? "" : result.toString()) + ",用时:" + elapsed);
 
        return result;
    }
}

然后只需要在想使用的地方 @MyLog 就可以了,当然也可以加上 @MyLog(desc = “这是方法描述”),这样打出来的日志还会有方法是做什么的,别人看日志的时候能够一目了然。

需要说明的是,我在写这个切面的时候遇到的一个小问题,在网上看 AOP 的注解,很多人在举例子的时候都是不关注 @Around 的返回值,所以方法的返回值都写的 void,因为我对 AOP 也不是很熟,所以当时同样写了一个 void,结果写好一测试,返回拦截也正常,日志也打印了,被拦截的方法执行也挺正常,但是就是没有了返回值,当时还很奇怪,然后随便试了下返回值改成 Object,竟然对了,所以这是一个小坑,也是很多人没有说明的一点,大家可以注意下,其实这个问题也很容易想到,@Around 是环绕拦截,在执行完被拦截的方法之后,会继续执行切面方法,如果切面方法没有返回值,那么自然而然就没有返回值了,同理 @After 拦截个人猜测也应该有同样的问题,大家可以测试下。

以上就是Spring AOP 实现自定义注解的示例的详细内容,更多关于Spring AOP 实现自定义注解的资料请关注我们其它相关文章!

时间: 2021-03-29

基于Spring AOP @AspectJ进阶说明

@AspectJ可以使用切点函数定义切点,我们还可以使用逻辑运算符对切点进行复核运算得到复合的切点,为了在切面中重用切点,我们还可以对切点进行命名,以便在其他的地方引用定义过的切点. 当一个连接点匹配多个切点时,需要考虑织入顺序的问题,此外一个重要的问题是如何再增强中访问连接点上下文的信息. Waiter接口: package com.yyq.aspectJAdvanced; public interface Waiter { void greetTo(String name); void se

spring aop底层原理及如何实现

前言 相信每天工作都要用spring框架的大家一定使用过spring aop,aop的概念是面向切面编程,相对与传统的面向对象编程oop,aop更关注的是横向的逻辑,比如说一个大型系统中的日志记录,异常处理,性能监控等等,都是各个模块都需要的操作,那样代表着这些操作会散落在系统的各个地方,不易管理且杂乱无章,而aop就是关注的这些,aop将这些操作与业务代码分离,统一成一个个的切面,针对这些个切面进行编程处理.spring aop使得我们的aop开发工作变得简单,这次我就给大家讲讲spring

Spring Aop基本流程原理示例详解

一.代理对象的创建过程: AbstractAutowireCapableBeanFactory#initializeBean protectedObjectinitializeBean(StringbeanName,Objectbean,@NullableRootBeanDefinitionmbd){ if(System.getSecurityManager()!=null){ AccessController.doPrivileged((PrivilegedAction<Object>)()

Spring Boot 结合 aop 实现读写分离

前言 入职新公司到现在也有一个月了,完成了手头的工作,前几天终于有时间研究下公司旧项目的代码.在研究代码的过程中,发现项目里用到了Spring Aop来实现数据库的读写分离,本着自己爱学习(我自己都不信-)的性格,决定写个实例工程来实现spring aop读写分离的效果. 环境部署 数据库:MySql 库数量:2个,一主一从 关于mysql的主从环境部署,可以参考: https://www.jb51.net/article/184698.htm 开始项目 首先,毫无疑问,先开始搭建一个Sprin

springAop实现权限管理数据校验操作日志的场景分析

前言 作为一个写java的使用最多的轻量级框架莫过于spring,不管是老项目用到的springmvc,还是现在流行的springboot,都离不开spring的一些操作,我在面试的时候问的最多的spring的问题就是我们在平常的项目中使用spring最多的有哪几个点 在我看来无非就两个 spring的bean管理,说的高大上一点就是spring的ioc,di spring的AOP spring是一个很强大的轻量级框架,功能远不止这两点,但是我们用的最多的就是这两点. spring bean 管

聊聊Spring AOP @Before @Around @After等advice的执行顺序

用过spring框架进行开发的人,多多少少会使用过它的AOP功能,都知道有@Before.@Around和@After等advice. 最近,为了实现项目中的输出日志和权限控制这两个需求,我也使用到了AOP功能. 我使用到了@Before.@Around这两个advice.但在,使用过程中,却对它们的执行顺序并不清楚. 为了弄清楚在不同情况下,这些advice到底是以怎么样的一个顺序进行执行的,我作了个测试,在此将其记录下来,以供以后查看. 前提 对于AOP相关类(aspect.pointcut

基于spring AOP @Around @Before @After的区别说明

此段小代码演示了spring aop中@Around @Before @After三个注解的区别 @Before是在所拦截方法执行之前执行一段逻辑. @After 是在所拦截方法执行之后执行一段逻辑. @Around是可以同时在所拦截方法的前后执行一段逻辑. 连接点(JoinPoint) 这个就更好解释了,就是spring允许你是通知(Advice)的地方,那可就真多了,基本每个方法的前.后(两者都有也行),或抛出异常是时都可以是连接点,spring只支持方法连接点. 其他如AspectJ还可以

SpringAop实现操作日志记录

前言 大家好,这里是经典鸡翅,今天给大家带来一篇基于SpringAop实现的操作日志记录的解决的方案.大家可能会说,切,操作日志记录这么简单的东西,老生常谈了.不! 网上的操作日志一般就是记录操作人,操作的描述,ip等.好一点的增加了修改的数据和执行时间.那么!我这篇有什么不同呢!今天这种不仅可以记录上方所说的一切,还增加记录了操作前的数据,错误的信息,堆栈信息等.正文开始~~~~~ 思路介绍 记录操作日志的操作前数据是需要思考的重点.我们以修改场景来作为探讨.当我们要完全记录数据的流向的时候,

Spring AOP 切面@Around注解的用法说明

@Around注解可以用来在调用一个具体方法前和调用后来完成一些具体的任务. 比如我们想在执行controller中方法前打印出请求参数,并在方法执行结束后来打印出响应值,这个时候,我们就可以借助于@Around注解来实现: 再比如我们想在执行方法时动态修改参数值等 类似功能的注解还有@Before等等,用到了Spring AOP切面思想,Spring AOP常用于拦截器.事务.日志.权限验证等方面. 完整演示代码如下: 需要说明的是,在以下例子中,我们即可以只用@Around注解,并设置条件,

Spring AOP底层源码详解

ProxyFactory的工作原理 ProxyFactory是一个代理对象生产工厂,在生成代理对象之前需要对代理工厂进行配置.ProxyFactory在生成代理对象之前需要决定到底是使用JDK动态代理还是CGLIB技术. // config就是ProxyFactory对象 // optimize为true,或proxyTargetClass为true,或用户没有给ProxyFactory对象添加interface if (config.isOptimize() || config.isProxy

Spring AOP的实现原理详解及实例

Spring AOP的实现原理详解及实例 spring 实现AOP是依赖JDK动态代理和CGLIB代理实现的. 以下是JDK动态代理和CGLIB代理简单介绍 JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理. CGLIB代理:实现原理类似于JDK动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类.CGLIB是高效的代码生成包,底层是依靠ASM(开源的Java字节码编辑类库)操作字节码实现的,性能比JDK强. 在Spring中

Android实现屏幕锁定源码详解

最近有朋友问屏幕锁定的问题,自己也在学习,网上找了下也没太详细的例子,看的资料书上也没有有关屏幕锁定程序的介绍,下个小决心,自己照着官方文档学习下,现在做好了,废话不多说,先发下截图,看下效果,需要注意的地方会加注释,有问题的朋友可以直接留言,我们共同学习交流,共同提高进步!直接看效果图: 一:未设置密码时进入系统设置的效果图如下: 二:设置密码方式预览: 三:密码解密效果图 四:九宫格解密时的效果图 下面来简单的看下源码吧,此处讲下,这个小DEMO也是临时学习下的,有讲的不明白的地方请朋友直接

话说Spring Security权限管理(源码详解)

最近项目需要用到Spring Security的权限控制,故花了点时间简单的去看了一下其权限控制相关的源码(版本为4.2). AccessDecisionManager spring security是通过AccessDecisionManager进行授权管理的,先来张官方图镇楼. AccessDecisionManager AccessDecisionManager 接口定义了如下方法: //调用AccessDecisionVoter进行投票(关键方法) void decide(Authent

Android context源码详解及深入分析

Android context详解 前言: Context都没弄明白,还怎么做Android开发? Activity mActivity =new Activity() 作为Android开发者,不知道你有没有思考过这个问题,Activity可以new吗?Android的应用程序开发采用Java语言,Activity本质上也是一个对象,那上面的写法有什么问题呢?估计很多人说不清道不明.Android程序不像Java程序一样,随便创建一个类,写个main()方法就能运行,Android应用模型是基

php-msf源码详解

我们来看分享下具体源码:php-msf: https://github.com/pinguo/php-msf 源码解读也做了一段时间了, 总结一下自己的心得: 抓住 生命周期, 让代码在你脑海中 跑起来 分析架构, 关键字 分层 边界 隔离 一个好的框架, 弄清楚 生命周期 和 架构, 基本就已经到了 熟悉 的状态了, 之后是填充细节和编码熟练了 这里再介绍几个次重要的心得: 弄明白这个工具擅长干什么, 适合干什么. 这个信息也非常容易获取到, 工具的文档通常都会显眼标注出来, 可以通过这些 功

ReentrantLock源码详解--公平锁、非公平锁

问题 (1)重入锁是什么? (2)ReentrantLock如何实现重入锁? (3)ReentrantLock为什么默认是非公平模式? (4)ReentrantLock除了可重入还有哪些特性? 简介 Reentrant = Re + entrant,Re是重复.又.再的意思,entrant是enter的名词或者形容词形式,翻译为进入者或者可进入的,所以Reentrant翻译为可重复进入的.可再次进入的,因此ReentrantLock翻译为重入锁或者再入锁. 重入锁,是指一个线程获取锁之后再尝试获

Django 对象关系映射(ORM)源码详解

前言 从前面已经知道, 一个 request 的到来和一个对应 response 的返回的流程, 数据处理和数据库离不开. 我们也经常在 views.py 的函数定义中与数据库打交道. django ORM 源代码组织结构 对于数据库, django 有自己的一套 ORM(对象关系映射), 或许其他的框架可以随意更换 ORM, 但 django 不建议这么做. 因为 django 内置有很多的 model, 这些 model 无疑是用 django 内置 ORM 实现的, 如果更换后, 内置的

java开发之Jdbc分页源码详解

总之是用jdbc 的游标移动 package com.sp.person.sql.util; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Map; import java.util.TreeMap; import javax.sql.DataSource; /** *

微信 小程序前端源码详解及实例分析

微信小程序前端源码逻辑和工作流 看完微信小程序的前端代码真的让我热血沸腾啊,代码逻辑和设计一目了然,没有多余的东西,真的是大道至简. 废话不多说,直接分析前端代码.个人观点,难免有疏漏,仅供参考. 文件基本结构: 先看入口app.js,app(obj)注册一个小程序.接受一个 object 参数,其指定小程序的生命周期函数等.其他文件可以通过全局方法getApp()获取app实例,进而直接调用它的属性或方法,例如(getApp().globalData) //app.js App({ onLau

JS小游戏之宇宙战机源码详解

本文实例讲述了JS小游戏的宇宙战机源码,分享给大家供大家参考.具体介绍如下: 一.游戏介绍: 这是一款飞行射击游戏,纵向,共六关. 二.游戏需求: 1.战机可发射子弹,子弹可通过获取道具升级. 2.战机可放bomb,可获取道具增加数量. 3.战机可蓄力攻击. 4.道具有三种,分别是升级子弹,增加bomb数量,增加战机数量. 5.每关音乐不同. 6.战机被击落后再进入战场,有保护状态. 7.敌机AI设计. 游戏运行如下图所示: 完整实例代码点击此处本站下载. 三.Javascript源码部分: /