spring aop底層原理及如何實(shí)現(xiàn)
前言
相信每天工作都要用spring框架的大家一定使用過spring aop,aop的概念是面向切面編程,相對(duì)與傳統(tǒng)的面向?qū)ο缶幊蘯op,aop更關(guān)注的是橫向的邏輯,比如說一個(gè)大型系統(tǒng)中的日志記錄,異常處理,性能監(jiān)控等等,都是各個(gè)模塊都需要的操作,那樣代表著這些操作會(huì)散落在系統(tǒng)的各個(gè)地方,不易管理且雜亂無章,而aop就是關(guān)注的這些,aop將這些操作與業(yè)務(wù)代碼分離,統(tǒng)一成一個(gè)個(gè)的切面,針對(duì)這些個(gè)切面進(jìn)行編程處理。spring aop使得我們的aop開發(fā)工作變得簡單,這次我就給大家講講spring aop的底層原理和實(shí)現(xiàn)
使用
要分析spring aop的底層原理,首先要會(huì)使用,先創(chuàng)建一個(gè)普通maven webapp項(xiàng)目,引入spring-context依賴,版本為5.1.1RELEASE
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.1.RELEASE</version>
</dependency>
然后我使用aspectj作為aop的語法實(shí)現(xiàn),和spring整合起來
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
接下來我全稱用注解的形式來模擬spring aop的使用,先創(chuàng)建一個(gè)配置類去掃描包,開啟aspectJ的自動(dòng)代理支持
@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.ww")
public class Wconfig {
}
然后新建一個(gè)接口和接口的實(shí)現(xiàn)類
public interface Dao {
void query();
}
@Component
public class IndexDao implements Dao{
@Override
public void query() {
System.out.println("query......");
}
}
創(chuàng)建切面
//代表是一個(gè)切面
@Aspect
@Component
public class WAspect {
/**
* execution表達(dá)式,可以百度寫法
*/
@Pointcut("execution(* com.ww.dao.*.*(..))")
public void point(){
}
/**
* 在切點(diǎn)上進(jìn)行前置通知
*/
@Before("point()")
public void beforeAd(){
System.out.println("before-------------");
}
}
創(chuàng)建測試方法
public class TestAspect {
public static void main(String[] args) {
AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext(Wconfig.class);
Dao dao = configApplicationContext.getBean(Dao.class);
dao.query();
}
}
執(zhí)行方法,可以看到在打印query...之前打印了before----------

這個(gè)時(shí)候我們很想知道為什么這句before會(huì)打印在query之前呢,稍微對(duì)spring aop有所了解的人應(yīng)該知道,spring是通過動(dòng)態(tài)代理和字節(jié)碼技術(shù)來實(shí)現(xiàn)aop操作的,也就是經(jīng)常說的jdk動(dòng)態(tài)代理和cglib動(dòng)態(tài)代理兩種模式,那么,spring究竟是怎么創(chuàng)建的代理對(duì)象,又是什么時(shí)候產(chǎn)生的代理對(duì)象呢,下面我們來一起探究一下源碼,來揭開這個(gè)謎底
源碼分析
首先我們透過現(xiàn)象看本質(zhì),我先把斷點(diǎn)打在測試方法的最后一行,我們來看這個(gè)時(shí)候的dao對(duì)象

那么接下來我們就要去找到什么時(shí)候這個(gè)dao對(duì)象變成了動(dòng)態(tài)代理對(duì)象的,既然在最后一行的時(shí)候?qū)ο笠呀?jīng)變成了代理對(duì)象,那么我門自然就猜想是在上一句代碼的位置spring執(zhí)行了創(chuàng)建代理對(duì)象的操作,我們把斷點(diǎn)移到上一行,debug進(jìn)去

再往下走

