前言
这篇文章之前我们说了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(下一篇文章会进行仔细的说明)