cglib动态代理过程

本文介绍了Cglib动态代理的原理,它用于对没有实现接口的类进行代理,通过生成目标类的子类实现。在Spring中,AOP代理在AbstractAutoProxyCreator类中进行,AopProxy接口的Cglib实现用于创建子类代理。当调用被代理对象的方法时,如果内部调用了本类的其他方法,不会经过代理,因此切面可能失效。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考链接:http://www.importnew.com/28342.html

静态代理:编译期将代理方法植入目标方法

Jdk动态代理:对于实现接口的类,采用jdk动态代理实现的接口,所以不是接口中定义的方法没办法被代理。JDK动态代理的核心是InvocationHandler接口和Proxy类。

Cglib动态代理:对于没有实现接口的类,采用cglib代理,通过动态生成目标类的子类进行代理,所以private方法,final方法不能被代理。我觉得关键类是CglibAopProxy和MethodInterceptor。

spring中bean加载过程文章中,我简单分析了一下加载过程,但是在最后设置属性的地方放过了,这个地方是进行AOP代理的入口。

在AbstractAutowireCapableBeanFactory类的doCreateBean方法中

......
try {
            this.populateBean(beanName, mbd, instanceWrapper);//设置属性,依赖关系
            exposedObject = this.initializeBean(beanName, exposedObject, mbd);//对bean进行判断是否要创建代理
        } catch (Throwable var18) {
            if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
                throw (BeanCreationException)var18;
            }

            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
        }
......

一路debug下去之后,在AbstractAutoProxyCreator类中

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// Create proxy if we have advice.
		//这个查找bean对象适用的advisor,并做排序,如果有advisor,那么就创建代理
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

一部分advisor是我们通过注解自定义的,一部分advisor是通过实现MethodMatcher接口的形式,静态的通知,比如Transactional注解,下面的参考链接是Transactional注解的一个解析过程
参考链接:https://blog.youkuaiyun.com/dalinsi/article/details/53215041

创建代理的接口类AopProxy,有两个实现,一个是cglib,一个是jdk,我测试是在CglibAopProxy中创建代理,这里看出是子类代理,将父类适用的advisor植入进去。

@Override
	public Object getProxy(@Nullable ClassLoader classLoader) {
	......
	// 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 ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
	
				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);
		......
		}

AOP切面失效案例:
测试代码如下:
有两个Service,PringLog注解上有设置切面,会打印相关日志。

@Service
public class BManager {

    @PrintLog(logContent = "I'm BService")
    public void functionA(){
        System.out.println("functionA is done");
        functionB();
    }

    @PrintLog(logContent = "I'm BService")
    public void functionB(){
        System.out.println("functionB is done");
    }

    @PrintLog(logContent = "I'm BService")
    public void functionC(){
        System.out.println("functionC is done");
    }
}
@Service
public class AManager {
    @Resource
    private BManager bManager;

    @PrintLog(logContent = "I'm AService")
    public void functionA(){
        System.out.println("functionA is done");
        bManager.functionA();
    }
    
    @PrintLog(logContent = "I'm AService")
    public void functionD(){
        System.out.println("functionD is done");
        bManager.functionB();
        bManager.functionC();
    }
}

测试1:

aManager.functionA();
结果:
enter interceptorstart print log :I'm AService
functionA is done
enter interceptorstart print log :I'm BService
functionA is done
functionB is done

测试2

aManager.functionD();
结果:
enter interceptorstart print log :I'm AService
functionD is done
enter interceptorstart print log :I'm BService
functionB is done
enter interceptorstart print log :I'm BService
functionC is done

在代用的时候,可以明确看到,我们不是直接调用AManager对象,而是调用cglib生成的代理类。
在这里插入图片描述

出现测试2的结果其实我们很好理解,但是测试1的情况,可能有朋友不理解。在进入BManager的A方法时,是通过子类代理进入的,这个时候子类代理前后是被植入了print代码的。但是在进入A方法后,调用本类的B方法,不是通过子类代理调用的, 而是通过父类直接调用,父类中是没有植入print代码的,所以不会有相应的日志

待更新完善…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值