Spring - AOP

 一、AOP概述

 简单通俗来说:AOP就是在保证代码不变的情况下给某一个/一些方法或类添加功能

上图中的代码中可以看到,上面对每个方法都加了统计耗时的代码,但是每个都加工作量太大且繁琐。因此将共同代码抽取出来,定义一个模版方法,如下图:

 下次在调用功能时,会执行模版方法中的原始方法(即选定进行AOP增强的方法或类),这样子之后,最原始的代码没有进行变更,但是已经对其添加了功能

那框架怎么知道我们想要对哪些方法进行AOP增强呢,这就多亏了JDK动态代理

二、AOP核心概念

 三、AOP进阶

3.1 通知类型

 可以将切入点表达式抽取出来,然后直接用:

 3.2 通知顺序

3.3 切入点表达式

 3.4 连接点

 四、基于XML的AOP

 五、基于注解的AOP

 Step2中的步骤可以通过注解代替

六、编写自己的AOP注解类

在Spring中,你可以自定义AOP注解,通过这些注解标记在哪些方法上应用切面逻辑。以下是一个简单的示例,演示如何定义自己的AOP注解,并在Spring中使用它:

首先,定义一个自定义的AOP注解类,可以使用@interface关键字来创建注解:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotation {
    // 可以定义一些注解的属性,视需求而定
    String value() default "";
}

在这个例子中,CustomAnnotation是一个自定义的AOP注解,它可以用于标记在方法上。

接下来,创建一个切面类,用于处理标记了CustomAnnotation注解的方法:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class CustomAspect {

    @Before("@annotation(com.example.CustomAnnotation)")
    public void beforeMethodWithCustomAnnotation() {
        System.out.println("Executing advice for method with CustomAnnotation");
        // 可以在这里实现切面逻辑
    }
}

在这个例子中,CustomAspect是一个切面类,它使用@Before注解定义了一个通知,这个通知在标记了CustomAnnotation注解的方法执行前执行。

最后,在你的服务类中使用CustomAnnotation注解标记要应用切面逻辑的方法:

import org.springframework.stereotype.Service;

@Service
public class MyService {

    @CustomAnnotation
    public void methodWithCustomAnnotation() {
        System.out.println("Executing method with CustomAnnotation");
        // 实际方法逻辑
    }

    public void methodWithoutCustomAnnotation() {
        System.out.println("Executing method without CustomAnnotation");
        // 实际方法逻辑
    }
}

在这个例子中,methodWithCustomAnnotation方法上使用了@CustomAnnotation注解,而methodWithoutCustomAnnotation没有使用。

当调用methodWithCustomAnnotation方法时,切面逻辑会在方法执行前执行。而调用methodWithoutCustomAnnotation方法时,切面逻辑不会被执行。

确保你的Spring配置类(例如使用@SpringBootApplication注解的类)包含@EnableAspectJAutoProxy注解,以启用自动代理。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@SpringBootApplication
@EnableAspectJAutoProxy
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

这样,你就成功定义了一个自己的AOP注解,并在Spring中使用它。这种方式可以帮助你更灵活地标记和处理不同的切点。 

七、AOP 实现权限不同

Spring的AOP 的注解方式实现不同接口权限不同

Spring AOP(面向切面编程)通过注解方式可以方便地实现不同接口权限的控制。你可以使用@Before@After等注解定义在方法执行前、执行后、抛出异常时等切点上执行的通知。以下是一个简单的示例,演示了如何使用AOP注解实现不同接口权限的控制:

首先,定义两个接口:

public interface AdminService {
    void performAdminAction();
}

public interface UserService {
    void performUserAction();
}

然后,创建两个实现类:

@Service
public class AdminServiceImpl implements AdminService {
    @Override
    public void performAdminAction() {
        System.out.println("Admin action performed");
    }
}

@Service
public class UserServiceImpl implements UserService {
    @Override
    public void performUserAction() {
        System.out.println("User action performed");
    }
}

接着,创建一个切面类,定义不同权限的切点和通知:

@Aspect
@Component
public class PermissionAspect {

    @Before("execution(* com.example.service.AdminService.*(..))")
    public void checkAdminPermission() {
        System.out.println("Checking admin permission...");
        // 实际权限检查逻辑
    }

    @Before("execution(* com.example.service.UserService.*(..))")
    public void checkUserPermission() {
        System.out.println("Checking user permission...");
        // 实际权限检查逻辑
    }
}

在这个例子中,checkAdminPermissioncheckUserPermission方法通过@Before注解定义了在执行AdminServiceUserService接口中的任何方法之前执行的通知。在实际应用中,你需要根据需求自定义权限检查逻辑。

最后,在Spring Boot应用程序的入口类上添加@EnableAspectJAutoProxy注解以启用自动代理,确保AOP能够正确工作:

@SpringBootApplication
@EnableAspectJAutoProxy
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

这样,当调用AdminServiceUserService中的方法时,将在执行方法前先执行相应的权限检查通知。请注意,这只是一个基本的示例,实际场景中你可能需要更复杂的权限控制逻辑和更细粒度的切点定义。 

八、使用AOP和JAVA反射实现后端参数校验

在后端参数校验中,你可以使用AOP和Java反射来创建一个通用的校验切面。这个切面可以拦截方法调用,根据方法的参数进行参数校验。下面是一个简单的示例:

首先,定义一个自定义注解来标记需要进行参数校验的方法:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ParamValidation {
}

然后,创建一个切面类,使用AOP和反射实现参数校验:

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

@Aspect
@Component
public class ParamValidationAspect {

    @Before("@annotation(com.example.ParamValidation)")
    public void validateParameters(JoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();

        Parameter[] parameters = method.getParameters();
        Object[] args = joinPoint.getArgs();

        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            Annotation[] annotations = parameter.getAnnotations();
           

            for (Annotation annotation : annotations) {
                // 在这里检查参数上的其他验证注解,例如@NotNull, @Size等
                // 省略具体实现,可以使用第三方库或自定义注解实现
            }

            // 你可以在这里添加其他参数校验逻辑
            validateParameter(args[i]);
        }
    }

    private void validateParameter(Object parameter) {
        // 进行参数校验逻辑,例如检查参数是否为null、是否符合规定的范围等
        // 省略具体实现
    }
}

在这个示例中,ParamValidationAspect类是一个切面类,通过@Before注解,它会在标记了@ParamValidation注解的方法执行前执行。在validateParameters方法中,使用反射获取方法的参数并进行校验。

接下来,你可以在你的服务类中标记需要进行参数校验的方法:

import org.springframework.stereotype.Service;

@Service
public class MyService {

    @ParamValidation
    public void methodWithParamValidation(String name, int age) {
        // 实际业务逻辑
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值