传统MVC项目违背的开发原则:
|--OCP原则:即允许功能扩展,禁止源码修改
|--DIP原则(依赖倒置原则):即在开发中应该尽可能面向接口编程,面向抽象编程
|--DIP原则是为了尽可能降低耦合度,提高扩展性
违背DIP原则的解决措施:
|--采用IoC策略:即控制反转的思想,将new对象和维护对象的权力交出去
|--IoC的实现方式为DI注入(包含set方法注入和构造方法注入两种)
|--DI注入其实就是提供方法接收别人创建和维护好的对象
Spring项目的基本创建流程:
|--创建一个Maven工程并导入spring-context依赖
|--spring-context依赖只是一个基本依赖,如果有需要其他spring功能记得也一并添加
|--在resources文件夹下创建spring容器的配置文件
|--在resources文件夹下创建是因为maven工程会将resources文件夹路径当成项目根路径,便于获取该配置文件
|--配置文件中的基本配置如下:
<!--用于将对应的bean类加入到spring容器中,XX为该bean的别名(不可重复),YY为该bean的全限定类名-->
<bean id="XX" class="YY">
<!--用于在一个bean中set注入其他bean对象,spring会自动调用需要注入bean对应的set方法-->
<!--XX一定要为所注入bean对应set方法去掉set后将首字母小写的名字-->
<!--YY为需要注入的bean类的别名-->
<property name="XX" ref="YY"/>
<!--用于在一个bean中构造注入其他bean对象,spring会自动调用当前bean中的构造方法-->
<!--XX为构造方法中参数的下标,从0开始-->
<!--YY为对应参数位置上所需要bean的别名-->
<constructor-arg index="XX" ref="YY"/>
<!--用于在一个bean中构造注入其他bean对象,spring会自动调用当前bean中的构造方法-->
<!--XX为构造方法中参数的变量名-->
<!--YY为对应参数变量所需要bean的别名-->
<constructor-arg name="XX" ref="YY"/>
</bean>
|--在需要bean对象的地方通过new ClassPathXmlApplicationContext("XX")得到一个ApplicationContext对象,再由该对象调用getBean("YY")方法得到
|--ClassPathXmlApplicationContext构造方法会自动从类路径下开始检索
|--注意成功检索到配置文件后会立即为容器中的bean创建对象(默认调用对应bean类的无参构造创建)
|--注意也可以用其他检索类进行检索,不唯一
|--XX为spring的配置文件路径(注意可以同时传递多个配置文件的路径)
|--YY为需要获取的bean对象别名(注意除了别名还可以传入一个需要spring帮助我们强转的class类型作为参数)
Set注入的注意事项:
|--Set注入时可以采用在property标签体内定义内部bean的形式代替property标签中的ref属性
|--注意内部bean不需要写id属性(即不用取别名)
|--Set注入的是简单类型时可以将property标签中的ref属性替换成value属性,直接传递简单类型的值
|--注意由于如果将Date当成简单类型对其value值的格式要求过于繁琐,故实际开发中我们一般将Date当成复杂类型
|--使用级联方式注入:即在一个bean中注入另一个bean并且在该bean中为另一个bean的属性赋值
|--格式为:<property name="XX.YY" value="ZZ"/>
|--XX为所注入bean对应get方法去掉get后将首字母小写的名字
|--YY为需要赋值的属性名
|--ZZ为需要赋的属性值
|--注意采用级联的方式注入需要为参与级联的bean对象提供get方法
|--可以理解为spring会自动调用get方法取到该对象,再调用该对象的set方法为属性赋值
|--注意级联注入必须放在所对应bean注入的下方
|--可以理解为只有先注入了bean,调用get方法时才能取到这个bean对象
|--简单类型的数组、List集合、Set集合注入
|--省略property标签中的ref属性,改用内部array标签/list标签/set标签配合value标签的形式注入
|--格式为:<property name="XX">
<array、list、set>
<value>YY<value>
</array、list、set>
</property>
|--XX为所注入bean对应set方法去掉set后将首字母小写的名字
|--YY为需要给数组中的元素赋的属性值
|--复杂类型的数组、List集合、Set集合注入
|--省略property标签中的ref属性,改用内部array标签/list标签/set标签配合ref标签的形式注入
|--格式为:<property name="XX">
<array、list、set>
<ref bean="YY">
</array、list、set>
</property>
|--XX为所注入bean对应set方法去掉set后将首字母小写的名字
|--YY为需要给数组中元素存入的bean的别名
|--简单类型Map集合的注入
|--省略property标签中的ref属性,改用内部map标签配合value标签的形式注入
|--格式为:<property name="XX">
<map>
<entry key="YY" value="ZZ">
</map>
</property>
|--XX为所注入bean对应set方法去掉set后将首字母小写的名字
|--YY为需要给map中存入元素的key值
|--ZZ为需要给map中存入元素的value值
|--复杂类型Map集合的注入
|--省略property标签中的ref属性,改用内部map标签配合ref标签的形式注入
|--格式为:<property name="XX">
<map>
<entry key="YY" ref="ZZ">
</map>
</property>
|--XX为所注入bean对应set方法去掉set后将首字母小写的名字
|--YY为需要给map中存入元素的key值
|--ZZ为需要给map中存入元素的value值所对应bean的别名
|--properties集合的注入
|--省略property标签中的ref属性,改用内部props标签配合prop标签的形式注入
|--格式为:<property name="XX">
<props>
<prop key="YY">ZZ</prop>
</props>
</property>
|--XX为所注入bean对应set方法去掉set后将首字母小写的名字
|--YY为需要给properties集合中存入元素的key值
|--ZZ为需要给properties集合中存入元素的value值
|--注意因为properties集合的value值只能为字符串,故只有简单注入
|--注意如果注入时不注入值默认是null
|--不注入值是指直接不写property标签中的value属性,不等同于空字符串
|--解决value属性值中有特殊字符的问题
|--方式一:采用转义字符代替特殊字符
|--方式二:由于是一个xml文件,可以考虑采用CDATA区包裹特殊字符,但这种做法只能使用内部value标签
|--格式为<property name="XX">
<value><![CDATA[YY]]></value>
</property>
|--XX为所注入bean对应set方法去掉set后将首字母小写的名字
|--YY为包含特殊字符的内容
命名空间简化bean注入:
|--p命名空间简化注入
|--使用p命名空间需要在配置文件beans标签中引入xmlns:p="http://www.springframework.org/schema/p"
|--引入p命名空间后可用p:XX="YY"属性为简单属性赋值
|--XX为所注入bean对应set方法去掉set后将首字母小写的名字
|--YY为需要给该属性赋的值
|--引入p命名空间后可用p:XX-ref="YY"属性为复杂属性赋值
|--XX为所注入bean对应set方法去掉set后将首字母小写的名字
|--YY为需要注入的bean的别名
|--注意p命名空间用于简化set注入
|--c命名空间简化注入
|--使用c命名空间需要在配置文件beans标签中引入xmlns:c="http://www.springframework.org/schema/c"
|--引入c命名空间后可用c:XX="YY"属性为简单属性赋值
|--XX为所注入bean对应构造方法中参数的下标或名字(注意如果是下标前面要加下划线)
|--YY为需要给该参数赋的值
|--引入c命名空间后可用c:XX-ref="YY"属性为复杂属性赋值
|--XX为所注入bean对应构造方法中参数的下标或名字(注意如果是下标前面要加下划线)
|--YY为需要注入的bean的别名
|--注意c命名空间用于简化构造注入
|--util命名空间简化注入
|--使用util命名空间前提
|--需要在beans标签中引入xmlns:util="http://www.springframework.org/schema/util"
|--需要为beans标签中xsi:schemaLocation属性添加http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
|--引入util命名空间后可以使用<util:XX id="YY">ZZ</util>标签简化集合的注入
|--XX为集合的类型
|--YY为该集合bean的别名
|--ZZ同正常集合注入的格式
|--通过util绑定集合后若其他地方需要注入该集合直接通过注入复杂类型的方式指向对应的别名即可
|--注意util命名空间用于简化集合的注入
自动注入(即自动装配)机制:
|--根据名称自动注入
|--在bean标签内添加autowire="byName"属性,spring容器会自动检索有哪些bean需要注入,然后根据名字查找并进行set注入
|--注意采用根据名称自动注入的方式给需要注入的bean取别名时必须为对应set方法去掉set后将首字母小写的名字
|--根据类型自动注入
|--在bean标签内添加autowire="byType"属性,spring容器会自动检索有哪些bean需要注入,然后根据类型查找并进行set注入
|--注意采用根据类型进行注入的方式应确保需要注入的bean只有一个实例,否则容器不知道找哪一个
引入外部文件中的内容:
|--使用外部文件中内容的前提
|--外部文件中的内容得保证为key=value的形式
|--需要在beans标签中引入xmlns:context="http://www.springframework.org/schema/context"
|--需要为beans标签中xsi:schemaLocation属性添加http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
|--通过<context:property-placeholder location="XX"/>标签指向文件
|--XX为对应的文件路径
|--注意location属性会默认从类的根路径下开始检索
|--在需要使用外部文件内容的地方通过${XX}使用,XX为对应的key值
|--注意由于spring容器会先检索系统文件中的key,故实际开发中我们会给key值添加前缀防止重名
bean的作用域:
|--通过在bean标签中添加scope="XX"属性设置bean的作用域,XX常取为singleton、prototype、request、session、application
|--singleton表示该bean为单例,且在spring一启动时就进行创建
|--prototype表示每次注入的bean都为一个新的对象,且只在需要注入时才创建该bean的对象
|--request表示一个请求对应一个新的bean对象
|--session表示一个会话对应一个新的bean对象
|--application表示一个项目对应一个新的bean对象
|--注意不写scope属性的话默认为单例作用域
|--自定义作用域
|--通过给spring配置类中的scopes属性注入我们自定义的作用域类达到自定义作用域的效果
|--注意我们自定义的作用域类必须要实现scope接口
|--具体格式
|--<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="XX">
<bean class="YY"/>
</entry>
</map>
</property>
</bean>
|--其中XX为自定义作用域的名字,YY为自定义的作用域类的全限定类名
|--不过实际开发中很少自定义作用域类,一般直接使用sping为我们提供好的,如org.springframework.context.support.SimpleThreadScope等
工厂模式(属于GoF设计模式之一):
|--简单工厂模式:即将生产行为和消费者分隔开
|--包含抽象产品模块、具体产品模块、具体工厂模块
|--消费者直接告诉具体工厂模块自己需要的是什么产品并以抽象产品模块的形式进行接收,由工厂自己调用具体产品模块进行生产
|--注意具体工厂模块中的方法应为静态
|--工厂方法模式:用于优化简单工厂模式中易违背ocp原则的问题
|--包含抽象产品模块、具体产品模块、抽象工厂模块、具体工厂模块
|--可以理解为将简单工厂模式中的一个工厂按类别分为不同种类的工厂,消费者根据自己的需要去找对应的工厂,后续同简单工厂模式
|--采用这种方式后如果诞生了新种类的工厂直接新建一个具体工厂模块继承抽象工厂模块即可
|--抽象工厂模式:解决工厂方法模式中会出现类爆炸问题
|--在工厂方法模式的基础上将多种相似的具体工厂模块合并为一个具体工厂类模块
|--可以理解为抽象工厂模式就是将简单工厂模式和工厂方法模式的特点相结合
spring中bean的四种实例化方式:
|--基本实例化
|--在bean标签中指定id属性和class属性,让spring自动调用对应的无参构造进行创建
|--class属性中写的是需要实例化bean的全限定类名
|--简单工厂实例化
|--在bean标签中指定id属性、class属性、factory-method属性,让spring自动调用对应工厂类中的对应方法得到bean对象
|--class属性中写的是工厂类的全限定类名
|--factory-method属性中写的是工厂类中能够得到bean对象的方法名
|--工厂方法实例化
|--在bean标签中指定id属性、factory-bean属性、factory-method属性,让spring自动调用对应工厂类中的对应方法得到bean对象
|--factory-bean属性中写工厂类bean的别名
|--factory-method属性写的是工厂类中能够得到bean对象的方法名
|--可以理解为就是在简单工厂实例化的基础上,将工厂类单独作为一个bean引入,然后用一个新的bean去找这个工厂类bean
|--使用spring提供的FactoryBean方式实例化
|--即自定义的工厂类实现spring提供的FactoryBean接口,并在getObject方法中返回需要实例化的bean对象
|--在配置文件中直接用基本实例化的方式实例化这个自定义工厂类即可
|--可以理解为spring在实例化bean的时候如果检测到这是个受spring管理的工厂类,会自动调用类中getObject方法
|--实际开发中常用FactoryBean类对需要创建的bean进行一系列加工
|--注意FactoryBean和BeanFactory不是一个东西
|--FactoryBean是工厂bean,本质上还是一个bean
|--BeanFactory是bean工厂,本质上不是一个bean
bean的生命周期:
|---> 调用构造方法创建bean对象
-> 执行set方法进行注入
-> 检查bean是否实现了Aware的相关接口,如果实现了则自动调用所实现的方法
-> 调用bean后处理器类中的before方法
|--我们自定义的类只有实现了BeanPostProcessor接口并在配置文件中进行配置后才可以称为bean后处理器
|--注意bean后处理器对其所在配置文件中的所有bean起作用
-> 检查bean是否实现了InitializingBean接口,如果实现了则自动调用所实现的方法
-> 调用init方法进行初始化
|--注意这里的init方法是我们自己写的,需要在bean标签中通过init-method属性进行关联
-> 调用bean后处理器类中的after方法
|--我们自定义的类只有实现了BeanPostProcessor接口并在配置文件中进行配置后才可以称为bean后处理器
|--注意bean后处理器对其所在配置文件中的所有bean起作用
-> 使用bean
-> 检查bean是否实现了DisposableBean接口,如果实现了则自动调用所实现的方法
-> 调用destroy方法销毁bean
|--注意这里的destroy方法是我们自己写的,需要在bean标签中通过destroy-method属性进行关联
|--注意最终实际销毁bean的是ClassPathXmlApplicationContext类中的close方法,调用时可能需要向下转型
|--注意spring只对单例模式的bean进行全生命周期的管理,对非单例的bean只会管理到开始使用bean这一步
将不属于spring管理的bean进行手动注册:
|--new一个DefaultListableBeanFactory实例对象
|--通过DefaultListableBeanFactory实例对象调用registerSingleton("XX",YY)方法将bean注册到spring容器中
|--XX用于设置该bean在spring容器中的别名
|--YY为需要注册的bean
spring中循环依赖的注意事项(即两个bean互相注入的情况):
|--两个单例bean+set注入模式下循环依赖不会存在问题
|--得益于spring在管理bean的时候会先统一调用bean的空参构造进行实例化并曝光,即不等属性赋值就给暴露出引用地址
|--可以简单理解spring通过将bean的实例化和赋值拆分成两步解决循环依赖的问题
|--一个单例bean+一个非单例bean+set注入模式下循环依赖不会存在问题
|--同两个单例bean+set注入情况一样,这种创建过程是有尽头的不会死循环
|--两个非单例bean+set注入模式下循环依赖会存在死循环问题
|--因为非单例bean每次注入都会创建新的对象,故如果循环依赖会一直循环创建对象
|--构造注入下循环依赖,无论bean为单例或非单例均会出现异常
|--因为构造注入调用的是有参构造,故要等所有属性值赋值成功后才可以成功创建对象,进而暴露引用地址
spring的注解式开发:
|--使用注解式开发的前提条件
|--引入spring的aop依赖(引入spring-context依赖即可,会自动关联)
|--在配置文件中引入context命名空间
|--在beans标签中引入xmlns:context="http://www.springframework.org/schema/context"
|--在beans标签的xsi:schemaLocation属性中添加http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
|--在配置文件中指定需要扫描的包路径
|--通过<context:component-scan base-package="XX"/>标签进行指定
|--XX为包路径,会默认从类的根路径下开始检索
|--注意如果为多个包的话可以用逗号间隔
|--通过注解注册bean
|--在需要注册的类上设置 @Repository(XX)、 @Controller(XX)、 @Service(XX)、 @Component(XX)注解中的任意一个
|--注意这几个注解都可以注册bean,本质上没有区别,可以理解为 @Repository(XX)、 @Controller(XX)、 @Service(XX)为 @Component(XX)注解的别名
|--XX用于设置该bean的别名,不写的化默认为类名首字母小写后的名字
|--通过注解注入简单类型
|--在需要注入值的属性上方设置 @Value(XX)注解,XX为简单类型的值
|--注意Value注解不仅可以用在属性上,还可以用在set方法上和构造方法的形参前
|--注意如果直接使用注解注入的话有没set方法都可以成功注入
|--通过注解依据bean类型注入复杂类型
|--在需要注入值的属性上方设置 @AutoWired注解即可,spirng会自动根据该属性的类型寻找对应的bean进行注入
|--注意如果采用这种方式的话,同类型的bean有多个则会注入失败
|--注意AutoWired注解可以使用在属性上、构造方法上、set方法上、构造方法的形参前
|--注意若只有一个构造方法,且构造方法的形参可以和属性呼应上,则AutoWired注解可以省略
|--通过注解依据bean名称注入复杂类型
|--在需要注入值的属性上方设置 @AutoWired注解和 @Qualifier("XX")注解即可,spirng会自动寻找相同名字的bean进行注入
|--XX为需要注入bean的别名
|--注意 @AutoWired注解必须在 @Qualifier注解上方
|--注意因为Qualifier注解和AutoWired注解的关联性,故可以出现的位置同AutoWired注解
|--通过注解既可以依据bean名称又可以根据bean类型注入复杂类型
|--在需要注入值的属性上方设置 @Resource("XX")注解,spring会寻找相同名字的bean进行注入,若找不到再依据类型进行注入
|--XX为需要注入bean的别名
|--注意如果没有指定名字,默认将属性名称作为bean名称
|--注意Resource注解只能出现在属性上方和set方法上方
|--注意使用Resource注解需要引入相关依赖,依赖的坐标如下
|--<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
|--全注解开发(即使用一个类代替spring的配置文件)
|--在代替配置文件的类上添加 @Configuration注解表明这是一个配置类
|--在代替配置文件的类上添加 @ComponentScan("XX")注解表明需要扫描的包路径
|--XX为需要扫描的包路径,为多个的话用数组表示
|--使用全注解开发在获取bean时需要实例化一个AnnotationConfigApplicationContext("XX")对象,在通过该对象调用getBean方法("YY")
|--XX为配置类的class类型
|--YY为需要得到的bean的别名
注解式开发之选择性注册bean:
|--选择性不注册:在<context:component-scan base-package="包路径" use-default-filters="true"></context>标签体中进行配置
|--配置内容为<context:exclude-filter type="annotation" expression="YY">
|--YY可以为Repository、Controller、Service、Component注解全限定类名中的任意一个
|--选择性注册:在<context:component-scan base-package="包路径" use-default-filters="false"></context>标签体中进行配置
|--配置内容为<context:include-filter type="annotation" expression="YY">
|--YY可以为Repository、Controller、Service、Component注解全限定类名中的任意一个
|--其实就是在检索bean注解时指定全放行或不放行,然后再对有特殊需要的bean注解进行处理
使用被spring封装的JDBC注意事项:
|--使用JdbcTemplate需要引入spring-jdbc依赖和数据库本身的驱动依赖
|--为数据源bean注入需要的配置属性
|--在JdbcTemplate的bean标签中注入数据源属性
|--在需要使用的时候得到该bean并调用各种方法进行增删改查
|--update(XX,YY):用于执行所有带有修改性质的操作,XX为sql语句,YY用于给预编译占位符赋值
|--queryForObject(XX,new BeanPropertyRowMapper<>(YY),ZZ):用于将查询的数据封装成指定类型进行返回
|--XX为sql语句
|--YY用于指定数据的返回类型
|--ZZ用于给预编译占位符赋值
|--注意如果返回的是记录条数将返回类型设置为int.class即可
|--query(XX,new BeanPropertyRowMapper<>(YY),ZZ):用于将查询的数据封装成指定类型的集合进行返回
|--XX为sql语句
|--YY用于指定数据的返回类型
|--ZZ用于给预编译占位符赋值
|--batchUpdate(XX,YY):用于批量执行所有带有修改性质的操作
|--XX为sql语句
|--YY为集合对象
|--spring会自动将list中的每一个元素按顺序为预编译中的占位符进行赋值
|--execute(XX,new PreparedStatementCallback<> (){YY}):用于自定义JDBC执行体
|--XX为sql语句
|--YY为PreparedStatementCallback的实现方法,该方法会默认接收到预编译对象作为参数供我们自定义JDBC时使用
代理模式(属于GoF设计模式之一):
|--思想:创建一个和目标对象具有同一种行为的代理对象,由这个代理对象代替目标对象去进行种种操作
|--使用场景
|--客户端无法直接访问目标对象,让代理对象去做桥接
|--目标对象太过脆弱,由代理对象代替目标对象去完成工作以起到保护目标对象的作用
|--代理对象虽然和目标对象是同一种行为,但其行为效果更强,故使用代理对象代替目标对象以达到更好的效果
|--静态代理
|--代理类由我们手动创建,相当于提前准备好
|--注意使用静态代理容易造成类爆炸,并且不好维护
|--动态代理
|--通过字节码技术在需要使用代理类时动态的在内存中生成
|--常用的两种动态代理
|--JDK动态代理:通过Proxy.newProxyInstance(XX,YY,ZZ)方法生成代理类并返回代理类对象
|--XX为目标类的类加载器,用于加载生成的代理类字节码文件
|--可以理解为是为了保证尽可能和目标类一致故使用目标类的类加载器
|--YY为目标类的接口加载器,用于加载目标类所实现的所有接口
|--可以理解为是为了保证尽可能和目标类一致故使用目标类的接口加载器
|--ZZ为我们自定义的处理器类对象
|--该自定义类必须实现InvocationHandler接口并重写其invoke方法
|--注意代理对象调用代理方法时底层会自动帮我们调用invoke方法
|--注意JDK动态代理只能代理接口
|--CGLIB动态代理:得到Enhancer的实例化对象,并通过该对象调用各种方法完成代理对象的创建
|--setSuperclass(XX):设置目标类,XX为目标类
|--setCallback(XX):设置自定义处理器对象,XX为自定义处理器对象
|--注意自定义处理器类必须实现MethodInterceptor接口并重写其intercept方法
|--create():生成代理类并返回代理类的实例化对象
|--注意使用CGLIB需要添加依赖
|--注意CGLIB动态代理既可以代理接口也可以代理类
面向切面编程AOP:
|--思想:即将与主线业务无关且通用的代码提取出来形成独立的组件,在需要的地方进行插入
|--可以将主线业务理解为纵向,提取的代码理解为横向,AOP即是一种横纵交叉的思想
|--实际开发中将主线称为业务逻辑代码,将被提取出来的代码称为交叉业务代码
|--常用术语
|--连接点(Joinpoint):可以插入切面的位置称为连接点
|--切点(PointCut):紧邻所插入切面的方法称为切点
|--通知(Advice):切面中所包含的具体代码称为通知
|--通知根据连接点和切点的相对位置又分为前置通知、后置通知、环绕通知、异常通知、最终通知五种
|--切面(Aspect):切点+通知统称为切面
|--织入(Weaving):把通知应用到连接点上的过程就称为织入
|--代理对象(Proxy):目标对象被织入时所产生的新对象称为代理对象
|--目标对象(Target):被织入通知的对象称为目标对象
|--可以将切面理解为代理类中的一部分,在生成代理类时,会根据切点寻找目标对象的方法,结合通知生成增强版的方法
|--切点表达式
|--格式:execution(AA BB CC.DD(EE) FF)
|--AA:权限修饰符,不写的话默认指定所有权限的方法
|--BB:返回值类型,*号代表返回值类型任意,不可省略
|--CC:全限定类名,.表示当前包以及子包下的所有类,不写默认为指定所有的类
|--DD:方法名,*号表示指定所有名字的方法,不可省略
|--EE:形参列表,()表示指定没有参数的方法,(..)表示指定参数类型和个数随意的方法,(*)表示指定只有一个参数的方法,不可省略
|--FF:异常类型,不写默认指定所有异常类型
|--作用:用于指定通知该往哪些切点上切入
spring框架对AOP的实现方式:
|--准备工作
|--引入spring-aspects依赖
|--在配置文件的beans标签中引入xmlns:context="http://www.springframework.org/schema/context"
|--在配置文件的beans标签中引入xmlns:aop="http://www.springframework.org/schema/aop"
|--在配置文件的beans标签的xsi:schemaLocation属性中添加http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
|--在配置文件的beans标签的xsi:schemaLocation属性中添加http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
|--具体使用
|--在配置文件中使用<aop:aspectj-autoproxy/>开启spring的切面扫描功能
|--在切面类上方添加 @Aspect注解,表名这是一个切面类
|--在切面类上方添加 @Order(XX)注解定义切面的执行优先级
|--XX为正整数数值,数值越小表名优先级越高
|--在切面类中以方法的形式定义通知
|--在通知上方通过 @XX("YY")注解定义通知的具体出现位置
|--XX用于定义是前置通知(Before)、后置通知(AfterReturning)、环绕通知(Around)、异常通知(AfterThrowing)、最终通知(After)的哪一种
|--YY用于设置切点表达式
|--注意环绕通知方法必须要一个ProceedingJoinPoint类型对象的参数,并通过该对象调用proceed方法表名目标函数执行位置
|--注意实际开发中可以在一个方法上通过 @Pointcut("XX")注解定义一个通用的切点表达式
|--XX为需要通用的表达式
|--在需要使用通用表达式的地方直接写该方法名()即可(注意跨包也可以使用,不过使用时要加上全限定类名)
|--spring整合AOP的全注解开发(即使用一个类代替spring的配置文件)
|--在代替配置文件的类上添加 @Configuration注解表明这是一个配置类
|--在代替配置文件的类上添加 @ComponentScan("XX")注解表明需要扫描的包路径
|--XX为需要扫描的包路径,为多个的话用数组表示
|--在代替配置文件的类上添加 @EnableAspectJAutoProxy 注解表明开启切面检索功能
|--使用全注解开发在获取bean时需要实例化一个AnnotationConfigApplicationContext("XX")对象,在通过该对象调用getBean方法("YY")
|--XX为配置类的class类型
|--YY为需要得到的bean的别名
|--注意无论是切面类还是目标类,都需要将其作为bean纳入spring容器的管理
|--注意我们在spring中使用的AOP开发其实是基于spring框架+aspectj框架的AOP开发
spring中的对事务的支持:
|--使用流程
|--在配置文件的beans标签中引入xmlns:tx="http://www.springframework.org/schema/tx"
|--在配置文件的beans标签的xsi:schemaLocation属性中添加http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
|--在配置文件中注册事务管理器bean
|--<bean id="XX" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="YY"/>
</bean>
|--XX为事务管理器bean的别名
|--YY为数据源bean对应的别名
|--在配置文件中通过<tx:annotation-driven transaction-manager="XX">标签开启事务的注解模式
|--XX为事务管理器bean的别名
|--在需要开启事务的地方添加 @Transactional注解即可
|--在方法上添加表明对该方法开启事务管理
|--在类上添加表名对该类中的所有方法开启事务管理
|--七种事务传播行为
|--REQUIRED:调用方有事务则加入,没有则新建一个事务
|--SUPPORTS:调用方有事务则加入,没有自己也不新建
|--MANDATORY:调用方有事务则加入,没有则抛异常
|--REQUIRES_NEW:无论调用方有无事务,都会新建一个自己的独立事务并暂停调用方的事务
|--NOT_SUPPORTED:不支持事务,如果调用方有事务的话则暂停该事务
|--NEVER:不支持事务,如果调用方有事务则抛异常
|--NESTED:无论调用方有无事务,都会新建一个自己的事务,如果调用方有事务,则会将自己的事务内嵌
|--注意事务的传播行为通过Transactional注解中的propagation属性进行设置
|--四种隔离级别
|--READ_UNCOMMITTED:读未提交,即存在脏读、不可重复读、幻读
|--READ_COMMITTED:读提交,即存在不可重复读、幻读
|--PEREATABLE_READ可重复读,即存在幻读
|--SERIALIZABLE:序列化,即三大读皆不存在
|--注意脏读是指可以读到缓存里的数据,即可以读到还没有提交到数据库中的数据
|--注意不可重复读是指在同一个事务中第一次和第二次读到的数据不同
|--注意幻读是指读到的数据和预期的结果不一致
|--注意事务的隔离级别通过Transactional注解中的isolation属性进行设置
|--超时机制
|--指执行完最后一条DML语句所耗费的时间如果超过了预设的时间,则会进行回滚
|--注意事务的超时时间通过Transactional注解中的timeout属性进行设置
|--只读策略
|--开启只读策略后事务内不能有任何修改类型的DML语句,并且spring会用更高效的方式执行查询语句
|--注意事务的只读策略通过Transactional注解中的readOnly属性进行设置
|--事务的全注解式开发(即使用一个类代替spring的配置文件)
|--在代替配置文件的类上添加 @Configuration注解表明这是一个配置类
|--在代替配置文件的类上添加 @ComponentScan("XX")注解表明需要扫描的包路径
|--XX为需要扫描的包路径,为多个的话用数组表示
|--在代替配置文件的类上添加 @EnableTransactionManagement注解开启事务的注解模式
|--在类中通过 @Bean(name="XX")注解和方法的结合完成一些必要bean的注册(如数据源对象、jdbcTemplate对象、DataSourceTransactionManagement对象)
|--XX为需要注册bean的别名
|--spring框架会自动将Bean注解下方方法的返回值对象注册为bean
spring整合mybatis框架:
|--依赖准备
|--引入spring-context、spring-jdbc、mysql驱动、mybatis、mybatis-spring依赖
|--注意根据需求可以选择是否引入数据库连接池依赖
|--配置转移(即将原本mybatis配置文件的大部分迁移至spring的配置文件中)
|--在spring配置文件中通过<context:property-placeholder location="XX">标签引入数据源配置文件
|--XX为数据源配置文件路径
|--在spring配置文件中注册数据源bean,具体格式如下
|--<bean id="XX" class="YY">ZZ</bean>
|--XX为该数据源bean的别名
|--YY为该数据源类的全限定类名
|--ZZ为数据源中的属性配置内容
|--在spring配置文件中注册SqlSessionFactoryBean,具体格式如下
|--<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="XX"/>
<property name="configLocation" value="YY"/>
<property name="typeAliasesPackage" value="ZZ"/>
</bean>
|--XX为数据源bean的别名
|--YY为mybatis配置文件路径(默认从类的根路径下开始扫描)
|--ZZ为需要取别名的包路径(mybatis会为该包下的所有类自动取别名,默认别名为类名)
|--在spring配置文件中注册Mapper扫描bean,具体格式如下
|--<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="XX">
</bean>
|--XX为需要扫描的包路径
|--在spring配置文件中注册事务管理器bean,具体格式如下
|--<bean id="XX" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="YY">
</bean>
|--XX为事务管理器bean的别名
|--YY为数据源bean的别名
|--在spring配置文件中启用事务管理器的注解模式,具体格式如下
|--<tx:annotation-driven transaction-manager="XX">
|--XX为事务管理器bean的别名
|--在service实现类的上方添加 @Transactional注解开启事务
|--可以理解为此时的mybatis配置文件仅仅用于配置mybatis框架的一些系统参数
|--其他具体的使用与非spring框架下mybatis的使用一致
spring配置文件中引入其他配置文件:
|--使用<import resource="XX"/>标签即可
|--XX为需要引入配置文件的路径,默认从类的根路径下开始检索