Spring AOP 建立代理的源碼解析

相關文章

Spring AOP 註解方式源碼解析java

Spring AOP 功能使用詳解app

Spring 的 getBean 方法源碼解析ide

Spring bean 建立過程源碼解優化

Spring 中 bean 註冊的源碼解析ui

前言

在上篇文章 Spring AOP 註解方式源碼解析 中已經獲取到了 bean 的對應加強器,以後,就能夠建立對應的代理了,Spring AOP 底層使用的是 JDK 動態代理和 CGLIB 的代理,在什麼狀況下使用JDK動態代理,何時使用 CGLIB 代理呢,下面經過源碼來看一下this

// AbstractAutoProxyCreator.java
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
	//......
    // 獲取的加強器
	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;
	}
    //............
	return bean;
}

建立代理 createProxy

protected Object createProxy(Class<?> beanClass, @Nullable String beanName, Object[] specificInterceptors, TargetSource targetSource) {
    // ....
	ProxyFactory proxyFactory = new ProxyFactory();
    //複製當前類的一些屬性
	proxyFactory.copyFrom(this);
    // 若是在配置文件中配置的aop標籤的屬性proxy-target-class爲false,
	if (!proxyFactory.isProxyTargetClass()) {
        // 是否須要代理當前類而不是代理接口,根據preserveTargetClass屬性來判斷Boolean.TRUE.equals(bd.getAttribute("preserveTargetClass")
		if (shouldProxyTargetClass(beanClass, beanName)) {
			proxyFactory.setProxyTargetClass(true);
		}
		else {
            // 若是代理的是接口,則添加代理接口
			evaluateProxyInterfaces(beanClass, proxyFactory);
		}
	}
    // 對加強器進行包裝,有些加強是經過攔截器等方式來實現的,因此這裏統一封裝爲 Advisor 進行處理
	Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    // 加入加強器
	proxyFactory.addAdvisors(advisors);
    // 設置要代理的類
	proxyFactory.setTargetSource(targetSource);
    // 用戶自定義代理
	customizeProxyFactory(proxyFactory);
    // 該屬性用來控制代理工廠被配置之後,是否還容許修改通知,默認爲false
	proxyFactory.setFrozen(this.freezeProxy);
	if (advisorsPreFiltered()) {
		proxyFactory.setPreFiltered(true);
	}
    // 建立代理
	return proxyFactory.getProxy(getProxyClassLoader());
}

// 添加接口代理
protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {
	Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());
	boolean hasReasonableProxyInterface = false;
	//....
	if (hasReasonableProxyInterface) {
		for (Class<?> ifc : targetInterfaces) {
			proxyFactory.addInterface(ifc);
		}
	}
	else {
		proxyFactory.setProxyTargetClass(true);
	}
}

封裝加強,在Spring中,有些加強是經過攔截器來實現的,因此這裏統一封裝爲 Advisor 進行處理,對應方法 buildAdvisors():lua

protected Advisor[] buildAdvisors(String beanName, Object[] specificInterceptors) {
	//解析全部的 InterceptorName
	Advisor[] commonInterceptors = resolveInterceptorNames();

	List<Object> allInterceptors = new ArrayList<>();
	if (specificInterceptors != null) {
        // 添加參數傳進來的,即咱們自定義的加強
		allInterceptors.addAll(Arrays.asList(specificInterceptors));
		if (commonInterceptors.length > 0) {
            // 添加攔截器
			if (this.applyCommonInterceptorsFirst) {
				allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
			}
			else {
				allInterceptors.addAll(Arrays.asList(commonInterceptors));
			}
		}
	}
    //把攔截器包裝爲Advisor
	Advisor[] advisors = new Advisor[allInterceptors.size()];
	for (int i = 0; i < allInterceptors.size(); i++) {
        // wrap包裝
		advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
	}
	return advisors;
}

