Heim  >  Artikel  >  Java  >  So implementieren Sie die Aop-Funktion schnell in einem Springboot-Projekt

So implementieren Sie die Aop-Funktion schnell in einem Springboot-Projekt

WBOY
WBOYnach vorne
2023-05-16 23:04:151424Durchsuche

Abhängigkeitseinführung

Nachdem Springboot das AOP-Abhängigkeitspaket eingeführt hat, ist im Allgemeinen keine weitere Konfiguration erforderlich. In niedrigeren Versionen oder anderen Konfigurationen, die die zugehörigen Funktionen von AOP beeinträchtigen und dazu führen, dass die AOP-Funktion nicht wirksam wird, können Sie versuchen, @EnableAspectJAutoProxy hinzuzufügen zur Startup-Klasse, um es zu aktivieren;

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

Code-Implementierung

1. Benutzerdefinierte Annotation @TestAop

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

Kernanmerkungen und -klassen

1. Aspekt, der angibt, dass die aktuelle Klasse ein Aspekt ist Vereinfacht gesagt handelt es sich bei der Klasse um eine abstrakte Kapselung von Einstiegspunkten und Benachrichtigungen, die die Entsprechung zwischen Einstiegspunkten und Benachrichtigungsmethoden ausdrückt.

Die mit der Annotation @Before markierte Methode wird ausgeführt, bevor die Methode ausgeführt wird Vorabbenachrichtigung

3. @After, Post-Benachrichtigung, wird für Methoden verwendet, die mit @After-Annotation markierte Methode wird nach der Ausführung der Cut-Methode ausgeführt

4, @AfterReturning, Rückbenachrichtigung, für Methoden verwendet, mit Anmerkungen versehen von @AfterReturning Die markierte Methode wird ausgeführt, nachdem die Cut-in-Methode das Ergebnis zurückgegeben hat.

6: Ausnahmebenachrichtigung, wird für Methoden verwendet, die durch die @AfterThrowing-Annotation markiert werden Löst eine Ausnahme aus. Der Zweck besteht darin, Ausnahmeinformationen abzurufen

8. @Pointcut, markiert in der Methode Ein, wird verwendet, um den Einstiegspunkt zu definieren, der sich auf die Definition bezieht, welche Verbindungspunkte im Frühjahr verbessert werden sollen bezieht sich auf die Definition, welche Methoden erweitert werden sollen; der mit @Pointcut versehene Ausdruck stellt den Einstiegspunkt dar. Die am häufigsten verwendeten sind Ausführungsausdrücke

9 bezieht sich auf den Positionspunkt, in den der AOP-Aspekt geschnitten wird, und bezieht sich insbesondere auf die Methode, in die

10, PointCut,

11, Benachrichtigung eingefügt wird die Definition, welche spezifischen Operationen nach dem Abfangen des definierten Einstiegspunkts ausgeführt werden sollen; in Spring bezieht es sich auf @Before, @After, @AfterReturning, @AfterThrowing, @Around-Annotationsmarkierte Methoden

; 1. Ausführungsausdruck

Ausdrucksmethode: Zugriffsmodifikator-Rückgabewert Paketname... Klassenname .Methode (Parameterliste)

Beispiel 1: Zeigt an, dass alle mit add beginnenden Methoden in allen com.fanfu-Paketen übereinstimmen alle Klassen unter Unterpaketen. Der Rückgabewert und die Parameter sind nicht begrenzt.

@Component
@Aspect
@Slf4j
public class ExampleAop {
 
    //切入点:增强标有@TestAop注解的方法
    @Pointcut(value = "@annotation(TestAop)")
    //切入点签名
    public void pointcut() {
        System.out.println("pointCut签名。。。");
    }
 
    //前置通知
    @Before("pointcut()")
    public void deBefore(JoinPoint joinPoint) throws Throwable {
        log.info("前置通知被执行");
        //可以joinpoint中得到命中方法的相关信息,利用这些信息可以做一些额外的业务操作;
    }
 
    //返回通知
    @AfterReturning(returning = "ret", pointcut = "pointcut()")
    public void doAfterReturning(Object ret) throws Throwable {
        log.info("返回通知被执行");
        //可以joinpoint中得到命中方法的相关信息,利用这些信息可以做一些额外的业务操作;
    }
 
    //异常通知
    @AfterThrowing(throwing = "ex", pointcut = "pointcut()")
    public void throwss(JoinPoint jp, Exception ex) {
        log.info("异常通知被执行");
        //可以joinpoint中得到命中方法的相关信息,利用这些信息可以做一些额外的业务操作;
        //可以从ex中获取到具体的异常信息
    }
 
