Spring AOP源码分析(五)Spring AOP的Cglib代理

简介:
上一篇文章介绍了Spring AOP的JDK动态代理的过程,这一篇文章就要介绍下Spring AOP的Cglib代理过程,仍然是使用上一篇文章的工程案例。 

JDK动态代理是由JdkDynamicAopProxy来生成代理对象的,Cglib则是由CglibAopProxy来生成代理对象的。JdkDynamicAopProxy、CglibAopProxy实现了AopProxy接口,如下:
 
?
1
2
3
4
5
6
7
public interface AopProxy {
 
     Object getProxy();
 
     Object getProxy(ClassLoader classLoader);
 
}

然后详细看下CglibProxy的代理对象的生成过程。CglibProxy、JdkDynamicAopProxy都拥有一个非常重要的属性AdvisedSupport advised这个属性包含了拦截的配置信息,这个属性在JdkDynamicAopProxy中已经说过了,不再详细说明。 
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public Object getProxy(ClassLoader classLoader) {
         if (logger.isDebugEnabled()) {
             logger.debug( "Creating CGLIB proxy: target source is " + this .advised.getTargetSource());
         }
         try {
//此时的rootClass为BServiceImpl
             Class<?> rootClass = this .advised.getTargetClass();
             Assert.state(rootClass != null , "Target class must be available for creating a CGLIB proxy" );
 
             Class<?> proxySuperClass = rootClass;
//这里判断rootClass是否是Cglib代理所产生的类(内部判断rootClass的className是否包含$$),对于本工程肯定不符合,跳过
             if (ClassUtils.isCglibProxyClass(rootClass)) {
                 proxySuperClass = rootClass.getSuperclass();
                 Class<?>[] additionalInterfaces = rootClass.getInterfaces();
                 for (Class<?> additionalInterface : additionalInterfaces) {
                     this .advised.addInterface(additionalInterface);
                 }
             }
//验证proxySuperClass中的是否有final方法(仅仅是打印出来警告信息,不做任何处理)
             // Validate the class, writing log messages as necessary.
             validateClassIfNecessary(proxySuperClass);
 
             // Configure CGLIB Enhancer...
             Enhancer enhancer = createEnhancer();
             if (classLoader != null ) {
                 enhancer.setClassLoader(classLoader);
                 if (classLoader instanceof SmartClassLoader &&
                         ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                     enhancer.setUseCache( false );
                 }
             }
             enhancer.setSuperclass(proxySuperClass);
             enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces( this .advised));
             enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
             enhancer.setStrategy( new UndeclaredThrowableStrategy(UndeclaredThrowableException. class ));
 
             Callback[] callbacks = getCallbacks(rootClass);
             Class<?>[] types = new Class<?>[callbacks.length];
             for ( int x = 0 ; x < types.length; x++) {
                 types[x] = callbacks[x].getClass();
             }
             // fixedInterceptorMap only populated at this point, after getCallbacks call above
             enhancer.setCallbackFilter( new ProxyCallbackFilter(
                     this .advised.getConfigurationOnlyCopy(), this .fixedInterceptorMap, this .fixedInterceptorOffset));
             enhancer.setCallbackTypes(types);
 
             // Generate the proxy class and create a proxy instance.
             return createProxyClassAndInstance(enhancer, callbacks);
         }
         //略
     }

上述内容,就是使用Enhancer设置下要继承的父类、设置下要实现的接口、设置下回调然后就创建出代理对象。其中的一个重要的回调Callback为DynamicAdvisedInterceptor,在DynamicAdvisedInterceptor的intercept方法里面实现了和JDK动态代理同样类似的逻辑。 
接下来我们看下这一拦截过程是如何实现的。在DynamicAdvisedInterceptor的intercept方法里:
 
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
@Override
         public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
             Object oldProxy = null ;
             boolean setProxyContext = false ;
             Class<?> targetClass = null ;
             Object target = null ;
             try {
                 if ( this .advised.exposeProxy) {
                     // Make invocation available if necessary.
                     oldProxy = AopContext.setCurrentProxy(proxy);
                     setProxyContext = true ;
                 }
                 // May be null. Get as late as possible to minimize the time we
                 // "own" the target, in case it comes from a pool...
                 target = getTarget();
                 if (target != null ) {
                     targetClass = target.getClass();
                 }
                 List<Object> chain = this .advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                 Object retVal;
                 // Check whether we only have one InvokerInterceptor: that is,
                 // no real advice, but just reflective invocation of the target.
                 if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                     // We can skip creating a MethodInvocation: just invoke the target directly.
                     // Note that the final invoker must be an InvokerInterceptor, so we know
                     // it does nothing but a reflective operation on the target, and no hot
                     // swapping or fancy proxying.
                     retVal = methodProxy.invoke(target, args);
                 }
                 else {
                     // We need to create a method invocation...
                     retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
                 }
                 retVal = processReturnType(proxy, target, method, retVal);
                 return retVal;
             }
             finally {
                 if (target != null ) {
                     releaseTarget(target);
                 }
                 if (setProxyContext) {
                     // Restore old proxy.
                     AopContext.setCurrentProxy(oldProxy);
                 }
             }
         }