//wrap包裝
// 僅僅對 Advisor 和 Advice進行包裝
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
    // 若是原本就是 Advisor,則直接返回
	if (adviceObject instanceof Advisor) {
		return (Advisor) adviceObject;
	}
    // 類型不正確,異常
	if (!(adviceObject instanceof Advice)) {
		throw new UnknownAdviceTypeException(adviceObject);
	}
	Advice advice = (Advice) adviceObject;
	if (advice instanceof MethodInterceptor) {
        // MethodInterceptor 類型使用 DefaultPointcutAdvisor 封裝
		return new DefaultPointcutAdvisor(advice);
	}
    // 若是存在 Advisor 的適配器,也須要包裝
	for (AdvisorAdapter adapter : this.adapters) {
		if (adapter.supportsAdvice(advice)) {
			return new DefaultPointcutAdvisor(advice);
		}
	}
	throw new UnknownAdviceTypeException(advice);
}

建立代理getProxyspa

return proxyFactory.getProxy(getProxyClassLoader());

public Object getProxy(ClassLoader classLoader) {
	return createAopProxy().getProxy(classLoader);
}

createAopProxy():

在這裏會判斷代理建立的方式,是使用 JDK 的動態代理仍是 CGLIB 的代理。.net

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    //這裏初步判斷代理的建立方式,若是不知足則直接使用 JDK 動態代理,若是知足條件,則進一步在判斷是否使用 JKD 動態代理仍是 CGLIB 代理
	if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
		Class<?> targetClass = config.getTargetClass();
		if (targetClass == null) {
			throw new AopConfigException("......");
		}
        // 若是代理的是接口或者設置代理的類就是當前類,則使用 JDK 動態代理
		if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
			return new JdkDynamicAopProxy(config);
		}
        // 不然使用 CGLIB 代理
		return new ObjenesisCglibAopProxy(config);
	}
    // 條件不知足CGBLIB的方式直接使用JDK動態代理
	else {
		return new JdkDynamicAopProxy(config);
	}
}

這裏的 if 條件有三個:代理

1. config.isOptimize() : 用來控制經過 CGLIB 建立的代理是否使用激進的優化策略,目前僅用於 CGLIB 代理

2. config.isProxyTargetClass() :  在 Spring AOP 功能使用詳解 中瞭解到,咱們能夠強制 Spring 徹底使用 CGLIB 進行代理,只要在配置文件配置 proxy-target-class 屬性爲true便可,如:<aop:aspectj-autoproxy expose-proxy="true" proxy-target-class="true"/>,若是配置個該屬性,則會使用 CGLIB 來建立代理

3. hasNoUserSuppliedProxyInterfaces(config) : 是否存在代理接口,若是不存在代理接口,則使用 CGLIB 進行代理

若是這三個條件有一個知足,則會再進一次判斷,須要代理的類是不是接口或者是否設置的就是代理當前類,若是是,則仍是會使用 JDK 動態代理,不然的話纔會使用 CGLIB 代理。

若是代理類實現了接口,則Spring默認使用 JDK 動態代理,但能夠設置強制使用 CGLIB 代理

JDK 動態代理只能代理接口而不能代理類

CGLIB 代理類,經過繼承的方式,爲目標類生成子類,並重寫方法來實現代理,它不能代理final的類或方法

關於 JDK 動態代理和 CGLIB 代理的使用方式能夠參考 Spring AOP 功能使用詳解

接下來看下 JDK 動態代理和 CGLIB 代理的建立過程:

JDK 動態代理

return new JdkDynamicAopProxy(config);

// JdkDynamicAopProxy.java
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
	this.advised = config;
}

經過 JDK 動態代理來獲取代理的方法 getProxy():

