Spring

概述:

Spring针对于业务层(逻辑分析,控制),以IOC和AOC为核心,提供给业务层和持久层的业务关系,目的减少层次的依赖性。

目的是(重要):解决企业开发应用的复杂性,使现有的技术更加容易。它是一个融合剂,乱七八糟的东西都可以交给它。
在这里插入图片描述

当前趋势
在这里插入图片描述
在这里插入图片描述

下载:如何在官网下载以前版本的文件。
在这里插入图片描述
在路径上修改你想下载的版本号
在这里插入图片描述
在这里插入图片描述
点击链接
在这里插入图片描述

复制打开这个地址
在这里插入图片描述
所有的版本
在这里插入图片描述
在这里插入图片描述
GitHub上下载,就是被github开源托管了。
如图带这个小猫的都是被GitHub开源的

点击小猫
在这里插入图片描述
在这里插入图片描述
如图点击下载的版本
在这里插入图片描述
在这里插入图片描述
引入spring的时候,导入spring web mvc东西最全 ,maven带这个功能就可以把需要的东西一起带进来。
在这里插入图片描述
在这里插入图片描述
当整合mybatis时候就可以使用这个依赖
在这里插入图片描述

IOC
Interval Of Control即控制反转,它不是技术而是一种设计思想。传统的创建对象是通过new关键字,而Spring通过IOC容器来帮助我们创建对象,也就是说我们将把创建对象的控制权交给IOC容器,从而消减程序中的耦合,也就是降低代码中的依赖关系。

AOP
Aspect Oriented Programming 即面向切面编程,它是面向对象编程的一种延伸。

优势
1、方便解耦,简易开发
2、支持AOP开发
3、事务的支持
4、方便程序的测试

以上的话比较官方,自己的理解:
IOC设计思想,通过bean配置文件中的class属性指明需要创建对象的实现类后,IOC容器会自动给我们创建出对象并由它接手。有了对象而不是我们new出来的,所以说叫控制反转。
那么如何操作IOC创建对象:
IOC容器 = bean.xml(配置文件) + ApplicationContext容器类

IOC 控制反转(重要)

配置bean标签,相当于建一个对象,spring是怎么创建出来的?
官网约束。
在这里插入图片描述

在这里插入图片描述
所以容器就指的是bean.xml配置文件中的标签,里面配置的一个个子标签就是一个个对象。注入数据的标签,value属性是相当于set值。 ref属性是引用中的对象。
在这里插入图片描述
在这里插入图片描述

演示一下:
创建包
在这里插入图片描述
pom.xml添加jar包
在这里插入图片描述
如图建立包结构
在这里插入图片描述
在这里插入图片描述
添加bean文件约束
在这里插入图片描述
配置bean文件的实现类
在这里插入图片描述
spring需要跟MyBatis建立联系
在这里插入图片描述
service层保存数据的方法
在这里插入图片描述
dao层接口保存数据
在这里插入图片描述
service实现类
在这里插入图片描述
配置bean.xml文件
在这里插入图片描述
获取IOC容器,并在容器中得到对象
核心容器就是为了存储我们需要的对象,根据id的标识,通过getBean方法获取对应的对象。
在这里插入图片描述
在这里插入图片描述
BeanFactory spring的顶级接口
可以查看该接口及子接口的关系
在这里插入图片描述
在这里插入图片描述
两个接口的区别
spring IO容器中默认一个类只产生一个对象,也就是默认是单例模式。
ApplicationContext
1、适用于单例模式 ,也就是说只有一个对象时用这个接口
2、创建核心容器时,创建对象的方式采用立即加载。立即加载就是读取配置 文件就立即创建出该配置文件的对象。

BeanFactory
1、使用于多例对象
2、采用延时加载的方式,什么时候需要对象再创建出来。

ApplicationContext 子接口

ApplicationContex接口是BeanFactory常用的子接口,有以下三个常用是实现类:
ClassPathXmlApplicationContext
基于xml文件方式 ,类路径的全限定类名,对应<bean>中的class属性(最常用)

FileSystemXmlApplicationContext
基于xml文件,针对磁盘中任意路径,可以加载本地磁盘中的文件路径(需要访问权限,不常用)

AnnotationConfigApplicatonContext
基于注解,读取用注解创建容器的信息

bean.xml配置文件(重要)

<bean>标签是核心
作用:为IOC容器配置对象信息。

属性:
id : 唯一标识,通过标识找到容器中的对象。

