当前位置: 首页 > 图灵资讯 > 技术篇> 揭示 Spring AOP 的内部工作原理

揭示 Spring AOP 的内部工作原理

来源:图灵教育
时间:2024-09-09 09:53:51

揭示 spring aop 的内部工作原理

在本文中,我们将揭秘 spring 面向方面的编程 (aop) 内部机制。重点是理解。 aop 如何实现日志记录等功能通常被认为是一种“魔法”。通过浏览核心 java 要实现,我们将理解 java 反射、代理模式和注释,而不是任何真正神奇的东西。

先决条件
  • java 核心代理 api
  • 反射api
  • 注释api

这些都是 java.lang.reflect、java.lang.annotation 和 javassist.util.proxy 包的一部分。

核心机制

spring aop 其核心是代理对象、方法拦截器和反射的概念。这种模式中的关键角色是 methodhandler(或调用处理程序)。该处理程序通过拦截调用来控制代理对象的行为。在代理上调用方法时,它会通过处理程序传递,可以通过反射来节省注释。根据应用注释,必要的逻辑(如日志记录)可以在异常前后或异常时执行。

分解它
  1. 代理对象:这些是动态创建的对象,代表您的实际业务对象,通过方法处理程序路由调用。
  2. 调用处理程序:这就是拦截的魔力。使用反射,处理程序可以检查目标方法上的注释,并相应地改变行为。
  3. 自定义注释:可定义自定义注释,用于触发日志记录、安全检查或事务管理等附加功能。

示例: 假设我们想在执行某些方法之前和之后添加日志记录。我们可以使用它 @beforemethod 和 @aftermethod 注释方法,而不是到处编码日志记录。我们的处理程序检查此注释的方法,并动态添加适当的日志记录逻辑。

以下是我们示例中的控制器和服务类别。

workercontroller.java

package edu.pk.poc.aop.controller;

import edu.pk.poc.aop.annotation.aftermethod;
import edu.pk.poc.aop.annotation.all;
import edu.pk.poc.aop.annotation.beforemethod;
import edu.pk.poc.aop.helper.proxyfactory;
import edu.pk.poc.aop.service.worker;
import edu.pk.poc.aop.service.workerservice;
import edu.pk.poc.aop.service.workerserviceimpl;

public class workercontroller {
    workerservice workerservice = proxyfactory.createproxy(workerserviceimpl.class);
    /**
     * this method 1s annotated with @beforemethod and @aftermethod, so the log statements
     * will be generated before and after method call.
     */
    @beforemethod
    @aftermethod
    public void engagefulltimeworker() throws exception {
        worker fulltimeworker = new worker();
        fulltimeworker.setname("fulltime-worker");
        fulltimeworker.setparttime(false);
        fulltimeworker.setduration(9);
        workerservice.dowork(fulltimeworker);
    }
    /**
     * this method is annotated with @all, so the log statements will be generated before and after method call
     * along with exception if raised.
     */
    @all
    public void engageparttimeworker() throws exception {
        worker parttimeworker = new worker();
        parttimeworker.setname("parttime-worker");
        parttimeworker.setparttime(true);
        parttimeworker.setduration(4);
        workerservice.dowork(parttimeworker);
    }
}

workerserviceimpl.java

package edu.pk.poc.aop.service;

import edu.pk.poc.aop.annotation.aftermethod;