這行代碼我看方法名覺得應(yīng)該是有用的代碼,方法意思應(yīng)該是spring處理好的bean,跟進(jìn)去看看
@Nullable
private <T> T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {
//這行代碼最有用,處理有beanName的bean,debug進(jìn)入看一下
NamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull);
if (namedBean != null) {
return namedBean.getBeanInstance();
}
BeanFactory parent = getParentBeanFactory();
if (parent instanceof DefaultListableBeanFactory) {
return ((DefaultListableBeanFactory) parent).resolveBean(requiredType, args, nonUniqueAsNull);
}
else if (parent != null) {
ObjectProvider<T> parentProvider = parent.getBeanProvider(requiredType);
if (args != null) {
return parentProvider.getObject(args);
}
else {
return (nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable());
}
}
return null;
}
@SuppressWarnings("unchecked")
@Nullable
private <T> NamedBeanHolder<T> resolveNamedBean(
ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {
Assert.notNull(requiredType, "Required type must not be null");
Class<?> clazz = requiredType.getRawClass();
Assert.notNull(clazz, "Required type must have a raw Class");
//候選name列表,直覺告訴我這行代碼比較重要
String[] candidateNames = getBeanNamesForType(requiredType);
if (candidateNames.length > 1) {
List<String> autowireCandidates = new ArrayList<>(candidateNames.length);
for (String beanName : candidateNames) {
if (!containsBeanDefinition(beanName) || getBeanDefinition(beanName).isAutowireCandidate()) {
autowireCandidates.add(beanName);
}
}
if (!autowireCandidates.isEmpty()) {
candidateNames = StringUtils.toStringArray(autowireCandidates);
}
}
//因?yàn)槲业拇a里只有一個(gè)bean,所以我覺得應(yīng)該會(huì)執(zhí)行這里的代碼
if (candidateNames.length == 1) {
String beanName = candidateNames[0];
return new NamedBeanHolder<>(beanName, (T) getBean(beanName, clazz, args));
}
else if (candidateNames.length > 1) {
Map<String, Object> candidates = new LinkedHashMap<>(candidateNames.length);
for (String beanName : candidateNames) {
if (containsSingleton(beanName) && args == null) {
Object beanInstance = getBean(beanName);
candidates.put(beanName, (beanInstance instanceof NullBean ? null : beanInstance));
}
else {
candidates.put(beanName, getType(beanName));
}
}
String candidateName = determinePrimaryCandidate(candidates, clazz);
if (candidateName == null) {
candidateName = determineHighestPriorityCandidate(candidates, clazz);
}
if (candidateName != null) {
Object beanInstance = candidates.get(candidateName);
if (beanInstance == null || beanInstance instanceof Class) {
beanInstance = getBean(candidateName, clazz, args);
}
return new NamedBeanHolder<>(candidateName, (T) beanInstance);
}
if (!nonUniqueAsNull) {
throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
}
}
return null;
}
執(zhí)行完getBeanNamesForType(requiredType)后,我們看idea的變量顯示,果然有一個(gè)bean,name是IndexDao

那么接下來自然會(huì)進(jìn)到length==1的那個(gè)代碼塊,這時(shí)候我再debug進(jìn)入,這里還是一個(gè)getBean方法


在spring容器中還有一些沒有name的其他的bean需要被創(chuàng)建,所以這里我用上了條件斷點(diǎn),當(dāng)beanName等于indexDao的時(shí)候,才會(huì)進(jìn)入斷點(diǎn),但是當(dāng)我F8跑完這行代碼的時(shí)候,出乎意料的事情發(fā)生了

驚不驚喜,意不意外,getSingleton這行代碼執(zhí)行結(jié)束之后,代理對(duì)象就已經(jīng)被創(chuàng)建了,所以需要debug進(jìn)入這行代碼去看
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//spring所有的bean被放在ioc容器中的地方,就是這個(gè)singletonObjects,這是一個(gè)concorrentHashMap。
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
但是我在這里只看到了get方法,那么這些bean是什么時(shí)候放到singletonObjects里的呢,我來找找
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
在DefaultSingletonBeanRegistry注冊(cè)器中,我找到了singletonObjects.put方法,代表bean是這個(gè)時(shí)候被放到這個(gè)map里去的,接下來我在這行代碼上進(jìn)行條件斷點(diǎn),然后我們來看它的調(diào)用鏈,找出是什么時(shí)候執(zhí)行的addSingleton方法,其實(shí)從這個(gè)時(shí)候我已經(jīng)知道,斷點(diǎn)打在測試方法的倒數(shù)第二行是不對(duì)的,在getBean之前其實(shí)代理對(duì)象已經(jīng)產(chǎn)生了

// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
//創(chuàng)建bean,核心代碼
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
在createBean方法上,我也加上條件斷點(diǎn),然后debug進(jìn)入
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isTraceEnabled()) {
logger.trace("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// Make sure bean class is actually resolved at this point, and
// clone the bean definition in case of a dynamically resolved Class
// which cannot be stored in the shared merged bean definition.
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
//核心代碼,創(chuàng)建bean實(shí)例,需要斷點(diǎn)進(jìn)入
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// A previously detected exception with proper bean creation context already,
// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
接下來我debug進(jìn)入doCreateBean方法
debug跟進(jìn)initializeBean方法,條件斷點(diǎn)在兩個(gè)初始化處理器上,我隱約覺得代理對(duì)象就是從這兩個(gè)方法中產(chǎn)生的,我們拭目以待
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
//包裝的bean
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//執(zhí)行前置初始化beanPostProcessor處理器
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
//執(zhí)行初始化后的beanPostProcessor處理器
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
執(zhí)行完applyBeanPostProcessorsBeforeInitialization方法,這個(gè)時(shí)候我們看到warppedBean還是indexDao,并沒有產(chǎn)生代理對(duì)象

我猜想在下一個(gè)后置處理器中,代理對(duì)象將被創(chuàng)建,我debug進(jìn)去
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
//經(jīng)過處理器處理后的bean,我先看看有多少個(gè)處理器
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}

可以看到我的猜想被證明是正確的,運(yùn)行完這個(gè)后置處理器,代理對(duì)象就被創(chuàng)建出來了。 到了這里我們知道了代理對(duì)象是從哪里來的了,但是還是沒搞清楚代理對(duì)象是怎么創(chuàng)建出來的,這時(shí)候我們就需要debug進(jìn)入到這個(gè)處理器內(nèi)部去瞧瞧了。
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
//獲取緩存key,不重要
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
//重要方法,需要debug進(jìn)去看
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
于是乎我又進(jìn)到了wrapIfNecessary這個(gè)方法內(nèi)部
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.
//看到上面這行注釋,可以確定代理類就是從這里產(chǎn)生的,下面這個(gè)方法得到的都是一些包括切點(diǎn)信息,通知類型等等的信息
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
//顧名思義,創(chuàng)建代理,bebug進(jìn)入看看
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;
}
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
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);
}
//重要的地方在這里,代理對(duì)象是通過這個(gè)方法生成的
return proxyFactory.getProxy(getProxyClassLoader());
}
public Object getProxy(@Nullable ClassLoader classLoader) {
//debug進(jìn)去看看
return createAopProxy().getProxy(classLoader);
}
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
//同樣需要debug進(jìn)入看看
return getAopProxyFactory().createAopProxy(this);
}
我們看到這里有一個(gè)if語句,當(dāng)config中的isOptimize和isProxyTargetClass還有hasNoUserSuppliedProxyInterfaces三個(gè)判斷條件只要有一個(gè)滿足的話,spring就會(huì)選擇cglib的方式進(jìn)行動(dòng)態(tài)代理,而config中的兩個(gè)boolean變量的默認(rèn)值都是false,而我們的被代理對(duì)象又是實(shí)現(xiàn)接口的,所以spring會(huì)選擇jdk動(dòng)態(tài)代理的實(shí)現(xiàn)形式來完成動(dòng)態(tài)代理,當(dāng)然,我們也可以在這種情況下手動(dòng)的配置config值來讓spring選擇cglib作為動(dòng)態(tài)代理的實(shí)現(xiàn)方式,稍后我會(huì)演示
@Override
public 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)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
//現(xiàn)在知道為什么我們的代理類是動(dòng)態(tài)代理了嗎
return new JdkDynamicAopProxy(config);
}
}

