博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring AOP解析(详解动态代理的误区)
阅读量:3897 次
发布时间:2019-05-23

本文共 3288 字,大约阅读时间需要 10 分钟。

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的。

转载地址:http://piyen.baihongyu.com/

你可能感兴趣的文章
[BUUCTF 2018]Online Tool
查看>>
[GXYCTF2019]BabySQli
查看>>
BUUCTF_upload-labs 第一题
查看>>
2020暑期集训WEB部分WriteUp
查看>>
[极客大挑战 2019]HardSQL
查看>>
[网鼎杯 2020 青龙组]AreUSerialz
查看>>
Ubuntu上使用docker部署flask项目记录
查看>>
[GXYCTF2019]禁止套娃
查看>>
[安洵杯 2019]easy_web
查看>>
[BJDCTF 2nd]假猪套天下第一
查看>>
使用Ubuntu搭建Web服务器
查看>>
MySQL数据库基本操作
查看>>
Docker简单使用教程
查看>>
Doc
查看>>
[网鼎杯 2020 朱雀组]Nmap
查看>>
[极客大挑战 2019]FinalSQL
查看>>
[NCTF2019]True XML cookbook
查看>>
[CISCN2019 华北赛区 Day1 Web2]ikun
查看>>
[BJDCTF2020]EasySearch
查看>>
[BJDCTF 2nd]xss之光
查看>>