public class workerserviceimpl implements workerservice {
    /**
     * here this method is annotated with only @aftermethod, so only log statement
     * will be generated after method call
     */
    @aftermethod
    @override
    public void dowork(worker worker) throws exception {
        if (worker.isparttime()) {
            throw new exception("part time workers are not permitted to work.");
        }
        system.out.print("a full time worker is working for " + worker.getduration() + " hours :: ");
        for (int i = 1; i 



<p><strong>main.java 测试类</strong><br></p>

<pre class="brush:php;toolbar:false">package edu.pk.poc.aop.test;

import edu.pk.poc.aop.controller.workercontroller;
import edu.pk.poc.aop.helper.proxyfactory;
import edu.pk.util.logger;

public class main {
    public static void main(string[] args) {
        workercontroller controller = proxyfactory.createproxy(workercontroller.class);
        logger logger = new logger();
        try {
            system.out.println("testing @beforemethod and @aftermethod");
            system.out.println("-----------------------------------------");
            controller.engagefulltimeworker();
            system.out.println("testing @all");
            system.out.println("-----------------------------------------");
            controller.engageparttimeworker();
        } catch (exception e) {
            logger.error("exception caught in main class");
        }
    }
}

输出

testing @beforemethod and @aftermethod
-----------------------------------------
&gt;&gt;&gt; entering into edu.pk.poc.aop.controller.workercontroller.engagefulltimeworker()
a full time worker is working for 9 hours :: * * * * * * * * 
&gt;&gt;&gt; exiting from edu.pk.poc.aop.service.workerserviceimpl.dowork()
&gt;&gt;&gt; exiting from edu.pk.poc.aop.controller.workercontroller.engagefulltimeworker()
testing @all
-----------------------------------------
&gt;&gt;&gt; entering into edu.pk.poc.aop.controller.workercontroller.engageparttimeworker()
&gt;&gt;&gt; exception in edu.pk.poc.aop.controller.workercontroller.engageparttimeworker()
exception caught in main class

它是如何工作的

当代理对象被调用时,调用将被处理程序拦截,处理程序使用反射来检查目标方法上的所有注释。根据这些注释,处理程序决定是否记录进入/退出、异常记录或完全跳过记录。

以下是可视化其方法:

  • 执行前:记录方法条目。
  • 实施后:退出或成功记录方法。
  • 全部:记录方法条目、方法条目和异常。 这种动态行为表明 spring aop 利用了核心 java api,而不是使用一些神奇的技巧。

定义注释

package edu.pk.poc.aop.annotation;

import java.lang.annotation.elementtype;
import java.lang.annotation.retention;
import java.lang.annotation.retentionpolicy;
import java.lang.annotation.target;

@retention(retentionpolicy.runtime)
@target(elementtype.method)
public @interface aftermethod {

}

package edu.pk.poc.aop.annotation;

import java.lang.annotation.elementtype;
import java.lang.annotation.retention;
import java.lang.annotation.retentionpolicy;
import java.lang.annotation.target;

@retention(retentionpolicy.runtime)
@target(elementtype.method)
public @interface beforemethod {

}

package edu.pk.poc.aop.annotation;

import java.lang.annotation.elementtype;
import java.lang.annotation.retention;
import java.lang.annotation.retentionpolicy;
import java.lang.annotation.target;

@retention(retentionpolicy.runtime)
@target(elementtype.method)
public @interface all {

}

定义代理工厂

package edu.pk.poc.aop.helper;

/**
 * the {@code proxyfactory} class is responsible for creating proxy objects using the javassist library.
 * it allows for dynamic generation of proxies for classes or interfaces, with support for method interception.
 */
public class proxyfactory {

    /**
     * a javassist proxyfactory instance used to generate proxy classes.
     */
    private static final javassist.util.proxy.proxyfactory factory = new javassist.util.proxy.proxyfactory();

    /**
     * creates a proxy object for the given class or interface.
     * if the class is an interface, the proxy implements the interface.
     * if it's a concrete class, the proxy extends the class.
     *
     * @param <t>   the type of the class or interface for which the proxy is to be created
     * @param klass the {@code class} object representing the class or interface to proxy
     * @return a proxy instance of the specified class or interface, or {@code null} if proxy creation fails
     */
    public static <t> t createproxy(class<t> klass) {
        if (klass.isinterface())
            factory.setinterfaces(new class[]{klass});
        else
            factory.setsuperclass(klass);
        try {
            return (t) factory.create(new class&gt;[0], new object[0], new aoploggingmethodhandler());
        } catch (exception e) {
            system.err.println(e.getmessage());
        }
        return null;
    }
}
</t></t></t>

定义 methodhandler

package edu.pk.poc.aop.helper;

import edu.pk.poc.aop.annotation.AfterMethod;
import edu.pk.poc.aop.annotation.All;
import edu.pk.poc.aop.annotation.BeforeMethod;
import edu.pk.poc.aop.annotation.OnException;

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

import edu.pk.util.Logger;
import javassist.util.proxy.MethodHandler;

public class AOPLoggingMethodHandler implements MethodHandler {

    private static final Logger logger = new Logger();

    public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
        if (proceed != null) { // Concrete Method
            Object result = null;
            String className = resolveClassName(self);
            try {
                if (isAnnotationPresent(thisMethod, BeforeMethod.class) || isAnnotationPresent(thisMethod, All.class)) {
                    logger.info("&gt;&gt;&gt; Entering into " + className + "." + thisMethod.getName() + "()");
                }
                result = proceed.invoke(self, args);
                if (isAnnotationPresent(thisMethod, AfterMethod.class) || isAnnotationPresent(thisMethod, All.class)) {
                    logger.info("&gt;&gt;&gt; Exiting from " + className + "." + thisMethod.getName() + "()");
                }
            } catch (Throwable t) {
                if (isAnnotationPresent(thisMethod, OnException.class) || isAnnotationPresent(thisMethod, All.class)) {
                    logger.error("&gt;&gt;&gt; Exception in " + className + "." + thisMethod.getName() + "()");
                }
                throw t;
            }
            return result;
        }
        throw new RuntimeException("Method is Abstract");
    }

    private boolean isAnnotationPresent(Method method, Class klass) {
        Annotation[] declaredAnnotationsByType = method.getAnnotationsByType(klass);
        return declaredAnnotationsByType != null &amp;&amp; declaredAnnotationsByType.length &gt; 0;
    }

    private String resolveClassName(Object self) {
        String className = self.getClass().getName();
        if (className.contains("_$$")) {
            className = className.substring(0, className.indexOf("_$$"));
        }
        return className;
    }
}

结论

spring aop 这是一个强大的工具,用于横切关注,但它没有做任何革命性的事情。它以反射和代理为核心 java 这些概念可以用于语言本身。通过理解这一点,你可以更好地理解它 spring 为了方便开发人员,如何简化这些底层机制。

以上是揭示 Spring AOP 详细介绍内部工作原理,请关注图灵教育的其他相关文章!

上一篇:

第 6 章 最终测试

下一篇:

返回列表