public Object getProxy(@Nullable ClassLoader classLoader) {
    // 獲取代理類的接口
	Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
    // 處理 equals , hashcode 方法
	findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    // 建立代理
	return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

能夠看到,Spring 使用 JDK 建立代理和咱們使用的 JDK 來建立代理是沒有區別的,都是使用 Proxy.newProxyInstance 的方式來建立;咱們知道 JDK 動態代理有個 invoke 方法,用來執行目標方法,而 JdkDynamicAopProxy 實現了 InvocationHandler 接口,全部它也會重寫該方法,在該方法中植入加強:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	MethodInvocation invocation;
	Object oldProxy = null;
	boolean setProxyContext = false;
    // 目標類
	TargetSource targetSource = this.advised.targetSource;
	Object target = null;

	try {
        // 若是接口沒有定義 equals 方法且當前方法是 equals 方法,則不會加強,直接返回
		if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
			return equals(args[0]);
		}
		else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            // 若是接口沒有定義 hashCode方法且當前方法是 hashCode方法,則不會加強,直接返回
			return hashCode();
		}
		else if (method.getDeclaringClass() == DecoratingProxy.class) {
			return AopProxyUtils.ultimateTargetClass(this.advised);
		}
		else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
				method.getDeclaringClass().isAssignableFrom(Advised.class)) {
            // 若是方法所在的類和Advised是同一個類或者是父類子類關係,則直接執行
			return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
		}
        // 返回值
		Object retVal;
        
        // 這裏對應的是expose-proxy屬性的應用,把代理暴露處理
        // 目標方法內部的自我調用將沒法實施切面中的加強,因此在這裏須要把代理暴露出去
		if (this.advised.exposeProxy) {
			oldProxy = AopContext.setCurrentProxy(proxy);
			setProxyContext = true;
		}

		target = targetSource.getTarget();
		Class<?> targetClass = (target != null ? target.getClass() : null);

		// 獲取該方法的攔截器
		List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

		//若是方法的攔截器爲空,則直接執行目標方法,避免建立 MethodInvocation 對象
		if (chain.isEmpty()) {
			Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            // 執行目標方法:method.invoke(target, args)
			retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
		}
		else {
            // 把全部的攔截器封裝在ReflectiveMethodInvocation中,以便於鏈式調用 
			invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // 執行攔截器鏈
			retVal = invocation.proceed();
		}
        // ..........
		return retVal;
	}
	finally {
      // .            
	}
}

在執行攔截器方法 proceed 中執行加強方法,好比前置加強在方法以前執行,後置加強在方法以後執行,proceed 方法以下:

public Object proceed() throws Throwable {
	//當執行完全部加強方法後執行目標方法
	if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        // method.invoke(target, args)
		return invokeJoinpoint();
	}
     // 獲取下一個要執行的攔截器
	Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

	if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
        // 動態匹配
		InterceptorAndDynamicMethodMatcher dm = interceptorOrInterceptionAdvice;
		Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
        // 若是可以匹配,則執行攔截器的方法,
		if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
            // 好比 @After @Before 對應的加強器(攔截器)的方法
            // 好比 @After 對應的加強器 AspectJAfterAdvice 的invoke方法爲:MethodInvocation.proceed();
			return dm.interceptor.invoke(this);
		}
		else {
			// 若是動態匹配失敗,則跳過該攔截器,執行下一個攔截器
			return proceed();
		}
	}
	else {
		// 普通攔截器,直接調用
		return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
	}
}

在該方法中完成了加強的植入,主要邏輯就是,每一個方法都會有一個攔截器鏈,在 AOP 中咱們稱之爲加強,而後循環執行每一個攔截器鏈,當執行完全部的攔截器後,纔會執行目標方法。好比 @After 對應的加強器AspectJAfterAdvice, @Around 對應的加強器AspectJAroundAdvice等。

以上就是 Spring 經過 JDK 動態代理來實現 AOP 的一個過程。

CGLIB 代理

ObjenesisCglibAopProxy 繼承於 CglibAopProxy

return new ObjenesisCglibAopProxy(config)

public CglibAopProxy(AdvisedSupport config) throws AopConfigException {
	this.advised = config;
	this.advisedDispatcher = new AdvisedDispatcher(this.advised);
}

CglibAopProxy 的 getProxy 方法以下:

public Object getProxy(@Nullable ClassLoader classLoader) {
    // 代理的目標類
	Class<?> rootClass = this.advised.getTargetClass();
	Class<?> proxySuperClass = rootClass;
	if (ClassUtils.isCglibProxyClass(rootClass)) {
		proxySuperClass = rootClass.getSuperclass();
		Class<?>[] additionalInterfaces = rootClass.getInterfaces();
		for (Class<?> additionalInterface : additionalInterfaces) {
			this.advised.addInterface(additionalInterface);
		}
	}
	// 建立並配置 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();
	}
	enhancer.setCallbackFilter(new ProxyCallbackFilter(this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
	enhancer.setCallbackTypes(types);

	//生成代理類和建立代理
	return createProxyClassAndInstance(enhancer, callbacks);
}

// 生成代理類和建立代理
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
	enhancer.setInterceptDuringConstruction(false);
	enhancer.setCallbacks(callbacks);
	return (this.constructorArgs != null && this.constructorArgTypes != null ?
			enhancer.create(this.constructorArgTypes, this.constructorArgs) :
			enhancer.create());
}

