博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring AOP源码分析(五)Spring AOP的Cglib代理
阅读量:6219 次
发布时间:2019-06-21

本文共 6469 字,大约阅读时间需要 21 分钟。

上一篇文章介绍了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的接口说明中给出了详细的说明。

转载地址:http://bymja.baihongyu.com/

你可能感兴趣的文章
[转]sprintf wsprintf swprintf
查看>>
(转)利用Lucene.net对附件做搜索
查看>>
AE CreateFeatureClass 创建shp. 删除shp. 向shp中添加要素
查看>>
uniq 命令去重复行的使用方法 (转)
查看>>
SpringSide 3 中的安全框架
查看>>
win32用GDI+加载png图片作为背景图
查看>>
C语言中字符串的格式化
查看>>
jquery实现select二级联动
查看>>
(转) 解决ssh的"Write failed: Broken pipe"问题
查看>>
struts2标签(转)
查看>>
.NET 环境中使用RabbitMQ(转)
查看>>
关于Http 传输二维json
查看>>
数据库审计
查看>>
[轉]UML
查看>>
H2 database translation.properties 中文翻译
查看>>
怎样招聘出色的产品经理zz
查看>>
PowerShell应用之-可更新订阅的事务复制
查看>>
让代码飞一会儿:快速编写 HTML 和 CSS 的工具和技术
查看>>
C# 委托系列(二)将方法绑定到委托
查看>>
nfs 网络共享
查看>>