千家信息网

如何理解Spring AOP的实现机制

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这篇文章将为大家详细讲解有关如何理解Spring AOP的实现机制,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。AOP(Aspect Orient P
千家信息网最后更新 2026年11月03日如何理解Spring AOP的实现机制

这篇文章将为大家详细讲解有关如何理解Spring AOP的实现机制,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

AOP(Aspect Orient Programming),一般称为面向切面编程,作为面向对象的一种补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理、日志、缓存等等。AOP实现的关键在于AOP框架自动创建的AOP代理,AOP代理主要分为静态代理和动态代理,静态代理的代表为AspectJ;而动态代理则以Spring AOP为代表。静态代理是编译期实现,动态代理是运行期实现,可想而知前者拥有更好的性能。

这里主要介绍Spring AOP的两种代理实现机制,JDK动态代理和CGLIB动态代理。

静态代理是编译阶段生成AOP代理类,也就是说生成的字节码就织入了增强后的AOP对象;动态代理则不会修改字节码,而是在内存中临时生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。

Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。

如果目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的,诸如private的方法也是不可以作为切面的。

我们分别通过实例来研究AOP的具体实现。

直接使用Spring AOP

首先定义需要切入的接口和实现。为了简单起见,定义一个Speakable接口和一个具体的实现类,只有两个方法sayHi()和sayBye()。

public interface Speakable {   void sayHi();   void sayBye();  }  @Service  public class PersonSpring implements Speakable {   @Override   public void sayHi() {   try {   Thread.currentThread().sleep(30);   } catch (Exception e) {   throw new RuntimeException(e);   }   System.out.println("Hi!!");   }   @Override   public void sayBye() {   try {   Thread.currentThread().sleep(10);   } catch (Exception e) {   throw new RuntimeException(e);   }   System.out.println("Bye!!");   }  }

接下来我们希望实现一个记录sayHi()和sayBye()执行时间的功能。

定义一个MethodMonitor类用来记录Method执行时间

public class MethodMonitor {   private long start;   private String method;   public MethodMonitor(String method) {   this.method = method;   System.out.println("begin monitor..");   this.start = System.currentTimeMillis();   }   public void log() {   long elapsedTime = System.currentTimeMillis() - start;   System.out.println("end monitor..");   System.out.println("Method: " + method + ", execution time: " + elapsedTime + " milliseconds.");   }  }

光有这个类还是不够的,希望有个静态方法用起来更顺手,像这样

MonitorSession.begin();  doWork();  MonitorSession.end();

说干就干,定义一个MonitorSession

public class MonitorSession {   private static ThreadLocal monitorThreadLocal = new ThreadLocal<>();   public static void begin(String method) {   MethodMonitor logger = new MethodMonitor(method);   monitorThreadLocal.set(logger);   }   public static void end() {   MethodMonitor logger = monitorThreadLocal.get();   logger.log();   }  }

万事具备,接下来只需要我们做好切面的编码,

@Aspect  @Component  public class MonitorAdvice {   @Pointcut("execution (* com.deanwangpro.aop.service.Speakable.*(..))")   public void pointcut() {   }   @Around("pointcut()")   public void around(ProceedingJoinPoint pjp) throws Throwable {   MonitorSession.begin(pjp.getSignature().getName());   pjp.proceed();   MonitorSession.end();   }  }

如何使用?我用了spring boot,写一个启动函数吧。

@SpringBootApplication  public class Application {   @Autowired   private Speakable personSpring;   public static void main(String[] args) {   SpringApplication.run(Application.class, args);   }   @Bean   public CommandLineRunner commandLineRunner(ApplicationContext ctx) {   return args -> {   // spring aop   System.out.println("******** spring aop ******** ");   personSpring.sayHi();   personSpring.sayBye();   System.exit(0);   };   }  }

运行后输出:

jdk dynamic proxy begin monitor..Hi!!end monitor..Method: sayHi, execution time: 32 milliseconds.begin monitor..Bye!!end monitor..Method: sayBye, execution time: 22 milliseconds.

JDK动态代理

刚刚的例子其实内部实现机制就是JDK动态代理,因为Person实现了一个接口。

为了不和***个例子冲突,我们再定义一个Person来实现Speakable, 这个实现是不带Spring Annotation的,所以他不会被Spring托管。

public class PersonImpl implements Speakable {   @Override   public void sayHi() {   try {   Thread.currentThread().sleep(30);   } catch (Exception e) {   throw new RuntimeException(e);   }   System.out.println("Hi!!");   }   @Override   public void sayBye() {   try {   Thread.currentThread().sleep(10);   } catch (Exception e) {   throw new RuntimeException(e);   }   System.out.println("Bye!!");   }  }

重头戏来了,我们需要利用InvocationHandler实现一个代理,让它去包含Person这个对象。那么再运行期实际上是执行这个代理的方法,然后代理再去执行真正的方法。所以我们得以在执行真正方法的前后做一些手脚。JDK动态代理是利用反射实现,直接看代码。

public class DynamicProxy implements InvocationHandler {   private Object target;   public DynamicProxy(Object object) {   this.target = object;   }   @Override   public Object invoke(Object arg0, Method arg1, Object[] arg2)   throws Throwable {   MonitorSession.begin(arg1.getName());   Object obj = arg1.invoke(target, arg2);   MonitorSession.end();   return obj;   }   @SuppressWarnings("unchecked")   public  T getProxy() {   return (T) Proxy.newProxyInstance(   target.getClass().getClassLoader(),   target.getClass().getInterfaces(),   this   );   }  }

通过getProxy可以得到这个代理对象,invoke就是具体的执行方法,可以看到我们在执行每个真正的方法前后都加了Monitor。

我实现了一个工厂类来获取Person代理对象

public class PersonProxyFactory {   public static Speakable newJdkProxy() {   // 代理PersonImpl   DynamicProxy dynamicProxy = new DynamicProxy(new PersonImpl());   Speakable proxy = dynamicProxy.getProxy();   return proxy;   }  }

具体使用

// jdk dynamic proxy  System.out.println("******** jdk dynamic proxy ******** ");  Speakable jdkProxy = PersonProxyFactory.newJdkProxy();  jdkProxy.sayHi();  jdkProxy.sayBye();

输出结果:

******** jdk dynamic proxy ********   begin monitor..  Hi!!  end monitor..  Method: sayHi, execution time: 32 milliseconds.  begin monitor..  Bye!!  end monitor..  Method: sayBye, execution time: 22 milliseconds.

CGLib动态代理

我们再新建一个Person来,这次不实现任何接口。

public class Person {   public void sayHi() {   try {   Thread.currentThread().sleep(30);   } catch (Exception e) {   throw new RuntimeException(e);   }   System.out.println("Hi!!");   }   public void sayBye() {   try {   Thread.currentThread().sleep(10);   } catch (Exception e) {   throw new RuntimeException(e);   }   System.out.println("Bye!!");   }  }

如果Spring识别到所代理的类没有实现Interface,那么就会使用CGLib来创建动态代理,原理实际上成为所代理类的子类。

public class CGLibProxy implements MethodInterceptor {   private static CGLibProxy instance = new CGLibProxy();   private CGLibProxy() {   }   public static CGLibProxy getInstance() {   return instance;   }   private Enhancer enhancer = new Enhancer();   @SuppressWarnings("unchecked")   public  T getProxy(Class clazz) {   enhancer.setSuperclass(clazz);   enhancer.setCallback(this);   return (T) enhancer.create();   }   @Override   public Object intercept(Object arg0, Method arg1, Object[] arg2,   MethodProxy arg3) throws Throwable {   MonitorSession.begin(arg1.getName());   Object obj = arg3.invokeSuper(arg0, arg2);   MonitorSession.end();   return obj;   }  }

类似的通过getProxy可以得到这个代理对象,intercept就是具体的执行方法,可以看到我们在执行每个真正的方法前后都加了Monitor。

在工厂类中增加获得Person代理类的方法,

public static Person newCglibProxy() {   CGLibProxy cglibProxy = CGLibProxy.getInstance();   Person proxy = cglibProxy.getProxy(Person.class);   return proxy;  }

具体使用

// cglib dynamic proxy  System.out.println("******** cglib proxy ******** ");  Person cglibProxy = PersonProxyFactory.newCglibProxy();  cglibProxy.sayHi();  cglibProxy.sayBye();

输出结果:

begin monitor..Hi!!end monitor..Method: sayHi, execution time: 53 milliseconds.begin monitor..Bye!!end monitor..Method: sayBye, execution time: 14 milliseconds.

小结

对比JDK动态代理和CGLib代理,在实际使用中发现CGLib在创建代理对象时所花费的时间却比JDK动态代理要长,实测数据

Method: newJdkProxy, execution time: 5 milliseconds.  Method: newCglibProxy, execution time: 18 milliseconds.

所以CGLib更适合代理不需要频繁实例化的类。

在具体方法执行效率方面,理应是不通过反射的CGlib更快一些,然后测试结果并非如此,还需要高手指教。

JDKMethod: sayHi, execution time: 32 milliseconds.CGLibMethod: sayHi, execution time: 53 milliseconds.

关于如何理解Spring AOP的实现机制就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

代理 动态 方法 对象 接口 静态 生成 机制 实际 就是 时间 目标 结果 反射 输出 接下来 代码 代表 内容 子类 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 科技互联网 互联网科技公司 深圳市人人互联网科技有限公司 互联网科技工作委员会主任 中国互联网科技工作委员会毛军 互联网科技活动banner 互联网巨头反垄断金融科技 互联网科技视频 远拓互联网科技 上海亿帐通互联网科技 卫星互联网科技股票 宁波青枫互联网科技有限公司 互联网媒体平台算高科技产业 上海创道互联网络科技有限公司 从那以后互联网科技有限公司 兰石爱特工业互联网科技分公司 同城互联网络科技 银川新华互联网科技学校原画 科技互联网公司两年变化 互联网金融金融科技 上海挚品互联网科技有限公司 互联网科技公司税收优惠 港股互联网科技股 电子科技大学互联网 乌苏新华互联网科技做什么的 华夏恒生科技与互联网科技 沐思想互联网科技有限公司 唯美互联网科技 保山浩联互联网科技有限公司 华人运通互联网科技公司
0