Spring AOP解析(详解动态代理的误区)

Spring是广大java程序员必学的一个框架,Spring的底层源码十分繁琐,封装特别多的方法,今天就从源码的角度浅谈Spring AOP的底层原理。

首先,第一个问题:什么是AOP?
与OOP对比,面向切面,传统的OOP开发中的代码逻辑是自上而下的,在这些自上而下的过程中会产生一些横切性的问题,这些横切性的问题和我们主业务的逻辑关系不大,会散落在代码的各个角落,造成难以维护,AOP的编程性的问题就是把业务逻辑和横切的问题进行分离,从而达到解耦的目的,使代码的通用性和开发效率高。
在这里插入图片描述
2.AOP的应用场景:
(1)日志记录
(2)权限验证
(3)效率检查
(4)事务管理

3.Spring AOP的底层技术
JDK动态代理
Cglib代理
编译时期的织入还是运行时期的织入?两者是在运行时织入
初始化时期织入还是获取对象时期的织入?通过源码分析,可以知道是在初始化时期织入。

4.Spring AOP和AspectJ的关系
Spring AOP提供两种编程风格
@AspectJ support ----------利用AspectJ的注解
Schema-based AOP support ----------xml
证明:Spring,通过源码分析了,我们可以知道Spring底层使用的是JDk或者CGLIB来完成的代理,并且在官网上Spring给出了AspectJ的文档,和SpringAOP是不同的。

AOP是我们要达到的编程目标,面向切面。SpringAOP是实现AOP具体的一个手段。比如AOP是发财,卖肾就是实现发财的一个手段。

AspectJ也可以实现AOP,他跟SpringAOP是同一个级别的,为什么他可以实现AOP了,Spring还要干一个SpringAOP出来,在Spring2.5的时候,也有一个自己的AOP,但是他的语法相当蛋疼,就是别人学起来很难,于是他就借助了AspectJ实现了AOP的语法。

5.AOP开发中相关术语

在这里插入图片描述
在这里插入图片描述
6.Spring AOP基于AspectJ开发步骤
(1)在配置类开启Spring对AspectJ编码风格的支持(通过注解,还可以通过xml)
@EnableAspectJAutoProxy
(2)声明一个切面类,并交给Spring管理
在这里插入图片描述
(3)声明一个切点
在这里插入图片描述
(4)声明一个通知
在这里插入图片描述

7.证明Spring使用JDK动态代理还是CGLIB代理(大误区):
看一下下面这两种情况:
(1)没有实现接口的

public class Test {

    public static void main(String[] args){
        //初始化
        AnnotationConfigApplicationContext annotationConfigApplicationContext=new AnnotationConfigApplicationContext(Appconfig.class);
        //IndexDaoImpl没有继承接口
        IndexDaoImpl dao= (IndexDaoImpl) annotationConfigApplicationContext.getBean("dao");
        dao.query();
    }
}

在这里插入图片描述

(2)有实现接口的

public class Test2 {

    public static void main(String[] args){
        //初始化
        AnnotationConfigApplicationContext annotationConfigApplicationContext=new AnnotationConfigApplicationContext(Appconfig.class);
        IndexDao dao=  annotationConfigApplicationContext.getBean(IndexDao.class);
        dao.query();
    }
}

在这里插入图片描述

如果没有接口用CGLIB代理,如果有接口用JDK代理,这句话对不对???
错了,
加上proxyTargetClass=true 这句话后前面使用有接口的情况变成了CGLIB代理
proxyTargetClass=flase 就会变成JDK代理,但是这个值默认就是false,如果这个值是true的话,他就会强制使用CGLIB,不管你有没有接口
那怎么什么时候JDK代理,什么时候CGLIB代理,是有条件的,条件是什么?
取决与proxyTargetClass值和有没有接口,如果proxyTargetClass是true,他就会使用CGLIB,不管有没有接口。如果这个值为false(默认为false),他有接口则使用JDK动态代理,如果没有接口就使用CGLIB代理。

8.那从IndexDaoimpl对象到CGLIB代理对象,经历了什么?
IndexDaoImpl—>init(初始化)---->getBean----->cglib Proxy
那他是在init的时候成为的还是在getBean的时候成为了代理对象?

可以看一下下面这个Spring源码,这段可以说是Spring最核心的代码:

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
        Map var4 = this.singletonObjects;
        synchronized(this.singletonObjects) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }

    return singletonObject != NULL_OBJECT ? singletonObject : null;
}

singletonObjects返回的是一个ConcurrentHashMap,这是个线程安全的HashMap,这个map就是Spring中所谓的IOC容器,key是名字,value是包名
从这边可以看出Spring织入在初始化(也就是把对象放进IOC容器)的时候就已经完成了,这边是从IOC容器里面拿出来get的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值