class : 指明需要创建对象的类(全限定类名),应用到反射技术。
默认调用的是无参的构造方法。

scope : 指定对象的作用域
singleton 默认单例对象 prototype 多例对象
request域 session域 globalsession 全局

init-method : 指定类中初始化方法的名字

destory-method :指定类中销毁方法的名字

spring的IOC对bean对象管理的细节:

创建对象的方式(重要)

1、使用无参构造方法(默认 编译器自动调用)
以上spring演示的方式就是这种。
弊端:如果类存在于jar包,其中无源码只有class文件的话,无法操作构造方法

<!--默认的无参构造方法-->
    <!--<bean id="accountService" class="com.neuedu.service.impl.AccountServiceImpl">

    </bean>-->

创建一个类的对象,并给类中的属性注入值
在这里插入图片描述

在这里插入图片描述

有参构造方法可以直接通过参数名(记住这个就可以了)
在这里插入图片描述

在这里插入图片描述
起别名(配置关于bean对象的信息)
在这里插入图片描述
applicationContext.xml
这个是一个总的容器。
比如
在这里插入图片描述

当创建出两个bean.xml的文件,可以把两个文件配置的对象合并到一起
在这里插入图片描述
合并
在这里插入图片描述
总结
在这里插入图片描述

2、用类中的方法创建对象,存储到spring容器中(常用)
在这里插入图片描述

在这里插入图片描述

<!--非静态方法获取对象-->
    <!--<bean id="instanceFactory" class="com.neuedu.factory.InstanceFactory">

    </bean>
    <bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService">

    </bean>-->

在这里插入图片描述
3、使用工厂中的静态方法创建对象,存储到spring容器中
在这里插入图片描述
在这里插入图片描述

<!--静态方法获取对象-->
    <bean id="accountService" class="com.neuedu.factory.StaticFactory" factory-method="getAccountService">

    </bean>

在这里插入图片描述
作用域分为单例和多例。

生命周期(重要)

	bean对象的生命周期
	单例:
	1、创建期:被容器创建时对象产生
	2、存在期:只要容器存在对象就存在
	3、销毁期:容器销毁即销毁

    多例:
    1、创建期:当需要使用对象时,Spring框架为我们创建
    2、存在期:只要对象被使用的过程中,对象就一直存在
    3、销毁期:当对象长时间不用的时候,且没有对象的引用,由java垃圾回收器进行回           收

Spring 依赖注入

	Spring给我们提供了管理机制,也就所有的依赖关系由Spring DI管理。
	DI就是依赖注入:(独自见解)
	我们普通的创建对象可以通过有参的构造方法直接附值给类中属性、或者再通过对象
	调用set方法。而spring DI中注入方式也给我们提供了对应构造方法和set方法实现注
	入,提供了constructor-arg标签向对象中注入数据的方式.而在创建对象的过程中
	Spring可以依据配置对象的属性进行设置,这个过程称之为依赖注入,也即DI。

管理依赖注入

依赖注入的意思:
在这里插入图片描述

给类中这些熟悉进行注入,设置get/set方法
在这里插入图片描述
在这里插入图片描述

	可以实现依赖注入的数据分为三类:
	1、基本数据类型和String
	2、Bean类型(bean.xml中配置的对象,自己封装的对象),或者注解配置过的Bean对象。
	3、复杂数据类型,集合类型。

依赖注入三种方式

1、构造方法提供注入:
	创建对象的同时把数据注入对象,相当于初始化属性。
    利用<constructor-arg>标签,位置在<bean>标签内部

type :该属性用于指定注入数据的数据类型,构造方法中的参数的类型。
index:该属性给构造方法中指定索引位置参数赋值,从0位置开始。

标签内常用的属性
name:给构造方法中指定名称的参数赋值,最常用。
value:用于提供基本类型和String类型的数据
ref: 指定bean类型等其他的数据,比如自己封装的,集合,日期。

优劣势

优势:在获取bean对象时,在创建对象的同时可以做到立刻有对应的属性数据
劣势:如果改变了bean对象的实例化方式,那么在创建对象时只有一种有参数的构造方	
法,那么也必须提供该参数去创建对象(方法重载的话太麻烦不使用)。

注意

实际开发中,我们要求如果无法避免必须使用构造的注入,那么不要轻易使用构造注入
给对象注入基本数据类型和String类型。

