5:AOP: [动态代理]

指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式;

AOP: [动态代理]

      指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式
      1. 导入aop模块;Spring AOP: (Spring-aspects)
      2. 定义一个业务逻辑类(MathCalculator);在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常,xxx)
      3. 定义一个日志切面类(LogAspects): 切面类里面的方法需要动态感知MathCalculator.div运行到哪里,然后执行
              通知方法:
                   前置通知(@Before): logStart,在目标方法(div)之前运行
                   后置通知(@After): logEnd,在目标方法(div)运行结束之后运行
                   返回通知(@AfterReturning): logReturn,在目标方法(div)正常返回之后运行
                   异常通知(@AfterThrowing): logException,在目标方法(div)出现异常以后运行
                   环绕通知(@Around): 动态代理,手动推进目标方法运行(joinPoint.proceed())
      4. 给切面类标的目标方法标注何时何地运行(通知注解);
     5. 将切面类和业务逻辑类(目标方法所在类)都加入到容器中
      6. 必须告诉Spring哪个类是切面类(给切面类上加一个注解: @Aspect)
      7. 给配置类中加@EnableAspectJAutoProxy[开启基于注解的aop模式

三步:

  1. 将业务逻辑组件和切面类都加入到容器中,告诉Spring那个是切面类(@Aspect)
  2. 在切面类上的每一个通知方法上标注通知注解,告诉Spring何时何地运行(切入点表达式)
  3. 开启基于注解的aop模式,@EnableAspectJAutoProxy

AOP原理: [看给容器中注册了什么组件,这个组件是么时候工作,这个组件的功能是什么?]
@EnableAspectJAutoProxy:

  1. @EnableAspectJAutoProxy是什么?
    @Import(AspectJAutoProxyRegistrar.class): 给容器中导入AspectJAutoProxyRegistrar
    利用AspectJAutoProxyRegistrar自定义给容器中注册bean;
    internalAutoProxyCreator=AnnotationAwareAspectJAutoProxy

     给容器中注册一个AnnotationAwareAspectJAutoProxyCreator;
    
  2. AnnotationAwareAspectJAutoProxyCreator:
    AnnotationAwareAspectJAutoProxyCreator
    ->AspectJAwareAdvisorAutoProxyCreator
    ->AbstractAdvisorAutoProxyCreator
    ->AbstractAutoProxyCreator
    implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
    关注后置处理器(在bean初始化完成前后做的事情)、自动装配BeanFactory
    AbstractAutoProxyCreator.setBeanFactory()
    AbstractAutoProxyCreator.有后置处理器的逻辑:

AbstractAdvisorAutoProxyCreator.setBeanFactory()->initBeanFactory()

AnnotationAwareAspectJAutoProxyCreator.initBeanFactory()

流程:
1)、传入配置类,创建ioc容器
2)、注册配置类,调用refresh()刷新容器;
3)、registerBeanPostProcessors(beanFactory);注册bean的后置处理器来方便拦截bean的创建
1)、 先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessor
2)、 给容器中加BeanPostProcessor
3)、 优先注册实现了PriorityOrdered接口的BeanPostProcessor;
4)、 再给容器中注册实现了Ordered接口的BeanPostProcessor
5)、 注册没实现优先级接口的BeanPostProcessor;
6)、 注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中
创建internalAutoProxyCreator的BeanPostProcessor
1)、创建Bean的实例
2)、populateBean;给bean的各种属性赋值
3)、initializeBean: 初始化bean
1)、invokeAwareMethods(): 处理Aware接口的方法回调
2)、applyBeanPostProcessorsBeforeInitialization(): 应用后置处理器的postProcessBeforeInitialization
3)、invokeInitMethods(): 执行自定义的初始化方法
4)、applyBeanPostProcessorAfterInitialization(): 执行后置处理器的postProcessAfterInitialization()
4)、 BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功; -->aspectJAdvisorBuilder
7)、把BeanPostProcessor注册到BeanFactory中
beanFactory.addBeanPostProcessor(postProcessor)
======以上是创建和注册AnnotationAwareAspectJAutoProxyCreator的过程d
AnnotationAwareAspectJAutoProxyCreator => InstantiationAwareBeanPostProcessor
4)、finishBeanFactoryInitialization(beanFactory);完成BeanFactory初始化工作; 创建剩下的单实例bean
1)、 遍历获取容器中所有的Bean, 依次创建对象getBean(beanName);
getBean -> doGetBean()--> getSingleton()
2)、 创建bean;在bean创建之前会有一个拦截,InstantiationAwareBeanPostProcessor,会调用postProcessBeforeInstantiation()
1)、先从缓存中获取当前bean,如果能获取到,说明bean是之前被创建过的,直接使用,否则再创建
只要创建好的bean都会被缓存起来
2)、createBean();创建bean; AnnotationAwareAspectJAutoProxyCreator会在任何bean创建之前尝试返回bean的实例
【BeanPostProcessor实在Bean对象创建完成初始化前后调用的】
【InstantiationAwareBeanPostProcessor是在创建Bean实例之前先尝试用后置处理器返回对象的】
1)、resolveBeforeInstantiation(beanName, mbdToUse);解析BeforeInstantiation
希望后置处理器在此能返回一个代理对象;如果能反悔代理对象就使用,不能就继续
1)、后置处理器先尝试返回对象:
bean = applyBeanPostProcessorBeforeInstantiation()
拿到所有后置处理器,如果是InstantiationAwareBeanPostProcessor;
就执行postProcessBeforeInstantiation
if(bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
2)、doCreateBean(beanName, mbdToUse,args);真正的去创建一个bean实例,和3.6流程一样

