• 3-10:统一记录日志


    对所有的业务记录日志;注意日志与业务的耦合问题

    AOP的概念

    Aspect Oriented Programing,即面向方面(切面)编程。

    • AOP是一种编程思想,是对OOP的补充,可以进一步提高编程的效率。
      在这里插入图片描述
      在这里插入图片描述
      targert: 业务组件是需要处理的目标,目标对象;程序中已经开发好的bean
      aspect: 封装业务需求的方面组件;编程的过程针对于aspect;
      织入:将方面组件的代码,织入到目标对象;分为不同的时机,
      Joinpoint:连接点,在业务组件的哪个位置织入对象
    • 织入时越原始,运行速度越快;
    • 织入早,特殊情况处理的不精细;
    • 织入晚,处理各种情况灵活,但运行速度慢。
    Aspect中需要完成的任务
    1. 声明Pointcut
      声明切点,用表达式来声明,具体要把代码织入到那些目标对象的那些位置
    2. Advice通知
      实现具体的系统逻辑,织入到成员方法的前,后,返回,异常处等等。

    AOP的实现

    列举两项,实际实现方式还有很多

    AspectJ
    1. AspectJ是语言级的实现,它扩展了Java语言,定义了AOP语法。(新的语言,功能强大,但学习代价高
    2. AspectJ在编译期织入代码,它有一个专门的编译器, 用来生成遵守Java字节码规范的class文件。
    Spring AOP
    1. Spring AOP使用纯Java实现,它不需要专门的编译过程,也不需要特殊的类装载器。(方便上手)
    2. Spring AOP在运行时通过代理的方式织入代码,支持方法类型的连接点。(80%以上的项目,都是织入到方法里。灵活)
    3. Spring支持对AspectJ的集成。(高的性价比,有效)
    代理方式

    Spring AOP

    • JDK动态代理

      • Java提供的动态代理技术,可以在运行时创建接口的代理实例(织入代码到代理对象里)。(目标对象需要有接口)
      • Spring AOP默认采用此种方式,在接口的代理实例中织入代码。
    • CGLib动态代理

      • 采用底层的字节码技术,在运行时创建子类代理实例
      • 当目标对象不存在接口时,Spring AOP会采用此种方式,在子类实例中织入代码。

    实现实例

    1. 创建aspect包
    2. 创建相关业务aspect类
      在添加@Aspect 注解时,出现了一个错误,相关的import org.aspectj.lang.annotation相关的全部标红;经过查询多方面的资料
      在正确将依赖添加后,按如图所示操作即可
      在这里插入图片描述
      AlphaAspect.java
    package com.nowcoder.community.aspect;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.stereotype.Component;
    
    @Component //声明一个bean用容器去管理
    @Aspect //定义这是一个切片aspect bean
    public class AlphaAspect {//针对所有的service对象,而不用修改service
        @Pointcut("execution(* com.nowcoder.community.service.*.*(..))")//定义切点,描述那些bean和方法,是要处理的目标
        public void pointcut() {
    
        }
        //定义连接点实现的具体方式
    
        //连接点开头时织入代码
        @Before("pointcut()")
        public void before() {
            System.out.println("before");
        }
    
        //连接点之后时织入代码
        @After("pointcut()")
        public void after() {
            System.out.println("after");
        }
    
        //有了返回值以后,处理一些逻辑
        @AfterReturning("pointcut()")
        public void afterRetuning() {
            System.out.println("afterRetuning");
        }
    
        //在抛异常后的时候织入代码
        @AfterThrowing("pointcut()")
        public void afterThrowing() {
            System.out.println("afterThrowing");
        }
    
        //连接点前后都织入逻辑,需要有返回值
        @Around("pointcut()")
        public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
            System.out.println("around before");
            Object obj = joinPoint.proceed();//调(原始)目标组件的方法,被织入到代理对象
            System.out.println("around after");
            return obj;
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    处理正式的逻辑,记录日志(用户以ip地址表示)
    ServiceLogAspect.java

    package com.nowcoder.community.aspect;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    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.text.SimpleDateFormat;
    import java.util.Date;
    
    @Component
    @Aspect
    public class ServiceLogAspect {
    
        private static final Logger logger = LoggerFactory.getLogger(ServiceLogAspect.class);
    
        @Pointcut("execution(* com.nowcoder.community.service.*.*(..))")
        public void pointcut() {
    
        }
    
        @Before("pointcut()")//前置通知,在开头织入
        public void before(JoinPoint joinPoint) {
            // 用户[1.2.3.4],在[xxx],访问了[com.nowcoder.community.service.xxx()].
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();//获取用户ip,强制类型转换,转换为子类型,宏能多一点
            HttpServletRequest request = attributes.getRequest();
            String ip = request.getRemoteHost();//获取用户ip
            String now = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());//时间,指定格式
            String target = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();//目标的类名和方法名
            //那个类(joinPoint.getSignature().getDeclaringTypeName() )那个(joinPoint.getSignature().getName())方法
            logger.info(String.format("用户[%s],在[%s],访问了[%s].", ip, now, target));//写入日志
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    重启项目验证即可!

  • 相关阅读:
    Web上的推箱子游戏Sokoban
    离散高斯抽样(Discrete Gaussian Sampling)
    RabbitMQ 入门系列:8、扩展内容:接收信息时:可否根据RoutingKey过滤监听信息,答案是不能。
    C/C++内存管理
    Calendar类
    HBase-基本概念
    大数据下一代变革之必研究数据湖技术Hudi原理实战双管齐下-上
    前端图片转成base64
    【无标题】软件测试自动化“领导者”SmartBear举办首场中国线上研讨会:洞悉全球自动化测试走向,探讨降本增效之策
    关于ORVIBO的HomeAI V4.0的分析
  • 原文地址:https://blog.csdn.net/qq_41026725/article/details/127731280