演示
新建工程
在这里插入图片描述
加入jar包,百度搜索maven复制粘贴
在这里插入图片描述
在这里插入图片描述
在实现类中写构造方法
在这里插入图片描述

依赖注入给属性赋值
在这里插入图片描述
拿到对象调用方法
在这里插入图片描述
其他数据类型

一个bean标签代表创建了一个对象,只不过一个bean标签中的对象在另个bean中当做属性存在 如下图
在这里插入图片描述
注入
在这里插入图片描述

<!--配置service-->
    <bean id="accountService" class="com.neuedu.service.impl.AccountServiceImpl">
        <constructor-arg name="name" value="哈哈"></constructor-arg>
        <constructor-arg name="age" value="18"></constructor-arg>
        <constructor-arg name="birthday" ref="now"></constructor-arg>
    </bean>

<bean id="now" class="java.util.Date"></bean>

测试
在这里插入图片描述

2、通过set方法实现注入(重要)

使用最多的依赖注入方式,常用的方式。
前提:必须有set方法,在实现类中。
property标签,书写位置在bean标签中。
在这里插入图片描述
在这里插入图片描述

<bean id="accountService2" class="com.neuedu.service.impl.AccountServiceImpl2">
        <property name="name" value="呵呵"></property>
        <property name="age" value="20"></property>
        <property name="birthday" ref="now"></property>
    </bean>

    <bean id="now" class="java.util.Date"></bean>

在这里插入图片描述

set注入方式对比构造方法注入方式的比较?

set注入优势和劣势
优势:创建对象时候,没有参数限制,首先利用无参的构造方法创建对象,然后注入对
应属性信息,符合JavaBean的格式,所以我们更常用的是set方式注入。

劣势:某一个成员必须有值,如果我们没有给对应的值,有可能造成后续的操作问题。
3、通过注解实现注入

专门讲注解的时候统一说明

复杂类型注入

(set方式、构造方式都一样)

1、List结构集合注入数据的标签

List结构集合:数据存储为一列结构的,就是数组注入也可以使用list的标签 
<list> <array> <set>

数组:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

<bean id="accountService3" class="com.neuedu.service.impl.AccountServiceImpl3">
        <property name="myStrs">
            <list>
                <value>QQQ1</value>
                <value>QQQ2</value>
                <value>QQQ3</value>
            </list>
        </property>
<bean>

List集合:
在这里插入图片描述

<property name="myList">
            <list>
                <value>QQQ1</value>
                <value>QQQ2</value>
                <value>QQQ3</value>
            </list>
        </property>

set集合:

<property name="mySet">
            <set>
                <value>QQQ1</value>
                <value>QQQ2</value>
                <value>QQQ3</value>
            </set>
        </property>

2、Map结构集合注入数据的标签(双列结构的)
<map> <props>
在这里插入图片描述

<property name="myMap">
            <map>
                <entry key="111" value="AAA"></entry>
                <entry key="222" value="BBB"></entry>
            </map>
</property>

在这里插入图片描述

<property name="myPros">
            <props>
                <prop key="111">CCC</prop>
                <prop key="222">DDD</prop>
            </props>
        </property>

Spring注解

概念:
注解替代了xml中标签的使用
以上xml文件中的bean标签配置的格式是这样的:

<bean id="accountService" class="com.neuedu.service.impl.AccountServiceImpl"
          scope="" init-method="" destroy-method="">
        <!--set方式的依赖注入-->
        <property name="" value=""></property>
    </bean>

用注解配置需要开启注解,添加约束:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

<context:component-scan base-package="com.neuedu"></context:component-scan>

演示一下注解的操作方式

新建工程
在这里插入图片描述
配置pom文件
在这里插入图片描述
把上一个spring工程的src文件替换过来,否则还得建包结构
在这里插入图片描述
如红线所示添加注解的约束
在这里插入图片描述
开启注解
在这里插入图片描述
注意 小知识点 如图所示
在这里插入图片描述
用注解配置
在这里插入图片描述
创建对象
在这里插入图片描述
@Component创建对象的注解

作用与xml文件中配置bean标签实现是一致的
属性: value

用于指定bean的id,如果不写,value默认的值是当前的类名(首字母必须是小写)
实际中有衍生版的注解,通过Component实现的,在不同层次都是创建对象的
@Controller  表现层
@Service     业务逻辑层
@Repositroy  持久层
上述三个注解作用和属性和@Component一模一样的

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
单例注解
在这里插入图片描述
在这里插入图片描述

