今天讀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的相關技術。: )