前言
? 這篇文章之前我們說了Springboot的啟動流程,Bean對象怎么實現從無到有的一個過程還有一些接口的拓展的實現等等那么從這一篇文章開始的話我們就會開始說一說我們的常用的AOP它的底層實現原理所以大家一起加油加油!!!
AOP:
1.簡介:
? AOP的話大家其實就是特別熟悉就算沒有使用過的話其實也聽過,其實它就是面向切面編程,我的理解就是說將不同模塊的公共的邏輯全部都提取出來然后進行一個統一的處理如:日志的打印,權限的管理,其實這么做的目的就是說其實就是減少代碼的冗余我在下面寫了一個Demo
切面:
@Aspect
@Component
public class AOPDemo {//這個是第一種方法@Pointcut("execution( * com.example.springsimpledemo.Demo.test(..))")public void testMethod(){};@Before("testMethod()")public void testDemo(){System.out.println("成功調用AOP方法");}//這個是第二種方法@Before("execution( * com.example.springsimpledemo.Demo.test(..))")public void testDemo(){System.out.println("成功調用AOP方法");}
}
測試類:
@Component
public class Demo {public void test(){System.out.println("這個是一個測試的方法");}
}
啟動類:
@SpringBootApplication
@EnableAspectJAutoProxy
public class SpringSimpleDemoApplication {public static void main(String[] args) {// 啟動 Spring Boot 應用ConfigurableApplicationContext context =SpringApplication.run(SpringSimpleDemoApplication.class, args);Demo bean = (Demo) context.getBean("demo");bean.test();}
}
結果:
那么從上面我們就是可以知道: 整個AOP的組成主要就是說有四部分組成的:
1.切面(添加Aspect注解)這個就是對不同模塊中公共的邏輯進行通過處理的地方也就是說進行了模塊化的處理管理連接點 切點以及通知(這個就是在哪里干以及干什么 什么時候干 的集合)
2.切點(@pointcut):這個的話其實就是說是一個表達式就是對哪些地方進行AOP的操作可以是一個包或者具體的一個類,這個也是后面用于和連接點進行一個匹配(這個就是在哪里干)
3.通知(advice):這個表示的就是說進行AOP操作的時間有前置后置以及環繞(什么時候干)
4.連接點(joinPoint):這個就是就是正在進行AOP操作的地方,也就是說根據切點匹配之后然后根據通過進行相對應的額外增強的操作,一般就是在方法調用的時候會生效(干的地方)
2.AOP失效的場景:
?我們在上面測試類的基礎之上的話進行了一次修改然后我們繼續進行測試
新的測試類:
//這個就是添加了一個check方法并且在test方法里面進行方法的調用
@Component
public class Demo {public void check(){System.out.println("在這個測試方法調用前進行校驗");}public void test(){check();System.out.println("這個是一個測試的方法");}
}
測試代碼:
@SpringBootApplication
@EnableAspectJAutoProxy
public class SpringSimpleDemoApplication {public static void main(String[] args) {// 啟動 Spring Boot 應用ConfigurableApplicationContext context =SpringApplication.run(SpringSimpleDemoApplication.class, args);Demo bean = (Demo) context.getBean("demo");bean.test();}
}
這個其實的話就是會產生一個AOP失效的場景,如果我們按照正常的思路其實我們就是說這個最后的結果里面肯定會有兩個輸出的結果為成功調用AOP方法但是最終的只會出現一個因為調用test方法的對象是代理對象但是調用test方法里面調用的對象是普通的對象不信的話我們就一起來看一看如下圖所示:
解決方案:
? 其實現在的話解決方案就是說進行功能之間的拆分
@Component
public class Demo {public void check(){System.out.println("在這個測試方法調用前進行校驗");}public void test(){System.out.println("這個是一個測試的方法");}
}
@SpringBootApplication
@EnableAspectJAutoProxy
public class SpringSimpleDemoApplication {public static void main(String[] args) {// 啟動 Spring Boot 應用ConfigurableApplicationContext context =SpringApplication.run(SpringSimpleDemoApplication.class, args);Demo bean = (Demo) context.getBean("demo");bean.check();bean.test();}
}
通過我上面進行拆分之后就能夠達到我們想要其得到的最終的效果:
2.原理:
EnableAspectJAutoProxy注解:
?其實這個注解的話就是我們整個AOP的整個核心,下面的話我們就看看這個源碼:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {//這個就是說是否通過CGLB動態代理創建一個代理對象進行動態代理boolean proxyTargetClass() default false;//是否暴露代理對象boolean exposeProxy() default false;}
@Import(AspectJAutoProxyRegistrar.class)
?注解引入了AspectJAutoProxyRegistrar
?類那么我們再來看看這個源碼
@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {//如果必要的話那么就是會創建一個自動代理的創建器(這個就是創建代理對象的核心)//1.如果說容器里面不存在或者優先級比較低的話那么肯定是會進行創建的//2.創建出來就是會進行一個優先級的比較的使用的肯定就是說優先級比較高的那一個AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);// 獲取 @EnableAspectJAutoProxy 注解AnnotationAttributes enableAspectJAutoProxy =AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);if (enableAspectJAutoProxy != null) {//這個就是解析要解析proxyTargetClass屬性if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);}//這個就是解析exposeProxy的屬性if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);}}}
從上面的源碼我們就是可以看出來這個類的主要的目的就是說進行一個自動代理創建器的創建因為這個的作用的話其實見名知意:就是自動為需要進行代理的Bean對象創建代理對象(這個就是簡單理解為就是Spring封裝的一個工具類而已)下面的話我們就來看一看這個自動代理創建器
registerAspectJAnnotationAutoProxyCreatorIfNecessary:
這個方法經過幾次的跳轉之后就是到達了AopConfigUtils.registerOrEscalateApcAsRequired()這個方法里面下面的話我們就是來看一看這個里面的方法
@Nullableprivate static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {Assert.notNull(registry, "BeanDefinitionRegistry must not be null");//如果已經存在的話if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);if (!cls.getName().equals(apcDefinition.getBeanClassName())) {int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());int requiredPriority = findPriorityForClass(cls);//這個就是優先級之間的比較if (currentPriority < requiredPriority) {//這個就是修改BeanDefinition對應的class的值apcDefinition.setBeanClassName(cls.getName());}}//如果已經存在的自動代理創建器和將要創建的自動代理創建器一致的話那么就不需要進行如何處理return null;}//不存在的話那么就進行創建就行了RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);beanDefinition.setSource(source);beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);//public static final String AUTO_PROXY_CREATOR_BEAN_NAME ="org.springframework.aop.config.internalAutoProxyCreator";registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);return beanDefinition;}//這個優先級的話就是這個自動代理創建器的BeanClassName在集合中的位置private static int findPriorityForClass(Class<?> clazz) {return APC_PRIORITY_LIST.indexOf(clazz);}private static int findPriorityForClass(@Nullable String className) {for (int i = 0; i < APC_PRIORITY_LIST.size(); i++) {Class<?> clazz = APC_PRIORITY_LIST.get(i);if (clazz.getName().equals(className)) {return i;}}throw new IllegalArgumentException("Class name [" + className + "] is not a known auto-proxy creator class");}
從上面我們可以看出來我們這個自動代理創建器的話都是注冊為BeanName為"org.springframework.aop.config.internalAutoProxyCreator"的Bean對象但是在AOP的場景下使用的是AnnotationAwareAspectJAutoProxyCreator這個類型的,那么我們只要分析其的源碼其實就是可以明白了
AnnotationAwareAspectJAutoProxyCreator:
? 上面就是將AspectJAnnotationAutoProxyCreator注冊到Spring容器里面然后這個里面的邏輯其實是不多的最重要的邏輯就是在AbstarctAutoProxyCreator中
AbstarctAutoProxyCreator:
? 這個wrapIfNecessary放法就是創建代理對象的方法但是真正實現代理對象創建是CreateProxy(這個的話我的下篇文章會進行仔細說明),我覺得更多得就是進行判斷是否要創建一個代理對象,從Bean的生命周期的話以及循環依賴的話代理對象的創建時間是不一樣的,如果在正常的Bean的生命周期的條件下的話那么初始化之后才會創建代理對象但是如果循環依賴的化那么就是在實例化之前就要進行判斷是否要創建代理對象
wrapIfNecessary
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;}//如果是(advice advisor pointcut )或者應該跳過代理的話if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}// Create proxy if we have advice.//這個方法就是說如果存在advice或者advisor(也就是說進行增強的處理)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;}
下面的話我們就是對需要跳過代理的條件進行判斷的依據進行一個判斷主要就isInfrastructureClass以及shouldSkip這兩個方法進行判斷
isInfrastructureClass:
protected boolean isInfrastructureClass(Class<?> beanClass) {//這個就是通過判斷這個Bean對象對應的class的類型//如果為 Advice Pointcut Advisor AopInfrastructureBean//那么就會進行跳過 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;}
shouldSkip:
?這個方法通過幾次跳轉之后就到達了AutoProxyUtils.isOriginalInstance這個方法當中然后我們就是看一下這個源碼
//這個方法就是用來識別哪些原始的對象(就是原汁原味的對象)//就是沒有進行額外的處理的對象就是通過ORIGINAL_INSTANCE_SUFFIX后綴進行區別的static boolean isOriginalInstance(String beanName, Class<?> beanClass) {if (!StringUtils.hasLength(beanName) || beanName.length() !=beanClass.getName().length() + AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX.length()) {return false;}return (beanName.startsWith(beanClass.getName()) &&beanName.endsWith(AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX));}
這個類既然是創建代理對象的地方那么這里的話我們就是來復習一下在Bean生命周期中是不是就是實例化前(這個是不是就是說提前進行AOP的操作就是為了解決循環依賴的問題)以及初始化之后也會創建實例對象下面的話那么就是簡單看一下這個里面的方法:
@Override@Nullable//初始化之后創建代理對象public 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;}//這個就是實例話之前創建代理對象其實判斷條件的話就是和wrapIfNecessary一樣//這個注解的話那么就是不進行標記了public 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;}
總結:
? 如果要進行AOP操作的話那么就是通過@EnableAspectJAutoProxy注解來進行開啟(這個也就是一個自動配置的過程就是通過AopAutoConfiguration),就是通過AspectJAutoProxyRegistrar這個類就是創建了注冊了自動代理創建器AnnotationAwareAspectJAutoProxyCreator,然后之后的操作的話都是在AnnotationAwareAspectJAutoProxyCreator中進行然后實現創建代理類的話就是通過AbstractAutoProxyCreator中的CreateProxy方法當中然后就是說通過ProxyFactory(下一篇文章會進行仔細的說明)