    //后置通知
    @After("pointcut()")
    public void after(JoinPoint jp) {
        log.info("后置通知被执行");
        //可以joinpoint中得到命中方法的相关信息,利用这些信息可以做一些额外的业务操作;
    }
 
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info("------环绕通知 start");
        String methodName = proceedingJoinPoint.getSignature().getName();
        String className = proceedingJoinPoint.getTarget().getClass().getName();
        Object[] args = proceedingJoinPoint.getArgs();
        String argsName = null;
        StringBuilder sb = new StringBuilder();
        if (args != null && args.length > 0) {
            for (int i = 0; i < args.length; i++) {
                if (args[i] != null) {
                    sb.append(";").append(args[i].getClass().getName());
                }
            }
            if (sb.toString().length() > 0) {
                argsName = sb.toString().substring(1);
            }
        }
        log.info("命中类:{},方法{},参数{};", className, methodName, argsName);
        Object proceed = proceedingJoinPoint.proceed();
        log.info("------环绕通知 end");
        return proceed;
    }
 
}

Beispiel 2: Gibt an, dass alle Klassen unter dem Fanfu-Paket und den Unterpaketen mit add beginnen Zeichenfolge und der Rückgabewert sind nicht begrenzt;

@Pointcut("execution(* com.fanfu..*.*.add*(..))")

Beispiel 3: Gibt an, dass eine beliebige Klasse, eine beliebige Methode und ein beliebiger Parameter unter dem com.fanfu-Paket vorhanden sind Das erste * gibt an, dass der Rückgabewerttyp willkürlich ist, das heißt, der Rückgabewerttyp ist nicht begrenzt (..) stellt einen beliebigen Parameter dar;

Das letzte *.*(..) stellt eine beliebige Klasse, eine beliebige Methode und einen beliebigen Parameter dar

Annotationssyntax: @annotation (benutzerdefinierte Annotation)

Beispiel : Stellt eine Methode dar, die mit allen Tag-@TestAop-Anmerkungen übereinstimmt |, ! operation;

1, point1()&&point2() stellen den Schnittpunkt aller Pointcuts dar, die point1 und point2 treffen, wie im Beispiel: alle Klassen im com.fanfu-Paket und alle untergeordneten Unterpakete, alle Methoden Deren Methodennamen mit „add“ beginnen und deren Parametertyp „String“ ist, überschneiden sich mit allen Methoden im Paket „com.fanfu.service“ und allen Klassen in allen Unterpaketen, unabhängig vom Methodennamen und Parametertyp, also „com.fanfu“. Klassen im Servicepaket und allen Unterpaketen führt die Methode oder die Methode add1 oder add2 die Logik in der Methode around() vor und nach dem Aufruf aus.
@Pointcut("execution(* com.fanfu..*.*.add*(String))")

2, point1()&&point2() bedeutet, Punkt1 und the zu treffen Vereinigung aller Einstiegspunkte von point2; zum Beispiel: In allen Klassen des Pakets com.fanfu.service und allen untergeordneten Unterpaketen ist der Methodenname add1 und der Parametertyp String, und alle Methoden von com.fanfu. Controller-Paket und In allen Klassen aller untergeordneten Unterpakete ist der Methodenname add2 und der Parametertyp String. Nehmen Sie die Vereinigung aller Methoden, also in allen Klassen von com.fanfu.service oder com.fanfu. Controller-Paket und alle untergeordneten Unterpakete, die Methode Oder die Methode von add1 oder add2, die Logik in der Methode around() wird vor und nach dem Aufruf ausgeführt

@Pointcut("execution(* com.fanfu..*.*.*(String))")

3 Einstiegspunkte, die auf point() treffen, wie im Beispiel: com.fanfu In allen Klassen des .service-Pakets und aller seiner Unterpakete führen Methoden, die nicht mit add beginnen, die Logik in der Methode around() vor und aus Wenn die Methode nach dem Aufruf zum ersten Mal in der aktuellen Aufrufkette abgeglichen wird, wird sie ausgeführt, d. h. die entsprechende Benachrichtigung wird ausgeführt, wenn die aktuelle Aufrufkette noch nicht beendet ist Wenn die aktuelle Klasse in der aktuellen Methode aufgerufen wird, stimmt sie mit anderen Einstiegspunkten überein, d. h. es werden keine anderen zugehörigen Benachrichtigungen mehr ausgelöst, wenn andere Methoden ausgeführt werden, die mit dem Einstiegspunkt übereinstimmen Das folgende Beispiel:

当请求http://localhost:8080/example时,ExampleController中的example方法被触发,ExampleController#example()又调用了ExampleService#test(),在ExampleService#test()内部,又顺序调用了ExampleService#test1()和ExampleService#test2();在ExampleAop中,按照execution中的配置,是可以匹配到test()、test1()、test2(),实际是命中的方法只有test();