上面和JDK动态代理一样也是分两大步,第一步获取一个拦截器链,第二步创建一个MethodInvocation来执行这个拦截器链。 
第一步:和JDK动态代理获取拦截器链的过程一样的。 
第二步:它创建的MethodInvocation是CglibMethodInvocation,它是继承了JDK动态代理所创建的ReflectiveMethodInvocation,覆写了ReflectiveMethodInvocation的invokeJoinpoint方法。ReflectiveMethodInvocation的invokeJoinpoint方法内容如下:
 
?
1
2
3
protected Object invokeJoinpoint() throws Throwable {
         return AopUtils.invokeJoinpointUsingReflection( this .target, this .method, this .arguments);
     }

就是利用反射进行目标方法的调用执行。 
再看下CglibMethodInvocation的invokeJoinpoint方法:
 
?
1
2
3
4
5
6
7
8
protected Object invokeJoinpoint() throws Throwable {
             if ( this .publicMethod) {
                 return this .methodProxy.invoke( this .target, this .arguments);
             }
             else {
                 return super .invokeJoinpoint();
             }
         }

this.publicMethod就是说明所调用的方法是否是public类型的。我们来看下它的来历: 
?
1
2
3
4
5
6
public CglibMethodInvocation(Object proxy, Object target, Method method, Object[] arguments,
                 Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {
             super (proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
             this .methodProxy = methodProxy;
             this .publicMethod = Modifier.isPublic(method.getModifiers());
         }

在构建CglibMethodInvocation这个MethodInvocation时进行赋值的。Modifier.isPublic(method.getModifiers());就是判断该方法是否是public类型的。 
CglibMethodInvocation与ReflectiveMethodInvocation仅仅在执行目标方法的时候有所不同,当目标方法是public方法时,ReflectiveMethodInvocation一直采用反射的策略执行目标方法。而CglibMethodInvocation却使用this.methodProxy.invoke(this.target, this.arguments)代理方法来执行。看下它的好处的描述(CglibMethodInvocation的invokeJoinpoint()方法的注释):
 
?
1
2
3
4
5
6
7
8
/**
          * Gives a marginal performance improvement versus using reflection to
          * invoke the target when invoking public methods.
          */
         @Override
         protected Object invokeJoinpoint() throws Throwable {
//略
}

当执行public方法时,会比反射有一个更好的性能。然而当我们在使用cglib的callback的时候却还是使用反射,没有去使用MethodProxy。因此我们还是按照源码的使用方式来使用,来提升性能。 
本文章中许多步骤省略了,是因为在上一篇SpringAOP JDK的动态代理文章中都进行了详细介绍,同时许多的接口也在上上一篇文章SpringAOP的接口说明中给出了详细的说明。

相关文章
|
3天前
|
监控 Java 应用服务中间件
Spring Boot整合Tomcat底层源码分析
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置和起步依赖等特性,大大简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是其与Tomcat的整合。
19 1
|
9天前
|
XML Java 数据安全/隐私保护
Spring Aop该如何使用
本文介绍了AOP(面向切面编程)的基本概念和术语,并通过具体业务场景演示了如何在Spring框架中使用Spring AOP。文章详细解释了切面、连接点、通知、切点等关键术语,并提供了完整的示例代码,帮助读者轻松理解和应用Spring AOP。
Spring Aop该如何使用
|
14天前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
27 1
|
19天前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
28 1
|
20天前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
25 1
|
10天前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
22 0
|
17天前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
21 0
|
2月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
1月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
163 2
|
9天前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
20 2
 SpringBoot入门(7)- 配置热部署devtools工具