spring源碼分析之Aop

今天讀spring源碼,讀到aop相關內容,在此記錄一下,以便以後複習和查閱。

一、spring如何實現Aop

這裏簡單的說下原理,spring實例化bean要經歷一套完整的生命週期,在這個過程中會對要實例化的bean進行各種各樣的處理,例如先new對象、進行屬性注入、處理循環依賴、處理生命週期回調、實現Aop等等。這些操作實際都是通過spring的後置處理器,也就是通過BeanPostProcessor來完成的。

BeanPostProcessor的主要功能就是用來修改,對Bean做一系列處理用的。

這裏我們看下源碼。

注:

因爲spring源碼實在太深,這裏就省去中間步驟,直接找到對應的類和方法

這裏源主要看的spring常規情況下的AOP。還有spring循環依賴情況下的AOP,這裏暫不做分析,後續補充。

 

主要就是在類AbstractAutowireCapableBeanFactory的initializeBean方法中。

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);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			//執行spring當中的內置處理器---xxxPostProcessor---@PostConstruct 生命週期回調和InitMethod 時
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			//執行 InitializingBean 初始化 實現InitializingBean接口時
			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()) {
			//對 對象的初始化進行干預(將userService改變成爲代理對象 實現aop)
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

我們看到一行代碼,wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

 上面說的這行代碼,就是用來處理aop的。點進去,繼續看源碼。

我們可以看到,在這遍歷了被註冊進來的後置處理器,調用了每個BeanPostProcessor的postProcessAfterInitialization方法。

其中有一個後置處理器的這個方法,就處理了aop.我們debug打個斷點看一下。

@Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		//執行所有直接實現了BeanPostProcessor的實現類的postProcessAfterInitialization
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			//拿出所有的後置處理器,調用postProcessAfterInitialization方法
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

 

 

上圖中紅色矩形框內的後置處理器,就是用來處理實現SpringAop功能。 

接着說,那麼上面的後置處理器是哪裏來的呢?

 我這裏才用的是註解的方式,這裏用過一個註解。點進去看一下,就明白了。

 

 

 那麼接着說,spring做了哪些處理呢?

 spring實現aop主要通過兩種技術。

  • JDK動態代理
  • Cglib動態代理 

 

JDK動態代理就不多說了,這裏模擬下spring採用CGlib動態代理。 

因爲之前說到了,spring是通過後置處理器即實現BeanPostProcessor,調用applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName)。在裏面實現了aop.

我們也採用這樣的思路。

代碼測試:

package com.evan.config;

import com.evan.processor.CustomAopBeanPostProcessor;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

//配置類
@ComponentScan("com.evan")
@Configuration
@Import(CustomAopBeanPostProcessor.class)
public class MyConfig {
}
package com.evan.service;

import org.springframework.stereotype.Component;

/**
 * @ClassName UserService
 * @Description
 * @Author EvanWang
 * @Version 1.0.0
 * @Date 2019/11/1 12:09
 */
@Component
public class UserService {
	
	public void testAop(){
		System.out.println("---------logic code--------");
	}

	public UserService() {
		System.out.println("start user");
	}
}

 

package com.evan.proxy;

import com.evan.service.UserService;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @ClassName CglibUtil
 * @Description 用來產生代理對象的util
 * @Author EvanWang
 * @Version 1.0.0
 * @Date 2019/11/1 14:38
 */
public class CglibUtil {
	public static Object getProxy() {
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(UserService.class);
		enhancer.setCallback(new MethodInterceptor() {
			@Override
			public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
				System.out.println("--------cglib aop----------");
				Object result = methodProxy.invokeSuper(o, objects);
				return result;
			}
		});
		Object o = enhancer.create();
		return o;
	}
}

 

package com.evan.processor;

import com.evan.proxy.CglibUtil;
import com.evan.service.UserService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
 * @ClassName CustomAopBeanPostProcessor
 * @Description 我們自定義的後置處理器
 * @Author EvanWang
 * @Version 1.0.0
 * @Date 2019/11/1 14:36
 */
//aop核心的部分,就是後置處理器BeanPostProcessor
public class CustomAopBeanPostProcessor implements BeanPostProcessor {
	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if (bean instanceof UserService) {
			bean = CglibUtil.getProxy();
		}
		return bean;
	}
}

 

package com.evan.test;

import com.evan.config.MyConfig;
import com.evan.service.UserService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class AopTest {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(MyConfig.class);
		ac.getBean(UserService.class).testAop();
	
	}
}

 通過上面的一系列模擬,我們拿到的bean就已經是一個代理bean,即實現了Aop增強的bean。

運行結果:我們可以看到,在初始化的時候打印了一次,start user.

然後在創建代理對象時候,通過繼承默認調用父類的午餐構造,又打印了一遍start user.

然後接着實現了代理,最後打印代碼邏輯。至此,我們模擬的spring aop就完成了。

start user
start user
--------cglib aop----------
---------logic code--------

 

二、使用spring AOP

AOP的應用詳細介紹,請參考我的另一篇文章:Spring應用之AOP的使用和總結

我更傾向於,註解的使用方法,這些寫一個小的demo.

 

首先引入依賴。我這裏用的是gradle。maven類似,只要引入相對應的依賴就可以了。

compile(project(":spring-context"))
compile(project(":spring-aop"))
compile group: 'org.aspectj', name: 'aspectjweaver', version: '1.9.4'

代碼: 

package com.evan.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@ComponentScan("com.evan")
@Configuration
@EnableAspectJAutoProxy
public class MyConfig {
}

 

package com.evan.service;

import org.springframework.stereotype.Component;

/**
 * @ClassName UserService
 * @Description
 * @Author EvanWang
 * @Version 1.0.0
 * @Date 2019/11/1 12:09
 */
@Component
public class UserService {

	public void testAop(){
		System.out.println("---------logic code--------");
	}

	public void testAop2(){
		System.out.println("--------logic code---------2");
	}

	public UserService() {
		System.out.println("start user");
	}
}

 

package com.evan.aop;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * @ClassName NotVeryUsefulAspect
 * @Description
 * @Author EvanWang
 * @Version 1.0.0
 * @Date 2019/11/1 15:01
 */

@Component
@Aspect
public class NotVeryUsefulAspect {
	//切點
	@Pointcut("within(com.evan.service.UserService)")
	private void pointCutWithin() {
	}

	//前置通知
	@Before("pointCutWithin()")
	public void doAccessCheck() {
		System.out.println("Permission verification...");
	}

	//後置通知
	@After("pointCutWithin()")
	public void doLog() {
		System.out.println("Output log...");
	}
}

 

package com.evan.test;

import com.evan.config.MyConfig;
import com.evan.service.UserService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class AopTest {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(MyConfig.class);
		ac.getBean(UserService.class).testAop();
		ac.getBean(UserService.class).testAop2();
	}
}

運行結果: 

start user
Permission verification...
---------logic code--------
Output log...
Permission verification...
--------logic code---------2
Output log...

 

好的關於springAOP就介紹到這裏,還有很多不足。歡迎大家多提意見,以及和我討論spring的相關技術。: )

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章