@Configuration

这种方式不需要spring的xml配置对象,而是java的注解。也就是纯Java配置bean。springboot源码就是用了这个注解实现的

在这里插入图片描述
配置文件
在这里插入图片描述
在这里插入图片描述
整合多个配置文件的注解
相当于之前的import标签
在这里插入图片描述
在这里插入图片描述

总结
在这里插入图片描述
在这里插入图片描述

@Autowired
用于注入数据的注解,等价于<property> 标签。

作用:自动按照类型注入。
要求:容器中有唯一的一个bean对象类型和要注入的变量类型匹配
弊端:如果ioc容器没有bean的类型和要注入的类型匹配(匹配不上),报错。
所以利用注解实现依赖注入的操作习惯:
先利用类型查找,如果是同类型,再用变量名查找。
注意:使用该注解,set方法不是必须存在的

这些注解可以存在位置:
可以放在变量上
可以放在方法上

在这里插入图片描述

service层注解
在这里插入图片描述
dao层注解
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
@Qualifier

作用:在按照类型中注入的基础上,再次按照名称注入,就是先根据类型找,类型多
          个的时候再根据变量名找,然后注入数据。
注意:它在给类的成员注入时不能单独使用,给方法参数注入时可以单独使用
属性:value 用于指定注入的bean的id

在这里插入图片描述

@Resource

作用:直接按照bean的id查找然后注入,它是可以独立使用。
属性:name 用于指定bean的id。

在这里插入图片描述
在这里插入图片描述

注解注入一个对象操作流程:(图解)

在这里插入图片描述

上面三个注解只能注入其他bean类型(我们自己写的或者官方认可的)的数据
注意:
1、基本数据类型(Integer、char…)和String类型无法使用上面的注解实现的
   (但有单独的注解配合使用)
2、集合类型注入只能通过xml方式实现

@Value

作用:注入基本数据类型和String类型的
属性:value 用于指定数据的值,它可以使用Spring中EL表达式(缩写SpEL)
格式:${表达式}

在这里插入图片描述

@Scope注解

用于改变作用范围(作用域)
实现与bean标签中的scope属性是一样
属性:value 指定取值范围  singleton prototype(单例和多例)

在这里插入图片描述

和生命周期相关(了解)
@PreDestroy
destroy-method=""
用于销毁方法

@PostConstruct
init-method=""
用于初始化方法
注意:正常默认是单例模式
如果是多例对象,不负责销毁

在这里插入图片描述

学习方式 note.md文件

idea是可以建立.md文件,写笔记,不如经常用的约束,依赖,注解。
在这里插入图片描述

Spring AOP

代理模式(底层代码原理):

23中设计模式的一种;包括单例模式
目的:真实对象之间纯粹的做一件事情,其他乱七八糟的事情交给代理对象。
以下是AOP的底层原理

静态代理

在这里插入图片描述

你,租房的人 就是客户(由他去访问代理角色)

代码
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
代理模式的模拟真实案例
一个接口或抽象方法即抽象对象
实现类即真实对象
在这里插入图片描述
真实对象
在这里插入图片描述
真实对象
在这里插入图片描述
在这里插入图片描述
这是实际的实现
需求:实现的每一步操作都需要打印日志。
前提:所有的程序都不希望在源码上更改,那么在不改变源码情况下给方法
加四个日志。
实现:通过代理对象实现。
缺点:代码量翻倍。

创建一个代理对象
在这里插入图片描述
在这里插入图片描述
思路图解
原有的业务流程不改动,而是使用代理横切进去,实现增加的需求。
在这里插入图片描述

动态代理

动态代理的由来,我们即要使用代理对象,还要不使代码量增加,那么动态代理来了。

个人理解:动态代理通过反射动态的加载一些类

在这里插入图片描述
代码实现:

在这里插入图片描述

抽象对象
在这里插入图片描述
真实对象
在这里插入图片描述
代理对象请求处理类
目的: 得到代理类,执行真正执行的方法(租房子)
在这里插入图片描述
模拟客户
getProxy()方法就是通过反射动态生成的。
在这里插入图片描述
在这里插入图片描述
以上就搭建好了动态代理
现在我们想程序中纵向切入两个方法,在方法执行前和之后。
在这里插入图片描述
在这里插入图片描述

重要(理解这个就可以了)

以上推导过程理解即可
生成不同代理对象需要去修改代理类。抽取请求处理类使之更灵活,直接使用即可。