總結(jié)
我以spring aop實(shí)現(xiàn)的調(diào)用鏈圖來結(jié)束這次的總結(jié)

以上就是spring aop底層原理及如何實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于spring aop原理及實(shí)現(xiàn)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
springboot讀取bootstrap配置及knife4j版本兼容性問題及解決
這篇文章主要介紹了springboot讀取bootstrap配置及knife4j版本兼容性問題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06
淺談什么是SpringBoot異常處理自動(dòng)配置的原理
今天給大家?guī)淼氖顷P(guān)于Java的相關(guān)知識(shí),文章圍繞著SpringBoot異常處理自動(dòng)配置展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06
Java實(shí)現(xiàn)的可選擇及拖拽圖片的面板功能【基于swing組件】
這篇文章主要介紹了Java實(shí)現(xiàn)的可選擇及拖拽圖片的面板功能,涉及java基于swing組件選擇與操作圖片元素的相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2018-01-01
Java的MyBatis框架中關(guān)鍵的XML字段映射的配置參數(shù)詳解
將XML文件的schema字段映射到數(shù)據(jù)庫的schema是我們操作數(shù)據(jù)庫的常用手段,這里我們就來整理一些Java的MyBatis框架中關(guān)鍵的XML字段映射的配置參數(shù)詳解,需要的朋友可以參考下2016-06-06
Spring接口版本控制方案及RequestMappingHandlerMapping接口介紹(最新推薦)
RequestMappingHandlerMapping接口是Spring MVC中的一個(gè)核心組件,負(fù)責(zé)處理請(qǐng)求映射和處理器的匹配這篇文章主要介紹了Spring接口版本控制方案及RequestMappingHandlerMapping接口介紹,需要的朋友可以參考下2024-07-07