@Component
@Aspect
@Slf4j
public class ExampleAop {
    @Pointcut("execution(* com.fanfu.service.impl.ExampleServiceImpl.test*(..))")
    public void point2() {
        log.info("切入点匹配");
    }
    @Around("point()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info("------around start");
        String methodName = proceedingJoinPoint.getSignature().getName();
        String className = proceedingJoinPoint.getTarget().getClass().getName();
        Object[] args = proceedingJoinPoint.getArgs();
        String argsName=null;
        StringBuilder sb=new StringBuilder();
        if (args!=null&&args.length>0) {
            for (int i = 0; i < args.length; i++) {
                if (args[i] != null) {
                    sb.append(";").append(args[i].getClass().getName());
                }
            }
            if (sb.toString().length()>0) {
                argsName=sb.toString().substring(1);
            }
        }
        log.info("命中类:{},方法{},参数{};",className,methodName,argsName);
        Object proceed = proceedingJoinPoint.proceed();
        log.info("------around end");
        return proceed;
    }
}
@Service
@Slf4j
public class ExampleServiceImpl implements IExampleService {
 
    @Override
    public String test(String msg) {
        log.info("test方法被执行");
        this.test1(msg);
        this.test2(msg);
        return msg;
    }
 
    public String test1(String msg) {
        log.info("test1方法被执行");
        return "msg1";
    }
 
    public String test2(String msg) {
        log.info("test2方法被执行");
        return "msg2";
    }
}
public interface IExampleService {
    public String test(String msg);
    public String test1(String msg);
    public String test2(String msg);
}
@RestController
@Slf4j
public class ExampleController {
    @Autowired
    private IExampleService exampleService;
    @GetMapping("/example")
    public String example() {
        log.info("example start");
        exampleService.test(null);
        log.info("example end");
        return String.valueOf(System.currentTimeMillis());
    }
}

So implementieren Sie die Aop-Funktion schnell in einem Springboot-Projekt

2、对于上面的问题,如果把execution表达换成注解,会不会结果不一样?再把ExampleAop中的@Pointcut改成注解形式,再在ExampleService#test1()、ExampleService#test2()、ExampleService#test()添加注解@TestAop,验证结果依然是一样的,只有test()会命中,其他不会!所以要注意呀。

@Component
@Aspect
@Slf4j
public class ExampleAop {
    @Pointcut("@annotation(TestAop)")
    public void point() {
    }
    @Around("point()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info("------around start");
        String methodName = proceedingJoinPoint.getSignature().getName();
        String className = proceedingJoinPoint.getTarget().getClass().getName();
        Object[] args = proceedingJoinPoint.getArgs();
        String argsName = null;
        StringBuilder sb = new StringBuilder();
        if (args != null && args.length > 0) {
            for (int i = 0; i < args.length; i++) {
                if (args[i] != null) {
                    sb.append(";").append(args[i].getClass().getName());
                }
            }
            if (sb.toString().length() > 0) {
                argsName = sb.toString().substring(1);
            }
        }
        log.info("命中类:{},方法{},参数{};", className, methodName, argsName);
        Object proceed = proceedingJoinPoint.proceed();
        log.info("------around end");
        return proceed;
    }
}
@Service
@Slf4j
public class ExampleServiceImpl implements IExampleService {
 
    @Override
    @TestAop
    public String test(String msg) {
        log.info("test方法被执行");
        this.test1(msg);
        this.test2(msg);
        return msg;
    }
    @Override
    @TestAop
    public String test1(String msg) {
        log.info("test1方法被执行");
        return "msg1";
    }
    @Override
    @TestAop
    public String test2(String msg) {
        log.info("test2方法被执行");
        return "msg2";
    }
   
}

3、那什么情况下,ExampleService#test1()、ExampleService#test2()、ExampleService#test()会同时命中呢?让从ExampleController#example()到ExampleService#test1()、ExampleService#test2()、ExampleService#test()分别在不同的调用链上,那么就可以同时命中了;

@RestController
@Slf4j
public class ExampleController {
    @Autowired
    private IExampleService exampleService;
    @GetMapping("/example")
    public String example() {
        log.info("example start");
        exampleService.test(null);
        exampleService.test1(null);
        exampleService.test2(null);
        log.info("example end");
        return String.valueOf(System.currentTimeMillis());
    }
}

So implementieren Sie die Aop-Funktion schnell in einem Springboot-Projekt

Das obige ist der detaillierte Inhalt vonSo implementieren Sie die Aop-Funktion schnell in einem Springboot-Projekt. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen