一文彻底帮你打通SpringAOP的任督二脉,大厂高薪指日可待,建议收藏!!!

简介: Spring的IoC和AOP不仅仅是我们学习Spring平台下各个框架的核心基础,同时也是我们出去面试问道的频率最高的面试题了,同时也是大家很难彻底掌握好的技术的,本文就透过本质来给大家来介绍下Spring的AOP,Spring的IoC也会在后续的文章中给大家介绍,欢迎大家一键三连哦!!!


  Spring的IoC和AOP不仅仅是我们学习Spring平台下各个框架的核心基础,同时也是我们出去面试问道的频率最高的面试题了,同时也是大家很难彻底掌握好的技术的,本文就透过本质来给大家来介绍下Spring的AOP,Spring的IoC也会在后续的文章中给大家介绍,欢迎大家一键三连哦!!!

image.png

一、代理模式

  要讲解清楚Spring的AOP那么我们不得不先来聊下代理模式。

1.代理模式的作用

  代理模式的作用是用来增强目标对象的。

image.png 上面那么介绍大家可能会感觉比较迷惑,为什么能增强目标对象?为什么要增强目标对象呢?我们举个简单的例子,比如你家拆迁分到了很多的money,这时你想要改变下生活品质这时你会想在吃晚饭的时候找个明星来给你唱歌,这时你需要自己去联系这个明星,然后还有很多的琐事需要处理,如下的结构

image.png

  这时你会感觉很麻烦,而且这个明星除了唱这件事情外还需要处理很多的非核心业务之外的事情,这时他可以请一个经纪人来帮他解决唱歌之外的其他杂事。如下:

image.png

  那么这里的经纪人其实就相当于代理模式中的代理对象,让我们的目标对象专注于核心功能,其他的非核心业务就由代理对象来完成了。

2.代理模式的实现

  通过上面的介绍相信大家应该清楚了代理对象的作用了,那么怎么实现代理对象呢?

这个请大家移步本人的另一篇文章:

https://dpb-bobokaoya-sm.blog.csdn.net/article/details/86484887

专门介绍了代理模式的三种实现方式(静态代理,JDK代理和CGLIB代理)

二、SpringAOP

  接下来我们看下SpringAOP的实现原理

1.AOP案例

  我们通过日志的案例来给大家来介绍,先看下我们不使用AOP的情况下来实现日志记录方法执行的时间。

1.1 非AOP实现

  首先创建一个SpringBoot项目,然后创建IUserService接口,定义如下:

public interface IUserService {
    public void log1();
    public void log2();
}

  然后创建接口的实现,如下:

