AOP-2-代码实战

目录

实战注意事项

准备

1 aop实现限流

2 aop实现 防止 SQL 注入

3 日志打印+优美的打印格式 (找问题时一幕了然。尤其使用elk)

4 自定义注解 整合 redis

7 异步线程注解形式


实战注意事项

1 环绕通知:环绕通知以及任何通知,不要将异常抓住,否则全局异常处理不到了。

2 注意抛异常时为了搭配全局异常处理器完成的。

准备

     <!--  aop-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

  注解和包扫描 一起组合等

AOP-1-简单应用_我的搬砖日常的博客-CSDN博客

1 aop实现限流

场景: 报表,图片 的下载接口 。 

   方式二:   网关层,读取配置中心,接口url,动态的做成根据url限流。

 自定义注解

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyRateLimiter {
    /**
     * 默认每秒两次限流
     * @return
     */
    int permitsPerSecond() default 2;
}

    @RequestMapping("/test1")
    @MyRateLimiter(permitsPerSecond=3)
    public String test1() throws Exception {
        System.out.println("我是目标方法");
    //    throw   new Exception("我就是要抛异常");
      return "成功";
    }
import cn.hutool.core.util.ObjectUtil;
import com.google.common.util.concurrent.RateLimiter;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.util.concurrent.ConcurrentHashMap;

/**
 * @创建人 赵伟
 * @创建时间 2022/12/12
 * @描述 限流aop
 */
@Aspect
@Component
@Order(value = 9)
@Slf4j
public class RateLimiterAspectaa {
    /**
     * 限流map
      */
   private ConcurrentHashMap<String,RateLimiter> limiterMap =new ConcurrentHashMap();
    /**
     * 环绕通知
     *
     * @param joinPoint
     * @throws Exception
     */
    @Around(value = "@annotation(com.example.comm.ratelimiter.aop.MyRateLimiter)") public Object Around1(
        ProceedingJoinPoint joinPoint) throws Throwable {
        //获取当前执行类
        String typeName = joinPoint.getSignature().getDeclaringTypeName();
        //获取当前执行类中的执行方法
        String name = joinPoint.getSignature().getName();
        //获取当前执行方法中的执行参数
        Object[] object = joinPoint.getArgs();
        //前置通知
        Signature sig = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature)sig;
        //获取注解
        MyRateLimiter declaredAnnotation = methodSignature.getMethod().getDeclaredAnnotation(MyRateLimiter.class);
        //获取限流次数
        int i = declaredAnnotation.permitsPerSecond();
        String key = typeName + "." + name;
        RateLimiter rateLimiter = limiterMap.get(key);
        if (ObjectUtil.isNull(rateLimiter)) {
            rateLimiter = RateLimiter.create(i);
            limiterMap.put(key, rateLimiter);
        }
        boolean b = rateLimiter.tryAcquire();
        if (!b) {
          throw new Exception("访问人数过多");
        }
        log.info("Around1 方法执行前");
        // 执行目标方法
        Object result = joinPoint.proceed();
        log.info("Around1 方法执行后");
        //后置通知
        return result;
    }
}

2 aop实现 防止 SQL 注入

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * @创建人 赵伟
 * @创建时间 2022/12/12
 * @描述 限流aop
 */
@Aspect
@Component
@Slf4j
@Order(value = 9)
public class RateLimiterAspectaa {
    /**
     * 环绕通知
     * @param joinPoint
     * @throws Exception
     */
    @Around(value="execution(* com.example.comm..*.controller..*.*(..)) && execution(public * *(..))")
    public Object Around1(ProceedingJoinPoint  joinPoint) throws Throwable {
        this.checkRequestParam(joinPoint);
        log.info("Around1 方法执行前");
        // 执行目标方法
        Object result = joinPoint.proceed();
        log.info("Around1 方法执行后");
        return result;
    }
    /**
     * 参数校验,防止 SQL 注入
     *
     * @param joinPoint
     */
    private void checkRequestParam(ProceedingJoinPoint joinPoint) throws Exception {
        Object[] args = joinPoint.getArgs();
        if (args == null || args.length <= 0) {
            return;
        }
        String params = Arrays.toString(joinPoint.getArgs()).toUpperCase();
        String[] keywords = {"DELETE ", "UPDATE ", "SELECT ", "INSERT ", "SET ", "SUBSTR(", "COUNT(", "DROP ",
            "TRUNCATE ", "INTO ", "DECLARE ", "EXEC ", "EXECUTE ", " AND ", " OR ", "--"};
        for (String keyword : keywords) {
            if (params.contains(keyword)) {
                log.warn("参数存在SQL注入风险,其中包含非法字符 {}.", keyword);
                throw new Exception("参数存在SQL注入风险:params=" + params);
            }
        }
    }
}

3 日志打印+优美的打印格式 (找问题时一幕了然。尤其使用elk)

4 自定义注解 整合 redis

已经有现成的了 ,就懒得写了。

5 自定义注解整合 权限 (模仿shiro)

单体架构还行,微服务了都,基本都在网关层做权限校验了。

6 动态的日志记录功能

记录个人改了哪些数据,(原始数据,修改后数据)

7 异步线程注解形式

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAsync {

}
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @创建人 赵伟
 * @创建时间 2022/12/14
 * @描述
 */
@Aspect
@Component
@Slf4j
@Order(value = 15)
public class AsyncAspect {


    @Resource
    private ThreadPoolTaskExecutor myExecutor;
    /**
     * 环绕通知
     * @param joinPoint
     * @throws Exception
     */
    @Around(value = "@annotation(com.example.demo.annotation.MyAsync)")
    public Object Around1(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("Around1 方法执行前");
        Object result = myExecutor.submit(() -> {
            try {
                System.out.println(Thread.currentThread().getName());
                return joinPoint.proceed();
            } catch (Throwable throwable) {
                return throwable;
            }
        }).get();
        if(result instanceof Throwable){
            //一定用error打印
            log.error(((Throwable)result).getMessage(),((Throwable)result));
          throw (Throwable)result;
        }
        return result;
    }
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @创建人 赵伟
 * @创建时间 2022/12/14
 * @描述
 */
@Configuration
public class ThreadPoolConfig {

    @Bean("myExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        //设置线程池参数信息
        taskExecutor.setCorePoolSize(1);
        taskExecutor.setMaxPoolSize(1);
        taskExecutor.setQueueCapacity(2);
        taskExecutor.setKeepAliveSeconds(60);
        taskExecutor.setThreadNamePrefix("eventHandle--");
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        // 设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住。
        taskExecutor.setAwaitTerminationSeconds(60);
        //修改拒绝策略为使用当前线程执行
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //初始化线程池
        taskExecutor.initialize();
        return taskExecutor;
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值