请求处理类:代理谁 + 生成代理类 + 执行方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
最终实现的需求是执行操作前添加日志

通过反射实现
添加日志的方法,改造
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结,请求处理类相当于一个工具类,需求不同的代理对象,直接调即可。都是利用反射实现的,我们不需要写,只是理解。

在这里插入图片描述

利用spring框架来实现AOP

方式1 利用spring API 主要接口实现

在这里插入图片描述

创建类 抽象对象和真实对象
在这里插入图片描述
打印日志的方法,
在这里插入图片描述
建立联系,把打印日志的方法(通知)在作用在insert等方法(切点)上,这个过程叫做织入。

表达式:访问修饰符 包名.包名.包名…类名.方法名(参数列表)

 * com.neuedu.service.impl.*.*(..)

在这里插入图片描述
调用,注意动态代理代理的是一个接口即抽象对象。
在这里插入图片描述
在这里插入图片描述
简单 对象之间互不干扰。

通过以上例子图解
在这里插入图片描述

在这里插入图片描述
总结:静态代理代理的是实现类(真实对象),动态代理代理的是接口(抽象对象)。抽象对象spring给我们生成,我们只需要在容器中拿出来使用。

方式2 自定义实现AOP 主要面向切面定义(建议)

织入自定义的方法
利用了切面的概念,其实就是一个类,我们自定义的一个类,类中是通知的方法。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

方式3 利用注解方式实现AOP

在这里插入图片描述
在这里插入图片描述
注意:需要开启注解支持
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

拓展
了解增强方法的执行顺序
在这里插入图片描述
在这里插入图片描述

以下为自己的理解整理

面向切面编程,是面向对象的延续。通过预编译方式和运行期间动态代理实现程序功能,
从而进行统一维护的一种技术.

通俗的说,将程序重复代码抽取出来,需要执行的时候使用动态代理的方式。
实现不修改源码的基础上,对已有的方法实现增强。

个人理解:
代码需要完善,但是不修改代码,所以使用AOP面向切面编程。面向切面就是切一个
面,在面上找到点就可以把需要的功能动态的放到方法里面,从而实现功能,也就是说
增强了原来的方法。

1)连接点(JoinPoint):指的是那些被拦截的点,在spring中这些点就是方法。
2)切入点(Pointcut):对哪些连接点进行拦截,增强某个方法需要用切入点实现。
3)通知(增强 Advice): 指的是拦截到连接点(JoinPoint)后要做的事情,也就是对方法
   的操作。
4)(了解)引介(Introduction) 一种特殊的通知在不修改类代码的前提下,可以在运
   行期间为类动态的添加一些方法或者属性。
5)织入 Weaving 指增强应用到目标对象来创建新的代理对象的过程  spring采用动态织
   入。
6)代理 Proxy  一个类被AOP织入增强后,就会产生一个结果代理类。
7)切面 Aspect 是切入点和通知的结合(结合的是引进)。

通知类型:
前置通知、后置通知、异常通知、最终通知、(这四个为基本通知)。
环绕通知。

了解:
动态代理技术:字节码随时使用随时创建,并且随时加载。
两种方式:
1、基于接口动态代理 利用官方JDK实现的(了解)
2、基于子类的动态代理 利用第三方插件CGlib(了解)

在这里插入图片描述

整合mybatis

这种方式回顾mybatis,

pom.xml

<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.13</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.2</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>
    </dependencies>

注意 需要用到这个依赖 mybatis-spring,连接数据源需要spring-jdbc
在这里插入图片描述

1 新建实体类
在这里插入图片描述
2 mabatis的核心配置文件(起名应该是mybatisConfig.xml,不用理会)
在这里插入图片描述
接口
在这里插入图片描述
对应接口的xml配置
在这里插入图片描述
测试
在这里插入图片描述
在这里插入图片描述
我们开始利用在spring框架上整合mybatis。

方式一:重要

在这里插入图片描述

spring的bean.xml中这三个配置文件是固定的
在这里插入图片描述
整合后不需要再配置mybatis的xml配置文件,而是写一个实现类在里面实现。然后在spring的bean.xml中给它配置对象和sqlSessionTemplate模版对象。
在这里插入图片描述
bean.xml中配置实现类对象查数据
在这里插入图片描述
在这里插入图片描述
总结:多了一个实现类,里面去实现mybatis的事情