@Service
public class UserServiceImpl implements IUserService {
    @Override
    public void log1() {
        long start = System.currentTimeMillis();
        try {
            Thread.sleep(5);
            System.out.println("log1 方法执行了 ...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println("log1方法执行耗时:" + (end - start));
    }
    @Override
    public void log2() {
        try {
            Thread.sleep(5);
            System.out.println("log2 方法执行了 ...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

测试代码

//@SpringBootApplication
@Configuration
@ComponentScan
public class SpringAopDemo02Application {
    public static void main(String[] args) {
        //SpringApplication.run(SpringAopDemo02Application.class, args);
        ApplicationContext ac = new AnnotationConfigApplicationContext(SpringAopDemo02Application.class);
        IUserService bean = ac.getBean(IUserService.class);
        bean.log1();
    }
}

image.png

  到这儿我们可以看出在Service中我们的核心业务代码和日志模块的代理耦合在了一块,这显然是不合适的,这时AOP就派上用场了。

1.2 AOP实现

  Spring中的AOP的实现有多种方式,本文就不具体的来一一介绍了,感兴趣的可以参考本人的另一篇文章

https://blog.csdn.net/qq_38526573/article/details/86441916

本文重点介绍原理,我们需要先添加AspectJ的依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
</dependency>

然后定义切面类

@Aspect
@Component
public class MyAspect {
    /**
     * 定义一个环绕通知
     * @param pjp
     * @return
     */
    @Around("execution(* com.bobo.service.impl.*.log2(..))")
    public Object around(ProceedingJoinPoint pjp){
        long start = System.currentTimeMillis();
        Object proceed = null;
        try {
            // 执行目标对象的方法
            proceed = pjp.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println(pjp.getSignature().getName() + "  执行耗时:" + (end - start));
        return proceed;
    }
}

然后我们在需要添加@EnableAspectJAutoProxy注解来放开代理的使用

//@SpringBootApplication
@Configuration
@ComponentScan
@EnableAspectJAutoProxy
public class SpringAopDemo02Application {
    public static void main(String[] args) {
        //SpringApplication.run(SpringAopDemo02Application.class, args);
        ApplicationContext ac = new AnnotationConfigApplicationContext(SpringAopDemo02Application.class);
        IUserService bean = ac.getBean(IUserService.class);
        bean.log1();
        System.out.println("-------------------");
        bean.log2();
    }
}

通过输入我们发现代理生效了

image.png

  通过上面的操作你会发现SpringAOP的实现还是比较简单的,也实现了业务代码和系统功能的分离。更利于系统的扩展。

2.AOP原理分析

  上面的案例实现了AOP,接下来我们需要分析下AOP的原理,前面介绍了代理模式,我们知道代理模式的实现方式有多种,首先我们来看看AOP是采用的JDK代理还是CGLIB代理呢?

2.1 AOP的本质

  其实在Spring的AOP中既有JDK代理的实现也有CGLIB的使用,为什么这么说呢?我们通过演示带大家看看。首先在前面的测试案例的基础上我们通过debug模式来看

image.png

  通过断点我们发现IUserService的bean对象是一个JDK动态代理的对象。那CGLIB代理呢?我们这样来做。定义一个PersonServiceImpl这个Service没有实现任何的接口

@Service
public class PersonServiceImpl {
    public void show(){
        System.out.println("Hello ...");
    }
}

然后我们同样的来获取

    public static void main(String[] args) {
        //SpringApplication.run(SpringAopDemo02Application.class, args);
        ApplicationContext ac = new AnnotationConfigApplicationContext(SpringAopDemo02Application.class);
        IUserService bean = ac.getBean(IUserService.class);
        bean.log1();
        System.out.println("-------------------");
        bean.log2();
        System.out.println("********");
        PersonServiceImpl personService = ac.getBean(PersonServiceImpl.class);
        personService.show();
    }

ac.getBean(PersonServiceImpl.class);这么去写是会报错的

image.png

  提示是没有找到。这儿大家可以思考下为什么没有获取到? 思考三秒

  原因是因为PersonServiceImpl没有实现任何的接口,那么肯定不能使用JDK动态代理,只能使用CGLIB代理,而CGLIB的代理对象是和目标对象没关系的。所以肯定获取到不到,那么这时怎么办呢?

image.png

  换种思路我们通过BeanName来获取即可。

image.png

注意:切面中的 切入点表达式要修改

image.png

  到这儿其实我们可以发现,在Spring的AOP中如果目标对象实现了接口则使用JDK代理如果目标对象没有实现接口就只能通过CGLIB代理来实现了。

当然你也可以显示的指定就使用CGLIB代理。如下

image.png

如果本文对你有帮助,欢迎关注点赞加收藏哦!!!


相关文章
|
8月前
|
JavaScript 前端开发 API
前端攻坚战
前端攻坚战
|
存储 区块链
创客互助公排开发功能丨创客互助公排系统开发技术详细丨创客互助公排系统源码案例模式
 区块头和区块体数据也会被当作输入数据做一次Hash运算,其运算结果会被存储在下一个区块的区块头中,这样任何区块内容的修改都会反映到区块的Hash值上,而区块的Hash值又是下一个区块的输入数据,它又会被当作新区块的数据参与一次新区块的Hash运算,随着时间的推移和交易量的增加,所有的区块会通过保存前一个区块的Hash运算结果的方式组成一条链。
|
JSON 小程序 JavaScript
【小程序 | 启航篇】一文打通任督二脉
【小程序 | 启航篇】一文打通任督二脉
【小程序 | 启航篇】一文打通任督二脉
|
新零售 双11 云计算
逆势招人,阿里平台做对了什么?
不依靠风口而是创造风口的开拓意识,持续投入建设平台使之具有平台效应,这或许是阿里巴巴具有商业价值和社会价值的原因。
133 0
逆势招人,阿里平台做对了什么?
|
存储 云安全 大数据
打造技术脱贫样板,阿里巴巴“云上贵州”暖人心
贵州数博会拉开帷幕,阿里巴巴宣布将在数字政府、教育、物联网、扶贫、科研、零售、工业和农业八大领域持续加大在贵州的投入。以阿里云为依托,撬动经济体的力量,全力推动当地大数据产业发展,重点攻坚技术脱贫
196 0
打造技术脱贫样板,阿里巴巴“云上贵州”暖人心
|
运维 监控 安全
从”蒸汽时代”到”高铁时代“,商米ALPD实践之路
做为一家初创企业,商米研发团队早期也经历过与当下大部分创业公司一样困境:协作基本靠吼、发布基本靠手的阶段。然而,业务的快速发展,团队规模不断的扩大,给商米带来了在「团队协作」和「工程效能」上的双重挑战。
|
智能硬件
13年IT老兵:闷头做智能家居体系容易走火入魔
1993年投身IT创业,深谙计算机领域贸易,21世纪初创建深圳市思浪实业有限公司,持续深耕安防监控、智能家居等行业,以Z-wave系列产品开拓全球市场,2016年携手涂鸦智能布局物联网时代。
530 0
|
人工智能 安全 中间件
十五年了,蚂蚁为何执着攻坚这两个技术堡垒?
近日,蚂蚁金服副CTO 胡喜应邀做了《蚂蚁金服十五年技术架构演进之路》的演讲,分享蚂蚁金服对金融科技未来的判断,并首次对外公开蚂蚁金服技术人才培训体系以及 BASIC College 项目。
3718 0
|
分布式计算 关系型数据库 Java
不要争了!技术选择没那么重要
摘要: 技术没有高下之分,做好产品才是王道。 很多开发者非常热衷于比较不同技术,比如:Angular 是否比 Vue.js 更好?Node.js 能否取代 Java?究竟应该选择 MySQL 还是 MongoDB 呢? 认真对比不同技术之间的优劣是非常有价值的事,可以加深我们对技术的理解,根据业务场景选择更合适的技术。
3748 0