Heim  >  Artikel  >  Java  >  So verwenden Sie AOP und Interceptors, um benutzerdefinierte Anmerkungen in SpringBoot zu implementieren

So verwenden Sie AOP und Interceptors, um benutzerdefinierte Anmerkungen in SpringBoot zu implementieren

PHPz
PHPznach vorne
2023-05-29 19:58:00935Durchsuche

    Spring implementiert benutzerdefinierte Anmerkungen

    Implementierung benutzerdefinierter Anmerkungen über Interceptor + AOP, wobei der Interceptor als Methode fungiert, die bei der angegebenen Annotation ausgeführt werden soll, und Aop dafür verantwortlich ist, die Methode des Interceptors und die Annotation in Kraft zu setzen Ein Weben vor Ort (Proxy-Klassenimplementierung durch dynamische Annotation generieren).

    1. Einführung verwandter Abhängigkeiten

    spring-boot-starter: einige grundlegende Abhängigkeiten von Spring

    spring-boot-starter-aop: einige verwandte Abhängigkeiten von Spring, die Aop implementieren

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

    1. Benutzerdefinierte Annotationsklasse

    @Target({ElementType.TYPE})  //说明了Annotation所修饰的对象范围,这里,的作用范围是类、接口(包括注解类型) 或enum
    @Retention(RetentionPolicy.RUNTIME)  //自定义注解的有效期,Runtime:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
    @Documented //标注生成javadoc的时候是否会被记录
    public @interface EasyExceptionResult {
    }

    2. Interceptor-Klasse

    /**
     * MethodInterceptor是AOP项目中的拦截器(注:不是动态代理拦截器),
     * 区别与HandlerInterceptor拦截目标时请求,它拦截的目标是方法。
     */
    public class EasyExceptionIntercepter implements MethodInterceptor {
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            AnnotatedElement element=invocation.getThis().getClass();
            EasyExceptionResult easyExceptionResult=element.getAnnotation(EasyExceptionResult.class);
            if (easyExceptionResult == null) {
                return invocation.proceed();
            }
            try {
                return invocation.proceed();
            } catch (Exception rpcException) {
                //不同环境下的一个异常处理
                System.out.println("发生异常了");
                return null;
            }
        }
    }

    3. Die Implementierungsklasse von MethodInterceptor kann als Ausführungsmethode von Aspector verwendet werden, da die übergeordnete Klasse von Interceptor Advice ist.

    @Configuration
    public class EasyExceptionAdvisor {
     
        /**
         * 放在最后执行
         * 等待ump/日志等记录结束
         *
         * @return {@link DefaultPointcutAdvisor}对象
         */
        @Bean
        @Order(Integer.MIN_VALUE)
        public DefaultPointcutAdvisor easyExceptionResultAdvisor() {
            DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
            //针对EasyExceptionResult注解创建切点
            AnnotationMatchingPointcut annotationMatchingPointcut = new AnnotationMatchingPointcut(EasyExceptionResult.class, true);
            EasyExceptionIntercepter interceptor = new EasyExceptionIntercepter();
            advisor.setPointcut(annotationMatchingPointcut);
            //在切点执行interceptor中的invoke方法
            advisor.setAdvice(interceptor);
            return advisor;
        }
     
    }

    4. Verwendung von benutzerdefinierten Anmerkungen

    @Service
    @EasyExceptionResult  //自定义异常捕获注解
    public class EasyServiceImpl {
     
        public void testEasyResult(){
            throw new NullPointerException("测试自定义注解");
        }
     
    }

    5. Wirkung

    @SpringBootApplication
    public class JdStudyApplication {
     
        public static void main(String[] args) {
            ConfigurableApplicationContext context=SpringApplication.run(JdStudyApplication.class, args);
            EasyServiceImpl easyService=context.getBean(EasyServiceImpl.class);
            easyService.testEasyResult();
        }
     
    }

    Bisher wurden benutzerdefinierte Anmerkungen bis zum Frühjahr implementiert.

    So verwenden Sie AOP und Interceptors, um benutzerdefinierte Anmerkungen in SpringBoot zu implementierenJava implementiert benutzerdefinierte Anmerkungen

    Obwohl benutzerdefinierte Anmerkungen über Spring implementiert werden, gibt es für uns immer noch Möglichkeiten, benutzerdefinierte Anmerkungen zu implementieren, ohne Spring zu verwenden. Schließlich gibt es Anmerkungen früher als Spring.

    Es gibt einige Meta-Anmerkungen im JDK, hauptsächlich @Target, @Retention, @Document und @Inherited, die zum Ändern von Anmerkungen verwendet werden. Das Folgende ist eine benutzerdefinierte Anmerkung.

    @Target({ElementType.TYPE})  //说明了Annotation所修饰的对象范围,这里,的作用范围是类、接口(包括注解类型) 或enum
    @Retention(RetentionPolicy.RUNTIME)  //自定义注解的有效期,Runtime:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
    @Documented //标注生成javadoc的时候是否会被记录
    public @interface EasyExceptionResult {
    }

    @Target

    Gibt den Java-Elementtyp an, auf den diese Annotation angewendet werden kann

    ZieltypBeschreibungGilt für Klassen, Schnittstellen (einschließlich Anmerkungstypen) und Aufzählungen angewandt auf Eigenschaften (einschließlich Konstanten in Aufzählungen) angewandt auf Methoden angewandt auf. Methode Parameterwird auf Konstruktoren angewendetwird auf lokale Variablen angewendetwird auf Annotationstypen angewendetauf die Tasche aufgetragenNeu in Version 1.8, angewendet auf Typvariablen) Neu in Version 1.8, angewendet auf alle Anweisungen, die Typen verwenden (z. B. Deklarationsanweisungen, Generika und Umwandlungsanweisungen). Geben Sie ein )@Retention
    ElementType.TYPE
    ElementType.FIELD
    ElementType.METHOD
    ElementType.PARAMETER
    ElementType.CONSTRUCTOR
    ElementType.LOCAL_VARIABLE
    ElementType.ANNOTATION_TYPE
    ElementType.PACK AGE
    ElementType.TYPE_PARAMETER
    ElementType.TYPE_USE

    Gibt den Lebenszyklus der Anmerkung an

    LebenszyklustypBeschreibung wird verworfen Kompilieren, nicht in der Klasse enthalten Die Datei wird beim Laden der JVM verworfen und in die Klassendatei aufgenommen. Der Standardwert wird von der JVM geladen und in die Klassendatei aufgenommen und kann sein Zur Laufzeit erhalten. An @Document
    RetentionPolicy.SOURCE
    RetentionPolicy.CLASS
    RetentionPolicy.RUNTIME

    gibt an, dass das durch diese Annotation markierte Element von Javadoc oder ähnlichen Tools dokumentiert werden kann

    @Inherited

    gibt an, dass die Annotation mit der Annotation @Inherited eine ist Unterklasse der markierten Klasse Die Klasse wird auch über diese Annotationimplementiert durch Cglib

    Nachdem wir die Annotation definiert haben, müssen wir überlegen, wie wir die Annotation und die Klasse miteinander verbinden, um den gewünschten Effekt zur Laufzeit zu erzielen Wir können den dynamischen Proxy-Mechanismus einführen. Die Annotation möchte die Operation ausführen, bevor die Methode ausgeführt wird, und eine Weboperation wird wie folgt ausgeführt, wenn die Klasse kompiliert wird.

    public static void main(String[] args) {
            Class easyServiceImplClass=EasyServiceImpl.class;
            //判断该对象是否有我们自定义的@EasyExceptionResult注解
            if(easyServiceImplClass.isAnnotationPresent(EasyExceptionResult.class)){
                final EasyServiceImpl easyService=new EasyServiceImpl();
                //cglib的字节码加强器
                Enhancer enhancer=new Enhancer();
                将目标对象所在的类作为Enhaner类的父类
                enhancer.setSuperclass(EasyServiceImpl.class);
                通过实现MethodInterceptor实现方法回调,MethodInterceptor继承了Callback
                enhancer.setCallback(new MethodInterceptor() {
                    @Override
                    public Object intercept(Object proxy, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                        try{
                            method.invoke(easyService, args);
                            System.out.println("事务结束...");
                        }catch (Exception e){
                            System.out.println("发生异常了");
                        }
                        return proxy;
                    }
                });
     
                Object obj= enhancer.create();;
                EasyServiceImpl easyServiceProxy=(EasyServiceImpl)obj;
                easyServiceProxy.testEasyResult();
            }
     
        }

    Betriebseffekt:

    implementiert durch den dynamischen JDk-Proxy

    public class EasyServiceImplProxy implements InvocationHandler {
     
        private EasyServiceImpl target;
     
        public void setTarget(EasyServiceImpl target)
        {
            this.target = target;
        }
     
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 这里可以做增强
            System.out.println("已经是代理类啦");
            try{
                return  method.invoke(proxy, args);
            }catch (Exception e){
                System.out.println("发生异常了");
                return null;
            }
        }
     
     
        /**
         * 生成代理类
         * @return 代理类
         */
        public Object CreatProxyedObj()
        {
            return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        }
    }
    So verwenden Sie AOP und Interceptors, um benutzerdefinierte Anmerkungen in SpringBoot zu implementierenDer Unterschied zwischen Cglib und dem dynamischen JDK-Proxy

    Der dynamische Java-Proxy verwendet den Reflexionsmechanismus, um eine anonyme Klasse zu generieren, die die Proxy-Schnittstelle implementiert, und ruft sie auf bevor Sie die spezifische Methode InvokeHandler aufrufen, die verarbeitet werden soll.

    Der dynamische Proxy von cglib verwendet das Open-Source-Paket ASM, um die Klassendatei der Proxy-Objektklasse zu laden und durch Ändern ihres Bytecodes zu verarbeiten, um eine Unterklasse zu generieren.

    1. Wenn das Zielobjekt die Schnittstelle implementiert, wird standardmäßig der dynamische Proxy von JDK verwendet, um AOP zu implementieren.

    2 Wenn das Zielobjekt die Schnittstelle implementiert, können Sie die Verwendung von CGLIB erzwingen

    3. Wenn das Zielobjekt die Schnittstelle nicht implementiert, muss die CGLIB-Bibliothek verwendet werden. Spring führt automatisch eine Konvertierung zwischen dem dynamischen JDK-Proxy und CGLIB durch.

    Wie erzwinge ich die Verwendung von CGLIB zur Implementierung von AOP?

    (1) Fügen Sie die CGLIB-Bibliothek SPRING_HOME/cglib/*.jar hinzu. (2) Fügen Sie

    in der Spring-Konfiguration hinzu Datei Was ist der Unterschied zwischen dem dynamischen JDK-Proxy und der CGLIB-Bytecode-Generierung?

    (1) Der dynamische JDK-Proxy kann nur Proxys für Klassen generieren, die Schnittstellen implementieren, nicht jedoch für Klassen.

    (2) CGLIB implementiert Proxys für Klassen, hauptsächlich um eine Unterklasse für die angegebene Klasse zu generieren und diese abzudecken Methode

    Weil Da es vererbt wird, ist es am besten, die Klasse oder Methode nicht als final zu deklarieren

    Das obige ist der detaillierte Inhalt vonSo verwenden Sie AOP und Interceptors, um benutzerdefinierte Anmerkungen in SpringBoot zu implementieren. 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