方式二:

直接继承SqlSessionDaoSupport类,即可得到sqlSessionTemplate对象,省去注入sqlSessionTemplate的过程

在这里插入图片描述
在这里插入图片描述

事务

在这里插入图片描述

现在有一个需求,增加一条数据然后再删除这条数据,这个需求在一个方法中,必须都执行成功。
目的:通过AOP配置事务,使我们在执行增删改查的时候自动将事务织入到程序中。
在上一个bean.xml增加
在这里插入图片描述

以下是根据王xx总结

Spring开发流程

两个过程:

开发过程(自己写代码)
1、编写核心业务代码(程序的主线),程序员编写(要求我们需要了解业务逻辑需
   求)。
2、将公用的代码抽取出来,写成通知,开发最后阶段实现  程序人员来做。
3)配置文件:负责切入点和通知的关系说明,我就将它叫做切面。

运行过程(Spring框架为我们完成)
Spring框架运行原理:Spring框架监控切入点方法的执行,一旦监控到切入点被运行,
使用代理机制,动态地创建对象,同时根据通知类型在代理对象的对应位置,将通知对
应的功能织入,从而完成对代码逻辑的增强。

实际结构搭建(重要)

在这里插入图片描述

1、基于XML方式的AOP的搭建

1)在核心配置文件中,添加解析切入点表达式jar

<!--解析切入点表达式-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.7</version>
        </dependency>

2)开始配置AOP的bean.xml

1、先将通知Bean交给Spring IOC来管理
<bean id="accountService" class="com.neuedu.service.impl.AccountServiceImpl">

</bean>

2、使用aop:config标签表明开始AOP的配置
<!--配置AOP-->
<aop:config>
    
</aop:config>

3、使用aop:aspect标签声明配置的切面
id属性:是提供给切面的一个唯一标识
ref属性:指定和通知类对应的bean标签中id属性建立连接
<!--配置AOP-->
<aop:config>
    <aop:aspect id="logAdvice" ref="logger">

    </aop:aspect>
</aop:config>

4、在aop:aspect标签内部使用对应的标签来配置通知的类型
让printLog方法在切入点方法执行之前执行,我们实现的是一个前置通知

aop:before:配置前置通知
method:用于指定Logger类(切面)中哪个方法是前置通知
pointcut:指定切点表达式,指的是对应业务层中哪些方法实现增强
pointcut属性放的是切点表达式

切点表达式格式
关键字 execution(表达式)
表达式:访问修饰符 返回值 包名.包名.包名...类名.方法名(参数列表)

切点表达式的演化过程:
public void com.neuedu.service.impl.AccountServiceImpl.saveAccount()
太长了,太麻烦
实际中一般我们不写成全路径的信息的切点表达式

* *..*.*(..) 太简单 没有一定标识含义

* void com.neuedu.service.impl.AccountServiceImpl.saveAccount()

* * *.*.*.*.AccountServiceImpl.saveAccount()

* *..AccountServiceImpl.saveAccount()

* *..*.*(..)

* com.neuedu.service.impl.*.*(..)
开始动手操作

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述 在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
补充
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
执行结果
在这里插入图片描述

四种通知配置
<!--配置AOP-->
    <aop:config>

        <aop:pointcut id="ptl" expression="execution(* com.neuedu.service.impl.*.*(..))"/>

        <!--配置切面-->
        <aop:aspect id="logAdvice" ref="logger">

            <!--配置前置通知-->
            <aop:before method="beforePrintLog" pointcut-ref="ptl"></aop:before>

            <!--配置后置通知-->
            <aop:after-returning method="afterPrintLog" pointcut-ref="ptl"></aop:after-returning>


            <!--配置异常通知
            注意:异常通知和后置通知只能有一个
            -->
            <!--<aop:after-throwing method="exceptionPrintLog" pointcut="execution(* com.neuedu.service.impl.*.*(..))"></aop:after-throwing>-->

            <!--配置最终通知,无论切入点方法是否正确都正常执行-->
            <aop:after method="finallyPrintLog" pointcut-ref="ptl"></aop:after>

        </aop:aspect>

    </aop:config>

代码演示:
创建工程demo05
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
补充
在这里插入图片描述
可以简化每个通知的切点表达式