從上述的方法可知,Sping 使用 CGLIB 來建立代理類和代理對象和咱們使用的同樣,都是使用 Enhancer.create() 來建立,這裏主要的是設置攔截器,經過 getCallbacks () 方法來實現的,以下:

private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
	//expose-proxy 屬性
	boolean exposeProxy = this.advised.isExposeProxy();
	boolean isFrozen = this.advised.isFrozen();
	boolean isStatic = this.advised.getTargetSource().isStatic();

	// 將攔截器封裝在 DynamicAdvisedInterceptor 中
	Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

	//暴露代理
	Callback targetInterceptor;
	if (exposeProxy) {
		targetInterceptor = (isStatic ?
				new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
				new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));
	}
	else {
		targetInterceptor = (isStatic ?
				new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
				new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));
	}
    // 將攔截器 aopInterceptor 進入到 Callback 中 
	Callback[] mainCallbacks = new Callback[] {
			aopInterceptor,  // for normal advice
			targetInterceptor,  // invoke target without considering advice, if optimized
			new SerializableNoOp(),  // no override for methods mapped to this
			targetDispatcher, this.advisedDispatcher,
			new EqualsInterceptor(this.advised),
			new HashCodeInterceptor(this.advised)
	};
    // ..............
	return callbacks;
}

咱們知道使用 CGLIB 來實現代理功能的時候,當代理執行的時候,會調用 intercept 方法,和 JKD 動態代理的 invoke 方法相似;Spring 中 CGLIB 的 intercept 方法以下,該方法在 DynamicAdvisedInterceptor 中,從上面的代理知道,使用它來封裝攔截器,它是 CglibAopProxy 的一個子類:

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy){
	Object oldProxy = null;
	boolean setProxyContext = false;
	Object target = null;
    // 目標類
	TargetSource targetSource = this.advised.getTargetSource();
    // 處理 expose-proxy 屬性,暴露代理
	if (this.advised.exposeProxy) {
		oldProxy = AopContext.setCurrentProxy(proxy);
		setProxyContext = true;
	}
	target = targetSource.getTarget();
	Class<?> targetClass = (target != null ? target.getClass() : null);
   
    // 獲取攔截器鏈
	List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

    // 返回值
	Object retVal;

	if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
		Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
        // 若是攔截器爲空則直接執行目標方法
		retVal = methodProxy.invoke(target, argsToUse);
	}
	else {
		//封裝攔截器鏈並執行
		retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
	}
    // 處理返回值類型
	retVal = processReturnType(proxy, target, method, retVal);
	return retVal;
    // .....................
}

CGLIB 使用 CglibMethodInvocation 來封裝攔截器鏈,它是 CglibAopProxy 的一個內部類:

private static class CglibMethodInvocation extends ReflectiveMethodInvocation {

	@Nullable
	private final MethodProxy methodProxy;

	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 = (Modifier.isPublic(method.getModifiers()) &&
				method.getDeclaringClass() != Object.class && !AopUtils.isEqualsMethod(method) &&
				!AopUtils.isHashCodeMethod(method) && !AopUtils.isToStringMethod(method) ?
				methodProxy : null);
	}

	// proceed 方法會調用該方法來執行
	@Override
	protected Object invokeJoinpoint() throws Throwable {
		if (this.methodProxy != null) {
			return this.methodProxy.invoke(this.target, this.arguments);
		}
		else {
			return super.invokeJoinpoint();
		}
	}
}

當調用 proceed 方法時,和 JDK 的處理是同樣的,只不過當執行完全部的攔截器後,執行目標方法調用的是 CglibMethodInvocation  的 invokeJoinpoint 來執行而已;由於 CglibMethodInvocation 繼承於 ReflectiveMethodInvocation ,而 JDK 使用的就是 ReflectiveMethodInvocation 來執行的,ReflectiveMethodInvocation 的 invokeJoinpoint 方法爲 : method.invoke(target, args)

以上就是 Spring  使用 JDK 動態代理和 CGLIB 代理來實現 AOP 的原理。

相關文章
相關標籤/搜索