![6d32404866b0aad86936eb5b611cfff6.png](https://i-blog.csdnimg.cn/blog_migrate/217faf2d9e7634f160f9bfd6daf03758.jpeg)
>>>Spring框架完整视频教程<<<
>>> 学习交流群 < < <
三、SpringAOP的介绍
1. 使用SpringIOC的项目开发流程
① 创建一个web项目
② 配置相关依赖(SpringIOC+Mybatis+整合包+jdbc)
③ 在src下创建MVC的包结构
④ 在src下创建并配置applicationcontext.xml文件
- 配置数据源bean
- 配置工 厂bean
- 配置mapper扫描bean
- 配置业务层bean(注入mapper对象)
⑤ 在web.xml中配置applicationcontext.xml的路径和Spring的监听器.
⑥ 完成功能开发
- 在Servlet中重写init方法完成spring容器的资源加载
- 在业务层中声明mapper属性,并且提供get/set方法
2. SpringAOP的介绍
问题:
在学习了SpringIOC之后,我们可以使用IOC的知识将代码中层与层之间的耦合性进行解耦,便于后期维护.但是在实际生产环境中,我们发现随着公司业务的增长,我们会升级某个业务层的业务方法的代码逻辑.升级后的业务方法还需要兼容以前的逻辑处理,也就说再保留原有功能逻辑的基础上,在方法中新增新的逻辑代码.而这个时候,就需要我们去修改当前功能方法的源码,增加新的逻辑代码,然后重新运行项目.这时候出现如下问题:
- 假如我们有当前功能方法的源码,就需要阅读当前方法的源码,然后再增加自己的新的逻辑代码.并且修改好后,需要将新的类文件替换旧的类文件,而阅读代码本身效率极低.
- 假如我们没有源码文件,那么就无法直接修改源码增加新的功能逻辑,怎么 办?
解决:
在不修改原有功能逻辑的基础上完成功能扩展.
方案:
A对象中有一个testA的方法,A--->testA(),现在需要升级testA方法.创建一个B对象,在B对象中声明一个testB方法,然后在testB中调用testA方法,并且在testB中声明扩展代码.然后将代码中调用A对象的testA方法的代码替换为调用B对象的testB方法.完成了升级.为了方便代码的替换,可以让A和B都实现接口C,将要进行功能扩展的方法在C中声明,这样就只需要将A对象替换为B对象,就不需要修改调用方法了.但是将A替换为B对象,如果有10000个代码都在调用A对象,就需要替换10000次,并且容易遗漏,考虑使用IOC.
原理图:
![924d3a53ef8fe09d50e12bcf5411f8c2.png](https://i-blog.csdnimg.cn/blog_migrate/95226cf618e2243a556468a11ccb371d.jpeg)
实现:
SpringAOP
四、SpringAOP的SchemaBase方式实现
1. SchemaBase方式实现的基本流程
SpringAOP的本质总结:
我们将要进行功能扩展相关的材料以及对应的组织规则告诉Spring容器,Spring容器帮我们动态创建一个代理对象。我们直接从Spring容器中获取代理对象完成功能开发。
1.1 导入SpringAOP的jar包
![b02ae16788d2bc5e30e5b28561456968.png](https://i-blog.csdnimg.cn/blog_migrate/55636c5647168349ba47a5b8c5a6d81e.png)
1.2 在src下创建包advice,并创建前置通知类和后置通知类
前置通知类:
创建一个普通的java类,实现MethodBeforeAdvice接口, 重写before方法,在before方法中声明扩展前的逻辑代码。
![9d857e1845b5b08e93107b0ffd692c4c.png](https://i-blog.csdnimg.cn/blog_migrate/f72d4e632463bf5c8b0ea7c678e490dc.jpeg)
后置通知类:
创建一个普通的Java类,实现AfterReturningAdvice接 口,重写after方法,并在after方法中声明扩展后的逻 辑代码。
![6a2726b2040fe207efa1d54d35687a89.png](https://i-blog.csdnimg.cn/blog_migrate/2ba4de921ebfb6f762dc40944d6a7d74.jpeg)
1.3 在applicationcontext.xml文件中配置资源的bean对象以及声明组装规则。
资源对象:
- 要进行功能扩展的bean对象
- 前置通知的bean对象
- 后置通知的bean对象
声明组装规则:(使用AOP标签完成)
- 声明切点
- 声明组装
![6ad6e48cf870080203206dc25b4266d3.png](https://i-blog.csdnimg.cn/blog_migrate/ad04b0e427504b8959335bd98e92aee7.jpeg)
1.4 从Spring容器中直接获取代理对象完成功能开发
![c8663f13c00f12038182bed3bb08974d.png](https://i-blog.csdnimg.cn/blog_migrate/272c2db58e985eb2e0a7c0b3bd461d13.jpeg)
注意:
如果让Spring容器对象某个bean对象按照AOP进行功能扩展,则从Spring容器中使用该对象的ID获取的对象已经不是其本身了,而是他的代理对象(夺舍)。
2. SpringAOP的专业概念
- 真实对象:
要进行功能扩展的对象,相当于A对象
- 代理对象:
完成功能扩展的对象,相当于B对象.
- 切点:
要进行功能扩展的方法,相当于testA()方法
- 前置通知方法:
在切点之前执行的扩展方法
- 后置通知方法:
在切点之后执行的扩展方法
- 切面:
由前置通知+切点+后置通知形成的横向执行的面
- 织入:
由前置通知+切点+后置通知形成切面的过程
- AOP的概念:
面向切面的编程
![5b94a386ef1860a98620a600db1d0404.png](https://i-blog.csdnimg.cn/blog_migrate/c78359e8174164467c3f511a7f1801f1.png)
3. SchemaBase方式环绕通知方式实现AOP
解释:
前面我们已经使用前置通知方式和后置通知方式完成了AOP的扩展代码的编写。而我们之前学过过滤器的概念,在过滤器中会先执行一部分代码,执行后如果放行了则继续执行
Servlet,Servlet执行后再次回到过滤器中执行。那么,从AOP的角度过滤器就相当于Servlet的扩展对象了。过滤器中的拦截方法,就相当于扩展方法,而我们将扩展代码和调用原有切点方法的代码全部直接声明在一个方法中了,那么能不能采用此种方案来完成我们会自己的AOP扩展呢?
实现:
环绕通知
特点:
将扩展代码和调用原有切点方法的代码声明在一起,简化扩展流程。也就说环绕通知中包含了前置通知和后置通知。
使用:
- 创建一个普通Java类,实现环绕通知的接口。
- 在applicationcontext.xml文件中配置环绕通知的bean
- 在组装规则中使用配置环绕通知的组装。
注意:前置通知和后置通知和环绕通知可以同时使用,执行顺序和配置顺序相关。
![bc51211d9b66f262809186b6a8452920.png](https://i-blog.csdnimg.cn/blog_migrate/9ca48dde384b2e77af516b1244760638.jpeg)
![9226fdb379bfee439b04d272b9a3cda7.png](https://i-blog.csdnimg.cn/blog_migrate/0736ea4eefd77caaa9e3953fd7ca6522.jpeg)
4. SchemaBase方式的异常通知
问题:
在我们封装一个功能方法时,一般方法处理数据所造成的异常信息需要抛出,或者代码编译没有问题,运行期间出现问题,该异常也应该有调用者来处理。那么在SpringAOP中,代理对象是动态生成的,在代理对象中会调用前置通知,后置通知,环绕通知,切点方法,那么如果这些方法出现异常信息,理论上来说应该在扩展对象中的扩展方法中完成异常的处理。但是尴尬的是,代理对象是动态生成的,不是由我们创建类然后根据类文件创建出来的,那么我们就无法直接的声明异常处理代码了,怎么办呢?
解决:
在外部声明异常处理的功能方法,让SpringAOP动态生成的代理对象,在生成的catch中调用我们声明的异常处理方法即可。
使用:
- 创建一个普通Java类,实现异常接口。
- 在applicationcontext.xml文件中配置异常通知bean对象
- 在applicationcontext.xml文件中配置异常通知bean的组装
![c76c24965c235132bee615dd8a32f47c.png](https://i-blog.csdnimg.cn/blog_migrate/aea82c0a65372fb5a464c6ba3b9d5b68.png)
![09f799cf662ac1b37494d1940aed0782.png](https://i-blog.csdnimg.cn/blog_migrate/89b60712ece26a69fbadcad560357ed0.png)
有什么疑问或者不懂的地方进群讨论哦,欢迎大家一起学习~