購物網站建設教程關鍵詞推廣效果
在之前的博客中?【JavaEE進階】Spring AOP使用篇_aop多個切點-CSDN博客
我們主要學習了SpringAOP的應用, 接下來我們來學習SpringAOP的原理, 也就是Spring是如何實現(xiàn)AOP的.
SpringAOP 是基于動態(tài)代理來實現(xiàn)AOP的,咱們學習內容主要分以下兩部分
1.代理模式
2.Spring AOP源碼剖析
1.代理模式
定義: 為其他對象提供一種代理以控制對這個對象的訪問, 它的作用就是通過提供一個代理類, 讓我們在調用目標方法的時候, 不再是直接對目標方法進行調用, 而是通過代理類間接調用.
在某些情況下, 一個對象不適合或者不能直接引用另一個對象, 而代理對象可以在客戶端和目標對象之間起到中介的作用.
使用代理前:
使用代碼后:
比如房屋租賃:
Subject: 就是提前定義了房東做的事情,交給中介代理,也是中介要做的事情
RealSubiect: 房東
Proxy: 中介
UML 類圖如下:
代理模式可以在不修改被代理對象的基礎上, 通過擴展代理類, 進行一些功能的附加與增強
根據代理的創(chuàng)建時期, 代理模式分為靜態(tài)代理和動態(tài)代理:
靜態(tài)代理: 由程序員創(chuàng)建代理類或特定工具自動生成源代碼再對其編譯,在程序運行前代理類的
class 文件就已經存在了
動態(tài)代理: 在程序運行時,運用反射機制動態(tài)創(chuàng)建而成
靜態(tài)代理:? 由程序員創(chuàng)建代理類或特定工具自動生成源代碼再對其編譯, 在程序運行前代理類的.class 文件就已經存在了
動態(tài)代理:? 在程序運行時, 運用反射機制動態(tài)創(chuàng)建而成
以房東和中介的的關系舉例:
1.1 靜態(tài)代理
以房東和中介的例子模擬靜態(tài)代理:
1.定義接口(定義房東要做的事情,也是中介需要做的事情)
package com.example.aop.proxy;/*** 業(yè)務接口類*/
public interface HouseSubject {void rentHouse();void saleHouse();
}
?2.實現(xiàn)接口(房東出租房子)目標對象:
package com.example.aop.proxy;/*** 業(yè)務實現(xiàn)類*/
public class RealHouseSubject implements HouseSubject {@Overridepublic void rentHouse() {System.out.println("我是房東, 我出租房子");}@Overridepublic void saleHouse() {System.out.println("我是房東, 我出售房子");}
}
3.代理(中介,幫房東出租房子)
package com.example.aop.proxy;/*** 靜態(tài)代理的代理類 (中介)*/public class HouseProxy implements HouseSubject {//房東對象private HouseSubject target;public HouseProxy(HouseSubject target) {this.target = target;}@Overridepublic void rentHouse() {//代理前System.out.println("我是中介, 開始代理");//出租房子target.rentHouse();//出租后System.out.println("我是中介, 結束代理");}@Overridepublic void saleHouse() {//代理前System.out.println("我是中介, 開始代理");//出售房子target.saleHouse();//出租后System.out.println("我是中介, 結束代理");}
}
?測試:
package com.example.aop.proxy;public class Main {public static void main(String[] args) {
// 靜態(tài)代理HouseProxy proxy = new HouseProxy(new RealHouseSubject());proxy.rentHouse();proxy.saleHouse();System.out.println("========================");HouseSubject houseSubject = new RealHouseSubject();houseSubject.rentHouse();houseSubject.saleHouse();}
}
上面這個代理實現(xiàn)方式就是靜態(tài)代理(仿佛啥也沒干).
從上述程序可以看出, 雖然靜態(tài)代理也完成了對目標對象的代理, 但是由于代碼都寫死了, 對目標對象的每個方法的增強都是手動完成的,非常不靈活. 所以日常開發(fā)幾乎看不到靜態(tài)代理的場景.?
我們修改接口(Subject)和業(yè)務實現(xiàn)類(RealSubject)時, 還需要修改代理類(Proxy).
同樣的, 如果有新增接口(Subiect)和業(yè)務實現(xiàn)類(RealSubiect), 也需要對每一個業(yè)務實現(xiàn)類新增代理類(Proxy). 既然代理的流程是一樣的, 有沒有一種辦法, 讓他們通過一個代理類來實現(xiàn)呢?
這就需要用到動態(tài)代理技術了?
1.2 動態(tài)代理
相比于靜態(tài)代理來說,動態(tài)代理更加靈活.
我們不需要針對每個目標對象都單獨創(chuàng)建一個代理對象, 而是把這個創(chuàng)建代理對象的工作推遲到程序運行時由JVM來實現(xiàn), 也就是說動態(tài)代理在程序運行時, 根據需要動態(tài)創(chuàng)建生成
比如房屋中介,我不需要提前預測都有哪些業(yè)務, 而是業(yè)務來了我再根據情況創(chuàng)建
我們還是先看代碼再來理解,Java也對動態(tài)代理進行了實現(xiàn), 并給我們提供了一些AP1, 常見的實現(xiàn)方式有兩種:
動態(tài)代理在我們日常開發(fā)中使用的相對較少,但是在框架中幾乎是必用的一門技術, 學會了動態(tài)代理之后, 對于我們理解和學習各種框架的原理也非常有幫助.
JDK動態(tài)代理?
JDK動態(tài)代理實現(xiàn)步驟:
定義JDK動態(tài)代理類
實現(xiàn) InvocationHandler?接口
package com.example.aop.proxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class JDKInvocationHandler implements InvocationHandler {private Object target; //目標對象public JDKInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("我是代理, 開始代理");//通過反射, 調用目標對象的方法Object result = method.invoke(target, args);System.out.println("我是代理, 結束代理");return result;}
}
創(chuàng)建一個代理對象并使用:
import java.lang.reflect.Proxy;public class Main {public static void main(String[] args) {//JDK動態(tài)代理/*** public static Object newProxyInstance(ClassLoader loader,* Class<?>[] interfaces,* InvocationHandler h) {* loader: 加載我們代理類的classload* interfaces: 要實現(xiàn)的接口* h: 代理要做的事情, 需要實現(xiàn) InvocationHandler 這個接口*///目標對象RealHouseSubject target = new RealHouseSubject();//動態(tài)生成代理對象HouseSubject proxy = (HouseSubject) Proxy.newProxyInstance(target.getClass().getClassLoader(),new Class[] {HouseSubject.class},new JDKInvocationHandler(target));proxy.rentHouse();proxy.saleHouse();}
}
JDK動態(tài)代理只能代理接口, 不能代理類:
運行成功
?運行失敗
CGLIB動態(tài)代理
JDK 動態(tài)代理有一個最致命的問題是其只能代理實現(xiàn)了接口的類
有些場景下,我們的業(yè)務代碼是直接實現(xiàn)的,并沒有接口定義,為了解決這個問題,我們可以用 CGLIB 動態(tài)代理機制來解決.
CGLIB(Code Generation Library)是一個基于ASM的字節(jié)碼生成庫,它允許我們在運行時對字節(jié)碼進行修改和動態(tài)生成.? CGLIB 通過繼承方式實現(xiàn)代理,很多知名的開源框架都使用到了CGLIB.
例如 Spring中的 AOP 模塊中: 如果目標對象實現(xiàn)了接口,則默認采用 JDK動態(tài)代理, 否則采用 CGLIB 動態(tài)代理.
CGLIB 動態(tài)代理類實現(xiàn)步驟
?添加依賴
和JDK動態(tài)代理不同, CGLlB(Code Generation Library) 實際是屬于一個開源項目,如果你要使用它的話,需要手動添加相關依賴
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>
自定義 MethodInterceptor(方法攔截器)
實現(xiàn)MethodInterceptor接
package com.example.aop.proxy;import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class CGLibMethodInterceptor implements MethodInterceptor {private Object target;public CGLibMethodInterceptor(Object target) {this.target = target;}/*** 調用代理對象*/@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("我是中介, 開始代理");Object result = method.invoke(target, args);System.out.println("我是中介, 結束代理");return result;}
}
創(chuàng)建代理類,并使用
package com.example.aop.proxy;import org.springframework.cglib.proxy.Enhancer;public class Main {public static void main(String[] args) {//使用CGLib完成代理//代理接口, 運行成功HouseSubject target = new RealHouseSubject();HouseSubject houseSubject = (HouseSubject) Enhancer.create(target.getClass(), new CGLibMethodInterceptor(target));houseSubject.saleHouse();houseSubject.rentHouse();System.out.println("====================");//代理類, 運行成功RealHouseSubject realHouseSubject = (RealHouseSubject) Enhancer.create(target.getClass(), new CGLibMethodInterceptor(target));realHouseSubject.saleHouse();realHouseSubject.rentHouse();}
}
CGLIB既可以代理接口, 又可以代理類:?
代碼簡單講解
1. Methodinterceptor
MethodInterceptor 和 JDK動態(tài)代理中的 InvocationHandler?類似,它只定義了一個方法 intercept(),用于增強目標方法,
public interface MethodInterceptor extends Callback {/*** 參數(shù)說明: * o: 被代理的對象 * method: ?標?法(被攔截的?法, 也就是需要增強的?法) * objects: ?法?參 * methodProxy: ?于調?原始?法 */Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable;
}
2. Enhancer.create()
Enhancer.create()用來生成一個代理對象
public static Object create(Class type, Callback callback) {//...代碼省略
}
參數(shù)說明:
type: 被代理類的類型(類或接口)
callback: 自定義方法攔截器 MethodInterceptor
JDK動態(tài)代理和CGLIB動態(tài)代理的區(qū)別
JDK 可以代理接口, 不可以代理類
CGLib 既可以代理接口, 又可以代理類
JDK 動態(tài)代理是 Java 標準庫的一部分,不需要額外的依賴。只要使用的是 Java 開發(fā)環(huán)境,就可以直接使用 JDK 動態(tài)代理
CGLIB 是一個第三方庫,需要在項目中添加相應的依賴才能使用。
2. SpringAOP 源碼閱讀
SpringAOP 主要基于兩種方式實現(xiàn)的: JDK及 CGLIB 的方式
生成代理對象的邏輯在父類 AbstractAutoProxyCreator 中
Spring 對于 AOP 的實現(xiàn),基本上都是靠? AnnotationAwareAspectJAutoProxyCreator 去完成
/*** {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation* that wraps each eligible bean with an AOP proxy, delegating to specified interceptors* before invoking the bean itself.** <p>This class distinguishes between "common" interceptors: shared for all proxies it* creates, and "specific" interceptors: unique per bean instance. There need not be any* common interceptors. If there are, they are set using the interceptorNames property.* As with {@link org.springframework.aop.framework.ProxyFactoryBean}, interceptors names* in the current factory are used rather than bean references to allow correct handling* of prototype advisors and interceptors: for example, to support stateful mixins.* Any advice type is supported for {@link #setInterceptorNames "interceptorNames"} entries.** <p>Such auto-proxying is particularly useful if there's a large number of beans that* need to be wrapped with similar proxies, i.e. delegating to the same interceptors.* Instead of x repetitive proxy definitions for x target beans, you can register* one single such post processor with the bean factory to achieve the same effect.** <p>Subclasses can apply any strategy to decide if a bean is to be proxied, e.g. by type,* by name, by definition details, etc. They can also return additional interceptors that* should just be applied to the specific bean instance. A simple concrete implementation is* {@link BeanNameAutoProxyCreator}, identifying the beans to be proxied via given names.** <p>Any number of {@link TargetSourceCreator} implementations can be used to create* a custom target source: for example, to pool prototype objects. Auto-proxying will* occur even if there is no advice, as long as a TargetSourceCreator specifies a custom* {@link org.springframework.aop.TargetSource}. If there are no TargetSourceCreators set,* or if none matches, a {@link org.springframework.aop.target.SingletonTargetSource}* will be used by default to wrap the target bean instance.** @author Juergen Hoeller* @author Rod Johnson* @author Rob Harrop* @author Sam Brannen* @since 13.10.2003* @see #setInterceptorNames* @see #getAdvicesAndAdvisorsForBean* @see BeanNameAutoProxyCreator* @see DefaultAdvisorAutoProxyCreator*/
@SuppressWarnings("serial")
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupportimplements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {/*** Convenience constant for subclasses: Return value for "do not proxy".* @see #getAdvicesAndAdvisorsForBean*/@Nullableprotected static final Object[] DO_NOT_PROXY = null;/*** Convenience constant for subclasses: Return value for* "proxy without additional interceptors, just the common ones".* @see #getAdvicesAndAdvisorsForBean*/protected static final Object[] PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS = new Object[0];/** Logger available to subclasses. */protected final Log logger = LogFactory.getLog(getClass());/** Default is global AdvisorAdapterRegistry. */private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();/*** Indicates whether the proxy should be frozen. Overridden from super* to prevent the configuration from becoming frozen too early.*/private boolean freezeProxy = false;/** Default is no common interceptors. */private String[] interceptorNames = new String[0];private boolean applyCommonInterceptorsFirst = true;@Nullableprivate TargetSourceCreator[] customTargetSourceCreators;@Nullableprivate BeanFactory beanFactory;private final Set<String> targetSourcedBeans = Collections.newSetFromMap(new ConcurrentHashMap<>(16));private final Map<Object, Object> earlyBeanReferences = new ConcurrentHashMap<>(16);private final Map<Object, Class<?>> proxyTypes = new ConcurrentHashMap<>(16);private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>(256);/*** Set whether the proxy should be frozen, preventing advice* from being added to it once it is created.* <p>Overridden from the superclass to prevent the proxy configuration* from being frozen before the proxy is created.*/@Overridepublic void setFrozen(boolean frozen) {this.freezeProxy = frozen;}@Overridepublic boolean isFrozen() {return this.freezeProxy;}/*** Specify the {@link AdvisorAdapterRegistry} to use.* <p>Default is the global {@link AdvisorAdapterRegistry}.* @see org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry*/public void setAdvisorAdapterRegistry(AdvisorAdapterRegistry advisorAdapterRegistry) {this.advisorAdapterRegistry = advisorAdapterRegistry;}/*** Set custom {@code TargetSourceCreators} to be applied in this order.* If the list is empty, or they all return null, a {@link SingletonTargetSource}* will be created for each bean.* <p>Note that TargetSourceCreators will kick in even for target beans* where no advices or advisors have been found. If a {@code TargetSourceCreator}* returns a {@link TargetSource} for a specific bean, that bean will be proxied* in any case.* <p>{@code TargetSourceCreators} can only be invoked if this post processor is used* in a {@link BeanFactory} and its {@link BeanFactoryAware} callback is triggered.* @param targetSourceCreators the list of {@code TargetSourceCreators}.* Ordering is significant: The {@code TargetSource} returned from the first matching* {@code TargetSourceCreator} (that is, the first that returns non-null) will be used.*/public void setCustomTargetSourceCreators(TargetSourceCreator... targetSourceCreators) {this.customTargetSourceCreators = targetSourceCreators;}/*** Set the common interceptors. These must be bean names in the current factory.* They can be of any advice or advisor type Spring supports.* <p>If this property isn't set, there will be zero common interceptors.* This is perfectly valid, if "specific" interceptors such as matching* Advisors are all we want.*/public void setInterceptorNames(String... interceptorNames) {this.interceptorNames = interceptorNames;}/*** Set whether the common interceptors should be applied before bean-specific ones.* Default is "true"; else, bean-specific interceptors will get applied first.*/public void setApplyCommonInterceptorsFirst(boolean applyCommonInterceptorsFirst) {this.applyCommonInterceptorsFirst = applyCommonInterceptorsFirst;}@Overridepublic void setBeanFactory(BeanFactory beanFactory) {this.beanFactory = beanFactory;}/*** Return the owning {@link BeanFactory}.* May be {@code null}, as this post-processor doesn't need to belong to a bean factory.*/@Nullableprotected BeanFactory getBeanFactory() {return this.beanFactory;}@Override@Nullablepublic Class<?> predictBeanType(Class<?> beanClass, String beanName) {if (this.proxyTypes.isEmpty()) {return null;}Object cacheKey = getCacheKey(beanClass, beanName);return this.proxyTypes.get(cacheKey);}@Overridepublic Class<?> determineBeanType(Class<?> beanClass, String beanName) {Object cacheKey = getCacheKey(beanClass, beanName);Class<?> proxyType = this.proxyTypes.get(cacheKey);if (proxyType == null) {TargetSource targetSource = getCustomTargetSource(beanClass, beanName);if (targetSource != null) {if (StringUtils.hasLength(beanName)) {this.targetSourcedBeans.add(beanName);}}else {targetSource = EmptyTargetSource.forClass(beanClass);}Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);if (specificInterceptors != DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);proxyType = createProxyClass(beanClass, beanName, specificInterceptors, targetSource);this.proxyTypes.put(cacheKey, proxyType);}}return (proxyType != null ? proxyType : beanClass);}@Override@Nullablepublic Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) {return null;}@Overridepublic Object getEarlyBeanReference(Object bean, String beanName) {Object cacheKey = getCacheKey(bean.getClass(), beanName);this.earlyBeanReferences.put(cacheKey, bean);return wrapIfNecessary(bean, beanName, cacheKey);}@Override@Nullablepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {Object cacheKey = getCacheKey(beanClass, beanName);if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {if (this.advisedBeans.containsKey(cacheKey)) {return null;}if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return null;}}// Create proxy here if we have a custom TargetSource.// Suppresses unnecessary default instantiation of the target bean:// The TargetSource will handle target instances in a custom fashion.TargetSource targetSource = getCustomTargetSource(beanClass, beanName);if (targetSource != null) {if (StringUtils.hasLength(beanName)) {this.targetSourcedBeans.add(beanName);}Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}return null;}@Overridepublic PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {return pvs; // skip postProcessPropertyValues}/*** Create a proxy with the configured interceptors if the bean is* identified as one to proxy by the subclass.* @see #getAdvicesAndAdvisorsForBean*/@Override@Nullablepublic Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);if (this.earlyBeanReferences.remove(cacheKey) != bean) {return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;}/*** Build a cache key for the given bean class and bean name.* <p>Note: As of 4.2.3, this implementation does not return a concatenated* class/name String anymore but rather the most efficient cache key possible:* a plain bean name, prepended with {@link BeanFactory#FACTORY_BEAN_PREFIX}* in case of a {@code FactoryBean}; or if no bean name specified, then the* given bean {@code Class} as-is.* @param beanClass the bean class* @param beanName the bean name* @return the cache key for the given class and name*/protected Object getCacheKey(Class<?> beanClass, @Nullable String beanName) {if (StringUtils.hasLength(beanName)) {return (FactoryBean.class.isAssignableFrom(beanClass) ?BeanFactory.FACTORY_BEAN_PREFIX + beanName : beanName);}else {return beanClass;}}/*** Wrap the given bean if necessary, i.e. if it is eligible for being proxied.* @param bean the raw bean instance* @param beanName the name of the bean* @param cacheKey the cache key for metadata access* @return a proxy wrapping the bean, or the raw bean instance as-is*/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.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;}/*** Return whether the given bean class represents an infrastructure class* that should never be proxied.* <p>The default implementation considers Advices, Advisors and* AopInfrastructureBeans as infrastructure classes.* @param beanClass the class of the bean* @return whether the bean represents an infrastructure class* @see org.aopalliance.aop.Advice* @see org.springframework.aop.Advisor* @see org.springframework.aop.framework.AopInfrastructureBean* @see #shouldSkip*/protected boolean isInfrastructureClass(Class<?> beanClass) {boolean retVal = Advice.class.isAssignableFrom(beanClass) ||Pointcut.class.isAssignableFrom(beanClass) ||Advisor.class.isAssignableFrom(beanClass) ||AopInfrastructureBean.class.isAssignableFrom(beanClass);if (retVal && logger.isTraceEnabled()) {logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]");}return retVal;}/*** Subclasses should override this method to return {@code true} if the* given bean should not be considered for auto-proxying by this post-processor.* <p>Sometimes we need to be able to avoid this happening, e.g. if it will lead to* a circular reference or if the existing target instance needs to be preserved.* This implementation returns {@code false} unless the bean name indicates an* "original instance" according to {@code AutowireCapableBeanFactory} conventions.* @param beanClass the class of the bean* @param beanName the name of the bean* @return whether to skip the given bean* @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#ORIGINAL_INSTANCE_SUFFIX*/protected boolean shouldSkip(Class<?> beanClass, String beanName) {return AutoProxyUtils.isOriginalInstance(beanName, beanClass);}/*** Create a target source for bean instances. Uses any TargetSourceCreators if set.* Returns {@code null} if no custom TargetSource should be used.* <p>This implementation uses the "customTargetSourceCreators" property.* Subclasses can override this method to use a different mechanism.* @param beanClass the class of the bean to create a TargetSource for* @param beanName the name of the bean* @return a TargetSource for this bean* @see #setCustomTargetSourceCreators*/@Nullableprotected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) {// We can't create fancy target sources for directly registered singletons.if (this.customTargetSourceCreators != null &&this.beanFactory != null && this.beanFactory.containsBean(beanName)) {for (TargetSourceCreator tsc : this.customTargetSourceCreators) {TargetSource ts = tsc.getTargetSource(beanClass, beanName);if (ts != null) {// Found a matching TargetSource.if (logger.isTraceEnabled()) {logger.trace("TargetSourceCreator [" + tsc +"] found custom TargetSource for bean with name '" + beanName + "'");}return ts;}}}// No custom TargetSource found.return null;}/*** Create an AOP proxy for the given bean.* @param beanClass the class of the bean* @param beanName the name of the bean* @param specificInterceptors the set of interceptors that is* specific to this bean (may be empty, but not null)* @param targetSource the TargetSource for the proxy,* already pre-configured to access the bean* @return the AOP proxy for the bean* @see #buildAdvisors*/protected Object createProxy(Class<?> beanClass, @Nullable String beanName,@Nullable Object[] specificInterceptors, TargetSource targetSource) {return buildProxy(beanClass, beanName, specificInterceptors, targetSource, false);}private Class<?> createProxyClass(Class<?> beanClass, @Nullable String beanName,@Nullable Object[] specificInterceptors, TargetSource targetSource) {return (Class<?>) buildProxy(beanClass, beanName, specificInterceptors, targetSource, true);}private Object buildProxy(Class<?> beanClass, @Nullable String beanName,@Nullable Object[] specificInterceptors, TargetSource targetSource, boolean classOnly) {if (this.beanFactory instanceof ConfigurableListableBeanFactory clbf) {AutoProxyUtils.exposeTargetClass(clbf, beanName, beanClass);}ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.copyFrom(this);if (proxyFactory.isProxyTargetClass()) {// Explicit handling of JDK proxy targets and lambdas (for introduction advice scenarios)if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.for (Class<?> ifc : beanClass.getInterfaces()) {proxyFactory.addInterface(ifc);}}}else {// No proxyTargetClass flag enforced, let's apply our default checks...if (shouldProxyTargetClass(beanClass, beanName)) {proxyFactory.setProxyTargetClass(true);}else {evaluateProxyInterfaces(beanClass, proxyFactory);}}Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);proxyFactory.addAdvisors(advisors);proxyFactory.setTargetSource(targetSource);customizeProxyFactory(proxyFactory);proxyFactory.setFrozen(this.freezeProxy);if (advisorsPreFiltered()) {proxyFactory.setPreFiltered(true);}// Use original ClassLoader if bean class not locally loaded in overriding class loaderClassLoader classLoader = getProxyClassLoader();if (classLoader instanceof SmartClassLoader smartClassLoader && classLoader != beanClass.getClassLoader()) {classLoader = smartClassLoader.getOriginalClassLoader();}return (classOnly ? proxyFactory.getProxyClass(classLoader) : proxyFactory.getProxy(classLoader));}/*** Determine whether the given bean should be proxied with its target class rather than its interfaces.* <p>Checks the {@link AutoProxyUtils#PRESERVE_TARGET_CLASS_ATTRIBUTE "preserveTargetClass" attribute}* of the corresponding bean definition.* @param beanClass the class of the bean* @param beanName the name of the bean* @return whether the given bean should be proxied with its target class* @see AutoProxyUtils#shouldProxyTargetClass*/protected boolean shouldProxyTargetClass(Class<?> beanClass, @Nullable String beanName) {return (this.beanFactory instanceof ConfigurableListableBeanFactory clbf &&AutoProxyUtils.shouldProxyTargetClass(clbf, beanName));}/*** Return whether the Advisors returned by the subclass are pre-filtered* to match the bean's target class already, allowing the ClassFilter check* to be skipped when building advisors chains for AOP invocations.* <p>Default is {@code false}. Subclasses may override this if they* will always return pre-filtered Advisors.* @return whether the Advisors are pre-filtered* @see #getAdvicesAndAdvisorsForBean* @see org.springframework.aop.framework.Advised#setPreFiltered*/protected boolean advisorsPreFiltered() {return false;}/*** Determine the advisors for the given bean, including the specific interceptors* as well as the common interceptor, all adapted to the Advisor interface.* @param beanName the name of the bean* @param specificInterceptors the set of interceptors that is* specific to this bean (may be empty, but not null)* @return the list of Advisors for the given bean*/protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {// Handle prototypes correctly...Advisor[] commonInterceptors = resolveInterceptorNames();List<Object> allInterceptors = new ArrayList<>();if (specificInterceptors != null) {if (specificInterceptors.length > 0) {// specificInterceptors may equal PROXY_WITHOUT_ADDITIONAL_INTERCEPTORSallInterceptors.addAll(Arrays.asList(specificInterceptors));}if (commonInterceptors.length > 0) {if (this.applyCommonInterceptorsFirst) {allInterceptors.addAll(0, Arrays.asList(commonInterceptors));}else {allInterceptors.addAll(Arrays.asList(commonInterceptors));}}}if (logger.isTraceEnabled()) {int nrOfCommonInterceptors = commonInterceptors.length;int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.length : 0);logger.trace("Creating implicit proxy for bean '" + beanName + "' with " + nrOfCommonInterceptors +" common interceptors and " + nrOfSpecificInterceptors + " specific interceptors");}Advisor[] advisors = new Advisor[allInterceptors.size()];for (int i = 0; i < allInterceptors.size(); i++) {advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));}return advisors;}/*** Resolves the specified interceptor names to Advisor objects.* @see #setInterceptorNames*/private Advisor[] resolveInterceptorNames() {BeanFactory bf = this.beanFactory;ConfigurableBeanFactory cbf = (bf instanceof ConfigurableBeanFactory _cbf ? _cbf : null);List<Advisor> advisors = new ArrayList<>();for (String beanName : this.interceptorNames) {if (cbf == null || !cbf.isCurrentlyInCreation(beanName)) {Assert.state(bf != null, "BeanFactory required for resolving interceptor names");Object next = bf.getBean(beanName);advisors.add(this.advisorAdapterRegistry.wrap(next));}}return advisors.toArray(new Advisor[0]);}/*** Subclasses may choose to implement this: for example,* to change the interfaces exposed.* <p>The default implementation is empty.* @param proxyFactory a ProxyFactory that is already configured with* TargetSource and interfaces and will be used to create the proxy* immediately after this method returns*/protected void customizeProxyFactory(ProxyFactory proxyFactory) {}/*** Return whether the given bean is to be proxied, what additional* advices (e.g. AOP Alliance interceptors) and advisors to apply.* @param beanClass the class of the bean to advise* @param beanName the name of the bean* @param customTargetSource the TargetSource returned by the* {@link #getCustomTargetSource} method: may be ignored.* Will be {@code null} if no custom target source is in use.* @return an array of additional interceptors for the particular bean;* or an empty array if no additional interceptors but just the common ones;* or {@code null} if no proxy at all, not even with the common interceptors.* See constants DO_NOT_PROXY and PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS.* @throws BeansException in case of errors* @see #DO_NOT_PROXY* @see #PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS*/@Nullableprotected abstract Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName,@Nullable TargetSource customTargetSource) throws BeansException;}
代理工廠有一個重要的屬性: proxyTargetClass,默認值為false.也可以通過程序設置
Spring Boot 2.X開始,默認使用CGLIB代理
可以通過配置項 spring.aop.proxy-target-class=false 來進行修改, 設置默認為jdk代理
SpringBoot設置 @EnableAspectJAutoProxy 無效, 因為Spring Boot 默認使用
AopAutoConfiguration 進行裝配
我看點進去看代理??的代碼
/*** Factory for AOP proxies for programmatic use, rather than via declarative* setup in a bean factory. This class provides a simple way of obtaining* and configuring AOP proxy instances in custom user code.** @author Rod Johnson* @author Juergen Hoeller* @author Rob Harrop* @since 14.03.2003*/
@SuppressWarnings("serial")
public class ProxyFactory extends ProxyCreatorSupport {/*** Create a new ProxyFactory.*/public ProxyFactory() {}/*** Create a new ProxyFactory.* <p>Will proxy all interfaces that the given target implements.* @param target the target object to be proxied*/public ProxyFactory(Object target) {setTarget(target);setInterfaces(ClassUtils.getAllInterfaces(target));}/*** Create a new ProxyFactory.* <p>No target, only interfaces. Must add interceptors.* @param proxyInterfaces the interfaces that the proxy should implement*/public ProxyFactory(Class<?>... proxyInterfaces) {setInterfaces(proxyInterfaces);}/*** Create a new ProxyFactory for the given interface and interceptor.* <p>Convenience method for creating a proxy for a single interceptor,* assuming that the interceptor handles all calls itself rather than* delegating to a target, like in the case of remoting proxies.* @param proxyInterface the interface that the proxy should implement* @param interceptor the interceptor that the proxy should invoke*/public ProxyFactory(Class<?> proxyInterface, Interceptor interceptor) {addInterface(proxyInterface);addAdvice(interceptor);}/*** Create a ProxyFactory for the specified {@code TargetSource},* making the proxy implement the specified interface.* @param proxyInterface the interface that the proxy should implement* @param targetSource the TargetSource that the proxy should invoke*/public ProxyFactory(Class<?> proxyInterface, TargetSource targetSource) {addInterface(proxyInterface);setTargetSource(targetSource);}/*** Create a new proxy according to the settings in this factory.* <p>Can be called repeatedly. Effect will vary if we've added* or removed interfaces. Can add and remove interceptors.* <p>Uses a default class loader: Usually, the thread context class loader* (if necessary for proxy creation).* @return the proxy object*/public Object getProxy() {return createAopProxy().getProxy();}/*** Create a new proxy according to the settings in this factory.* <p>Can be called repeatedly. Effect will vary if we've added* or removed interfaces. Can add and remove interceptors.* <p>Uses the given class loader (if necessary for proxy creation).* @param classLoader the class loader to create the proxy with* (or {@code null} for the low-level proxy facility's default)* @return the proxy object*/public Object getProxy(@Nullable ClassLoader classLoader) {return createAopProxy().getProxy(classLoader);}/*** Determine the proxy class according to the settings in this factory.* @param classLoader the class loader to create the proxy class with* (or {@code null} for the low-level proxy facility's default)* @return the proxy class* @since 6.0*/public Class<?> getProxyClass(@Nullable ClassLoader classLoader) {return createAopProxy().getProxyClass(classLoader);}/*** Create a new proxy for the given interface and interceptor.* <p>Convenience method for creating a proxy for a single interceptor,* assuming that the interceptor handles all calls itself rather than* delegating to a target, like in the case of remoting proxies.* @param proxyInterface the interface that the proxy should implement* @param interceptor the interceptor that the proxy should invoke* @return the proxy object* @see #ProxyFactory(Class, org.aopalliance.intercept.Interceptor)*/@SuppressWarnings("unchecked")public static <T> T getProxy(Class<T> proxyInterface, Interceptor interceptor) {return (T) new ProxyFactory(proxyInterface, interceptor).getProxy();}/*** Create a proxy for the specified {@code TargetSource},* implementing the specified interface.* @param proxyInterface the interface that the proxy should implement* @param targetSource the TargetSource that the proxy should invoke* @return the proxy object* @see #ProxyFactory(Class, org.springframework.aop.TargetSource)*/@SuppressWarnings("unchecked")public static <T> T getProxy(Class<T> proxyInterface, TargetSource targetSource) {return (T) new ProxyFactory(proxyInterface, targetSource).getProxy();}/*** Create a proxy for the specified {@code TargetSource} that extends* the target class of the {@code TargetSource}.* @param targetSource the TargetSource that the proxy should invoke* @return the proxy object*/public static Object getProxy(TargetSource targetSource) {if (targetSource.getTargetClass() == null) {throw new IllegalArgumentException("Cannot create class proxy for TargetSource with null target class");}ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.setTargetSource(targetSource);proxyFactory.setProxyTargetClass(true);return proxyFactory.getProxy();}}
createAopProxy的實現(xiàn)在 DefaultAopProxyFactory中
/*** Default {@link AopProxyFactory} implementation, creating either a CGLIB proxy* or a JDK dynamic proxy.** <p>Creates a CGLIB proxy if one the following is true for a given* {@link AdvisedSupport} instance:* <ul>* <li>the {@code optimize} flag is set* <li>the {@code proxyTargetClass} flag is set* <li>no proxy interfaces have been specified* </ul>** <p>In general, specify {@code proxyTargetClass} to enforce a CGLIB proxy,* or specify one or more interfaces to use a JDK dynamic proxy.** @author Rod Johnson* @author Juergen Hoeller* @author Sebastien Deleuze* @author Sam Brannen* @since 12.03.2004* @see AdvisedSupport#setOptimize* @see AdvisedSupport#setProxyTargetClass* @see AdvisedSupport#setInterfaces*/
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {/*** Singleton instance of this class.* @since 6.0.10*/public static final DefaultAopProxyFactory INSTANCE = new DefaultAopProxyFactory();private static final long serialVersionUID = 7930414337282325166L;@Overridepublic AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {Class<?> targetClass = config.getTargetClass();if (targetClass == null) {throw new AopConfigException("TargetSource cannot determine target class: " +"Either an interface or a target is required for proxy creation.");}if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {return new JdkDynamicAopProxy(config);}return new ObjenesisCglibAopProxy(config);}else {return new JdkDynamicAopProxy(config);}}/*** Determine whether the supplied {@link AdvisedSupport} has only the* {@link org.springframework.aop.SpringProxy} interface specified* (or no proxy interfaces specified at all).*/private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {Class<?>[] ifcs = config.getProxiedInterfaces();return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));}}
接下來就是創(chuàng)建代理了
JDK動態(tài)代理
CGLIB動態(tài)代理
CglibAopProxy類中:
@Overridepublic Object getProxy(@Nullable ClassLoader classLoader) {return buildProxy(classLoader, false);}@Overridepublic Class<?> getProxyClass(@Nullable ClassLoader classLoader) {return (Class<?>) buildProxy(classLoader, true);}private Object buildProxy(@Nullable ClassLoader classLoader, boolean classOnly) {if (logger.isTraceEnabled()) {logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());}try {Class<?> rootClass = this.advised.getTargetClass();Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");Class<?> proxySuperClass = rootClass;if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {proxySuperClass = rootClass.getSuperclass();Class<?>[] additionalInterfaces = rootClass.getInterfaces();for (Class<?> additionalInterface : additionalInterfaces) {this.advised.addInterface(additionalInterface);}}// Validate the class, writing log messages as necessary.validateClassIfNecessary(proxySuperClass, classLoader);// Configure CGLIB Enhancer...Enhancer enhancer = createEnhancer();if (classLoader != null) {enhancer.setClassLoader(classLoader);if (classLoader instanceof SmartClassLoader smartClassLoader &&smartClassLoader.isClassReloadable(proxySuperClass)) {enhancer.setUseCache(false);}}enhancer.setSuperclass(proxySuperClass);enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);enhancer.setAttemptLoad(true);enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(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 aboveProxyCallbackFilter filter = new ProxyCallbackFilter(this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset);enhancer.setCallbackFilter(filter);enhancer.setCallbackTypes(types);// Generate the proxy class and create a proxy instance.// ProxyCallbackFilter has method introspection capability with Advisor access.try {return (classOnly ? createProxyClass(enhancer) : createProxyClassAndInstance(enhancer, callbacks));}finally {// Reduce ProxyCallbackFilter to key-only state for its class cache role// in the CGLIB$CALLBACK_FILTER field, not leaking any Advisor state...filter.advised.reduceToAdvisorKey();}}catch (CodeGenerationException | IllegalArgumentException ex) {throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +": Common causes of this problem include using a final class or a non-visible class",ex);}catch (Throwable ex) {// TargetSource.getTarget() failedthrow new AopConfigException("Unexpected AOP exception", ex);}}
回顧:
1.什么是AOP
2.SpringAOP 的實現(xiàn)方式有哪些?
3.SpringAOP 的實現(xiàn)原理 (基于動態(tài)代理 1.JDK 2.CGLib)
4. Spring 使用的是那種代理方式?
Spring?默認 proxyTargetClass 值為false, 如果實現(xiàn)了接口, 使用JDK代理, 如果是普通類則使用CGLib代理
SpringBoot從2.x之后, proxyTargetClass值為true, 默認是使用CGLib代理
5. JDK動態(tài)代理和CGLib動態(tài)代理的區(qū)別?
總結?