AnnotationAwareAspectJAutoProxyCreator [InstantiationAwareBeanPostProcessor]的作用,

  1. 、每一个bean创建之前,调用postProcessorBeforeInstantiation()
    关心MathCalculator和LogAspect的创建
    1)、判断当前bean是否在advisedBeans中(保存了所有需要增强bean)
    2)、判断当前bean是否是基础类型的Advice、Pointcut、 Advisor、AopInfrastructureBean、或者是否是切面
    3)、是否需要跳过
    1)、获取候选的增强器(切面里面的通知方法)【List<Advisor> candidateAdvisors】
    每一个封装的通知方法的增强器是InstantiationModelAwarePointcutAdvisor;
    判断每一个增强器是否为AspectJPointcutAdvisor: 返回true
    2)、永远返回false
    2)、创建对象
    postProcessAfterInitialization
    return wrapIfNecessary(bean, beanName, cacheKey);//包装如果需要的情况下
    1)、获取当前bean的所有增强器(通知方法) Object[] specificInterceptors
    1. 找到候选的所有的增强器(找哪些方法是需要切入当前方法的)
    2. 获取到能在当前bean使用的增强器。
    3. 给增强器排序
    2)、保存当前bean在advisedBeans中
    3)、创建代理对象,创建当前bean的代理对象
    1)、获取所有增强器(通知方法)
    2)、保存到proxyFactory.getProxy(getProxyClassLoader())中
    3)、创建代理对象: Spring自动决定
    JdkDynamicAopProxy(config);
    ObjenesisCglibAopProxy(config);
    4)、给容器中返回当前组件使用cglib增强了的代理对象
    5)、以后容器中获取到的就是这个组建的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程
public class MathCalculator {
    public int div(int a, int b){
        System.out.println("MathCalculator...div...");
        return a / b;
    }
}
@Aspect
public class LogAspects {

    //抽取公共的切入点表达式
    //1、本类引用
    //2、其他的切面引用
    @Pointcut("execution(public int com.atguigu.aop.MathCalculator.*(..))")
    public void pointCut(){};

    @Before("pointCut()")
    public void logStart(JoinPoint joinPoint){
        Object[] args = joinPoint.getArgs();
        System.out.println("" + joinPoint.getSignature().getName() + "除法运行。。。参数列表是: {" + Arrays.asList(args) + "}");

    }

    @After(("com.atguigu.aop.LogAspects.pointCut()"))
    public void logEnd(){
        System.out.println("除法结束");
    }

    @AfterReturning(value = "pointCut()", returning = "result")
    public void logReturn(Object result){
        System.out.println("除法正常返回。。。@AfterReturning:运行结果: { " + result + "}");
    }

    //JoinPoint一定要出现在参数表的第一位
    @AfterThrowing(value = "pointCut()", throwing = "exception")
    public void logException(Exception exception){
        System.out.println("除法异常。。。异常信息: { " + exception);
    }

}

@Configuration
@EnableAspectJAutoProxy
public class MainConfigOfAOP {

    @Bean
    public MathCalculator calculator(){
        return new MathCalculator();
    }

    @Bean
    public LogAspects logAspects(){
        return new LogAspects();
    }
}
public class IOCTest_AOP {

    @Test
    public void test01(){
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfigOfAOP.class);

        MathCalculator bean = annotationConfigApplicationContext.getBean(MathCalculator.class);
        bean.div(3,1);

        annotationConfigApplicationContext.close();
    }
}
image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容

  • 个人专题目录[https://www.jianshu.com/u/2a55010e3a04] 1.5. AOP 核...
    Java及SpringBoot阅读 181评论 0 0
  • 1.MainConfigOfAOP.class /** * * AOP:[动态代理] * 指在程序运行期间动态...
    1b78cebcb5b8阅读 134评论 0 0
  • 1、AOP简介 AOP:【动态代理】 指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式;常...
    huangxiongbiao阅读 607评论 0 2
  • 13.AOP(动态代理) 指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方法。 切面编程:将...
    曦夫阅读 717评论 0 3
  • 表情是什么,我认为表情就是表现出来的情绪。表情可以传达很多信息。高兴了当然就笑了,难过就哭了。两者是相互影响密不可...
    Persistenc_6aea阅读 125,036评论 2 7