<aop:pointcut id="pt1" 
expression="execution(*com.neuedu.service.impl.*.*(..))"></aop:pointcut>
配置切入点表达式 aop:pointcut
id属性:用于指定表达式的唯一标识。
expression属性:用于指定表达式内容
注意:此标签写在aop:aspect标签内部只能当前切面使用。还可以写在
aop:aspect外面,此时就变成了所有切面可用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

环绕通知配置(特殊)
概述:
Spring 通知 环绕通知
与之前的四个通知互斥的 (前置、后置、异常、最终)
通知都是为了增强切入点的方法——事务处理使用
<!--配置环绕通知-->
<aop:around method="aroundPrintLog" pointcut-ref="ptl">

</aop:around>

代码运行出现问题:
当使用环绕通知后,切入点方法没有执行,只是执行了增加的功能(通知的方法)。
为什么?

动态代理的环绕通知有明确的切入点方法调用,而我们在代码中是没有调用的。

解决:spring为我们提供了一个接口

ProceedingJoinPoint,接口中有一个方法proceed(),当我们调用该方法时,相当于明确
了切入点方法。
/**
     * 环绕通知
     * */
    public Object aroundPrintLog(ProceedingJoinPoint pjp){
        Object rtValue = null;
        try {
            Object[] args = pjp.getArgs();//得到方法执行所需要的参数
            //模拟前置通知
            System.out.println("beforePrintLog,记录了日志...");
            //参数是一个Object[] 类型   明确调用业务逻辑方法(切入点方法)
            pjp.proceed(args);
            //模拟后置通知
            System.out.println("afterPrintLog,记录了日志...");
            return args;

        } catch (Throwable throwable) {//如果使用exception捕获,是无法捕获到异常
            //模拟异常通知
            System.out.println("exceptionPrintLog,记录了日志...");
            throw new RuntimeException();
        }finally {
            //模拟最终通知
            System.out.println("finallyPrintLog,记录了日志...");
        }

    }

基于XML实现的AOP,并且实现了切入点方法的增强(通知:4个基本通知),而环绕通知一般用于注解形式的AOP
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、基于注解的AOP配置

bean文件

<!--配置Spring针对IOC的配置,扫描包中的注解-->
 <context:component-scan base-package="com.neuedu"></context:component-scan>

   <!--针对AOP 配置spring开启AOP注解的支持-->
   <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

环绕通知通过注解实现的AOP–不要与四种基本通知一起使用

演示过程:利用之前的工程
包结构
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
通知(加强的文件)
在这里插入图片描述
bean.xml
在这里插入图片描述
注意:通常情况下,环绕通知都是独立使用的。
如果使用注解,建议使用环绕通知。

不使用XML的配置方式
@Configuration
作用: 用于指定当前类是一个spring配置类,当创建容器时会从该类上加载注解。获取
容器时需要使用AnnotationApplicationContext(有@Configuration注解的类.class)。
属性: value:用于指定配置类的字节码
@Configuration 
public class SpringConfiguration { }
@ComponentScan
作用: 用于指定spring在初始化容器时要扫描的包。作用和在spring的xml配置文件中
的: <context:component-scan base-package="com.itheima"/>是一样的。
属性: basePackages:用于指定要扫描的包。和该注解中的value属性作用一样。
/**
*spring的配置类,相当于bean.xml文件
*/
@Configuration 
@ComponentScan("com.neuedu") 
public class SpringConfiguration { }
新建一个类
package config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * 该类是一个配置类,它的作用和bean.xml是一样的
 * spring中的新注解
 * Configuration
 *     作用:指定当前类是一个配置类
 *     细节:当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写。
 * 
 * ComponentScan
 *      作用:用于通过注解指定spring在创建容器时要扫描的包
 *      属性:
 *      value:它和basePackages的作用是一样的,都是用于指定创建容器时要扫描的包。
 *      我们使用此注解就等同于在xml中配置了:
 *      <context:component-scan base-package="com.neuedu"></context:component-scan>
 */
@Configuration
//简写@ComponentScan("com.neuedu")
@ComponentScan(basePackages = "com.neuedu")
public class SpringConfiguration {
//...
}

@Component("Logger")
@EnableAspectJAutoProxy
@Aspect//表示当前类是一个切面类
public class Logger {...}
测试类:
package com.neuedu.test;

import com.neuedu.service.AccountService;
import config.SpringConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AOPTest {
    public static void main(String[] args) {
        //1.获取容器
        ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
        //2.获取对象
        AccountService as = (AccountService)ac.getBean("accountService");
        //3.执行方法
        as.saveAccount();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值