MyBatis框架
1. MyBatis框架
什么是MyBatis,MyBatis最早源自于Apache基金会的一个开源项目iBatis,2010年项目由Apache software foundation迁移到Google Code,改名为MyBatis
MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持续层框架,MyBatis使用简单的xml或注解做配置和定义映射的关系,将java POJOS(Plain Old Java Objects)映射成数据库中记录
MyBatis体系结构
1) 加载配置
配置有两种形式,一种是XML配置文件,一种是Java代码的注解,MyBatis将SQL的配置信息加载称为一个个的MapperStatement对象(包括传入的参数映射配置,执行的SQL语句,结果映射配置),将其存储在内存中
2) SQL解析
当API接口层接收到调用请求时,会接收到传入SQL的ID和传入的参数对象(可以是Map,JavaBean或者基本数据类型),Mybatis会根据SQL的id找到对应的MapperStatement,然后根据传入的参数对象对MappedStatement进行解析,解析后可以得到最终要执行的sql语句和参数
3) SQL执行
将最终得到的sql语句和参数拿到数据库中进行执行,得到操作数据库的结果
4) 结果映射
将操作数据库的结果按照映射配置进行转换,可以转换成HashMap,JavaBean或者基本数据类型,将最终的结果返回
MyBatis框架API
SqlSessionFactoryBuilder
此对象是负责根据MyBatis配置文件SqlMapConfig.xml构建SqlSessionFactory对象
SqlSessionFactory
每一个MyBatis的应用程序都以一个SqlSessionFactory对象为核心,此对象负责创建SqlSession对象
SqlSession对象包含所有执行sql语句操作的方法
MyBatis配置文件
1) SqlMapConfig.xml(1个)
主配置文件,用于指定数据库连接参数和框架参数
<configuration> <environments default="mysql"> <environment id="mysql"> <!-- JDBC的提交和回复--> <transactionManager type="JDBC"/>
<!-- JDBC的连接对象和数据源连接池的实现 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://127.0.0.1:3306/jsd1704"/> <property name="username" value="root"/> <property name="password" value="1234"/> </dataSource> </environment> </environments>
<!-- 关联映射文件 --> <mappers> <mapper resource="com/xms/entity/mapper/EmpMapper.xml"/> <mapper resource="com/xms/entity/mapper/DeptMapper.xml"/> </mappers>
</configuration> |
2) SqlMapper.xml(N个)
映射文件,用于定义SQL语句和映射信息
<!-- 添加命名空间 -->
<mappernamespace="com.xms.dao.DeptDao">
<selectid="findAll" resultType="com.xms.entity.Dept">
select * from dept
</select>
<selectid="findById" parameterType="integer" resultType="com.xms.entity.Dept">
select * from dept where deptno=#{deptno}
</select>
<insertid="save" parameterType="com.xms.entity.Dept">
insert into deptvalues(#{deptno},#{deptname},#{deptlevel},#{deptcreatedate},#{depttotalperson});
</insert>
<updateid="update" parameterType="com.xms.entity.Dept">
update emp setdeptname=#{deptname},deptlevel=#{deptlevel},deptcreatedate=#{deptcreatedate},depttotalperson=#{depttotalperson}where deptno=#{deptno}
</update>
<deleteid="delete" parameterType="integer">
delete from dept where deptno=#{deptno}
</delete>
</mapper>
2. MyBatis基本应用
1) 搭建MyBatis技术环境
为工程添加MyBatis开发包和数据库驱动包
在src下添加MyBatis配置文件SqlMapConfig.xml
修改SqlMapConfig.xml,指定数据库连接参数
利用MyBatis API编程,获取SqlSession实例
2) 获取SqlSession
String path="主配置文件URL";
Reader reader =Resources.getResourceAsReader(path);
//创建SqlSessionFactory对象
SqlSessionFactoryBuilder ssfb = newSqlSessionFactoryBuilder();
SqlSessionFactory ssf = ssfb.build(reader);
//创建SqlSession对象
SqlSession ss = ssf.openSession();
public class MyBatisUtil { private static SqlSessionFactory ssf; static{ //加载配置文件 SqlSessionFactoryBuilder ssfb = new SqlSessionFactoryBuilder(); // 类-->类加载器-->主配置文件 ssf = ssfb.build(MyBatisUtil.class.getClassLoader().getResourceAsStream("SqlMapConfig.xml")); } //获取SqlSession public static SqlSession getSession(){ return ssf.openSession(); }
public static void main(String[] args) { System.out.println(MyBatisUtil.getSession()); } } |
3) 利用SqlSession实现CRUD操作
当获取SqlSession对象后,就可以利用它对数据表执行增删改查操作
根据数据表编写实体类
编写SqlMapper.xml映射文件,定义SQL操作和映射信息获取SqlSession对象,执行增删改查操作
提交事务(DML)
释放SqlSession对象资源
如果是多表查询,返回的该是什么样的实体类型
返回Map类型查询结果
ResultMap映射定义
在映射文件定义<select>操作时,如果查询结果集的字段名和Java实体类的属性名不一致,则需要使用<resultMap>元素显示指定映射关系
MyBatis+Spring
1. Spring与MyBatis整合
Spring与MyBatis整合需要引入mybatis-spring.jar文件包
这个整合包由MyBatis提供,此包提供以下整合相关的API
SqlSessionFactoryBean
为整合对象提供SqlSession对象
MapperFactoryBean
根据指定Mapper接口来生成Bean实例(代理类对象)
MapperScanerConfigurer
根据指定包进行批量扫描Mapper接口生成对应的MapperFactoryBean
在单独使用MyBatis时,所有操作都是围绕SqlSession展开的
SqlSession通过SqlSessionFactory获取的,SqlSessionFactory通过SqlSessionFactory构建生成
在Spring与MyBatis整合应用时,同样需要SqlSession,MaBatis-spring.jar提供一个SqlSessionFactoryBean,这个组件的作用就是通过原SqlSessionFactoryBuilder生成SqlSessionFactory对象,为整合应用提供SqlSession对象
SqlSessionFactoryBean在spring-xml中配置:
<beanclass="org.mybatis.spring.SqlSessionFactoryBean">
<!--指定连接资源-->
<!--指定映射文件-->
</bean>
<!-- 定义一个sqlSession工厂 --> <bean class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="ds"></property> <property name="mapperLocations" value="classpath:com/xms/entity/mapper/*.xml"/> </bean> |
在使用MapperFactoryBean时,有一个Mapper就需要定义一个对应的MapperFactoryBean,当Mapper而比较少时可以,但遇到大量Mapper时就需要使用MapperScannerConfigurer组件,通过这个组件会自动扫描各个Mapper接口,注册对应的MapperFactoryBean对象。
在定义MapperScanerConfigurer时,只需要指定一个basePackge即可,basePackege用于指定Mapper接口所在的包,在这个包及其子包中的Mapper接口都将被扫描到,指向对应的MapperFactoryBean对象,多个包之间可以使用逗号或者分号进行分隔
<bean class="">
<property name="basePackage"value="com.xms.dao"/>
<bean>
<!-- 指定扫描包 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.xms.dao"/> <property name="annotationClass" value="com.xms.annotation.MyAnnotation"/> </bean> |
注意:sqlSessionFactory属性可以不用指定,会以Autowired方式自动注入
如果指定的某个包下并不完全是我们定义的Mapper接口,此时可以使用MapperScannerConfigurer的另外两个属性缩小扫描和注册范围,一个是annotationClass,一个是markerInterface
annotationClass: 用于指定一个注解标记,当指定了annotationClass注解标记时,MapperScannerConfigurer将只注册使用了annotationClass注解标记的接口
markerInterface:用于指定一个接口,当指定了markerInterface接口时,MapperScannerConfigurer将只注册继承自markerInterface的接口
此外mybatis-spring.jar还提供一个SqlSessionTemplate组件也可以将此组件对象注入到DAO,利用SqlSessionTemplate编程
2. Spring整合MyBatis应用
基于Spring SpringMVC MyBatis 和MyBatis技术开发的主要步骤;
练习:
SSM重构NETCTOSS资费模块
spring DI依赖注入的方式实现IOC控制反转
Spring MVC Model View Controller
MyBatis
MyBatis动态SQL
1. MyBatis动态SQL
动态SQL是MyBatis框架中特性之一,在一些组合查询页面需要根据用户输入的查询条件生成不同的查询SQL语句,在JDBC或者其他相似框架中需要在代码中拼接SQL,容易出错,MyBatis可以解决这种问题
动态SQL元素与JSTL相似,它允许在XML中构建不同的SQL语句,常用SQL元素如下:
判断元素: if , choose
关键字元素:where, set, trim
循环元素: foreach
if 元素是简单的条件判断逻辑,满足指定条件时追加 if 元素内的 SQL语句,不满足时不追加,使用格式如下:
<select> SQL语句1 <if test="条件表达式"> SQL语句2 </if> </select> |
if 元素最常见的使用在where子句部分,根据不同情况追加不同的SQL条件
示例:
<mapper namespace="com.xms.dao.EmpMapper"> <!-- 根据部门号查询员工 --> <select id="findByDeptno" resultType="com.xms.entity.Emp" parameterType="com.xms.common.Condition"> select * from emp <if test="deptno!=null"> where deptno=#{deptno} </if> </select> </mapper> |
SpringMyBatisDay09_01
spring ioc 5
spring mvc 2
spring jdbc 2
spring aop 1
mybatis 1
mybatis+spring 2
mysql连接 3
choose元素的作用相当于Java的switch语句,基本上跟JSTL中choose的作用和用法是一样的,通常与when和otherwise搭配使用,使用格式如下:
<select>
SQL语句1
<choose>
<when test="条件表达式">
SQL语句2
</when>
<otherwise>
SQL语句3
</otherwise>
</select>
示例
<select id="findBySalary" resultType="com.xms.entity.Emp" parameterType="com.xms.common.Condition"> select * from emp <choose> <when test="salary > 50000"> where salary > #{salary} </when> <otherwise> where salary > 5000 </otherwise> </choose>
</select> |
测试类
where元素主要是用户简化语句中的where部分的条件判断,where元素可以在<where>元素所在的位置输出一个where关键字,而且还可以将后面多余的and或者or关键字去除,使用格式如下:
<select>
select * from emp
<where>
动态追加条件
</where>
</select>
<!-- 根据部门号和薪水查询员工 --> <select id="findByDeptnoAndSalary" resultType="com.xms.entity.Emp" parameterType="com.xms.common.Condition"> select * from emp <where> <if test="salary!=null"> salary>#{salary} </if> <if test="deptno!=null"> and deptno=#{deptno} </if>
</where> </select> |
set元素主要用在更新操作时,它的主要功能和where元素相似,主要是在<set>元素所在位置输出一个set关键字,而且还可以去除内容结尾中无关的逗号,使用格式如下:
<update>
update emp
<set>
动态追加代码
</set>
</update>
<!-- 更新员工 --> <update id="update" parameterType="com.xms.entity.Emp"> update emp <set> <if test="ename!=null"> ename=#{ename}, </if> <if test="salary!=null"> salary=#{salary}, </if> <if test="bonus!=null"> bonus=#{bonus} </if> where empno=#{empno} </set> </update> |
trim 元素的主要功能如下:
1) 可以在自己包含的内容前加上某些前缀,也可以在其后加上某些后缀,与之对应的属性是prefix和suffix
2) 可以把包含内容的首部某些内容过滤,即忽略,也可以把尾部的某些内容过滤,对应的属性是prefixOverrides和suffixOverrides
即trim元素可以替代where元素和set元素的功能
<!--等价于where元素-->
<trim prefix="where"prefixOverrides="and|or">
......
</trim>
<!-- trim替换where --> <select id="findByDeptnoAndSalaryTwo" resultType="com.xms.entity.Emp" parameterType="com.xms.common.Condition"> select * from emp <trim prefix="where" prefixOverrides="and"> <if test="deptno!=null"> and deptno=#{deptno} </if> <if test="salary!=null"> and salary > #{salary} </if> </trim> </select> |
<!--等价于set元素-->
<trim prefix="set"suffixOverrides=",">
......
</trim>
<!-- trim替换set --> <update id="updateTwo" parameterType="com.xms.entity.Emp"> update emp <trim prefix="set" prefixOverrides=","> <if test="ename!=null"> ename=#{ename}, </if> <if test="salary!=null"> salary=#{salary}, </if> <if test="bonus!=null"> bonus=#{bonus} </if> where empno=#{empno} </trim> </update> |
foreach元素实现循环逻辑,可以进行一下集合的迭代,主要用在构建In条件中,使用格式如下:
<select>
select * from emp where empno in
<foreach collection="集合"item="迭代变量" open="("close=")" >
#{迭代元素}
</foreach>
</select>
<!-- 根据员工号查询员工 --> <select id="findByEmpnos" resultType="com.xms.entity.Emp" parameterType="com.xms.common.Condition"> select * from emp where empno in <foreach collection="empnos" item="empno" open="(" close=")" separator=","> #{empno} </foreach> </select> |
foreach元素它允许指定一个集合,声明集合项和索引变量,变量可以用在元素体内,它允许指定开放和关闭的字符串,在迭代之间放置分隔符
2. MyBatis的关联映射
1) 主键映射
在做插入操作时,可以由MyBatis负责主键生成
sequence index view
自动递增:
MySQL,SQLServer数据库都支持字段自动递增功能,在设计表时,可以为主键字段指定自动递增,在添加操作时,主键值的数据自动生成,不需要指定
在使用MyBatis时,有时需要返回MySQL和SQLServer数据库自动增长的主键值可以采用以下定义方式:
<insert id=" " parameterType=" " useGeneratedKeys="true" keyProperty="">
....
</insert>
在<insert>元素指定自动递增属性设置后,MyBatis会在插入操作后将自动递增生成的主键值给KeyProperty指定的属性赋值
2) 多对一映射
在查询时需要获取两张或两张以上关联表的数据,通过关联映射可以由一个对象获取相关对象的信息,例如:查询一个Emp员工对象,可以通过关联映射获取员工所在的部门Dept对象信息
MyBatis的多对一映射有以下两种不同的实现形式:
1) 嵌套查询:通过执行另外一个SQL映射语句来返回关联数据结果(查询两次)
<!-- 嵌套查询,查询员工时,关联查询出对应的部门信息 --> <select id="findByEmpno" resultMap="empMapOne" parameterType="java.lang.Integer"> select * from emp where empno=#{empno} </select>
<resultMap id="empMapOne" type="com.xms.entity.Emp"> <association property="dept" column="deptno" javaType="com.xms.entity.Dept" select="findByDeptno"></association> </resultMap>
<select id="findByDeptno" parameterType="java.lang.Integer" resultType="com.xms.entity.Dept"> select * from dept where deptno=#{deptno} </select> |
2) 嵌套结果查询:执行一个表关联查询SQL,然后将查询结果映射成关联对象(查询一次)
<!-- 嵌套结果查询 --> <select id="findByEmpnoTwo" resultMap="empMapTwo" parameterType="java.lang.Integer"> select e.*,d.* from emp e inner join dept d on e.deptno = d.deptno where e.empno=#{empno} </select> <resultMap id="empMapTwo" type="com.xms.entity.Emp"> <id property="empno" column="empno"/> <result property="ename" column="ename"/> <result property="salary" column="salary"/> <result property="bonus" column="bonus"/> <result property="hiredate" column="hiredate"/> <result property="deptno" column="deptno"/> <association property ="dept" column="deptno" javaType="com.xms.entity.Dept"> <id property="deptno" column="deptno"/> <result property="deptname" column="deptname"/> <result property="deptlevel" column="deptlevel"/> <result property="deptcreatedate" column="deptcreatedate"/> <result property="depttotalperson" column="depttotalperson"/> </association> </resultMap> <!-- 以上不需要再调用sql查询语句了,已经整合在上一条查询中 --> |
3) 一对多映射
当查询某个表的记录信息时,如果关联表有多条相关记录,此时就可以通过使用一对多映射,例如:查询某个Dept部门对象信息,通过一对多映射获取此部门所有的Emp员工对象信息
MyBatis的一对多映射有以下两种不同的实现形式:
1 嵌套查询:通过执行另外一个SQL映射语句来返回关联数据结果(查询两次)
<!-- 嵌套查询,查询到部门,查询该部门所有员工信息 --> <select id="findByDeptno" resultMap="deptMapOne" parameterType="java.lang.Integer"> select * from dept where deptno=#{deptno} </select>
<resultMap id="deptMapOne" type="com.xms.entity.Dept"> <!-- type最后映射的类型,dept中包含了有Emp的List --> <!-- 单个属性用<association property="dept" column="deptno" javaType="com.xms.entity.Dept" select="findByDeptno"></association> --> <!-- 集合属性用collection --> <collection property="emps" column="deptno" select="findEmps" javaType="java.util.ArrayList" ofType="com.xms.entity.Emp"></collection> <!-- 集合属性,属性名称 emps 关联的是deptno 参数 执行方法 select 属性类型是ArrayList,泛型是ofType Emp --> </resultMap>
<select id="findEmps" parameterType="java.lang.Integer" resultType="com.xms.entity.Emp"> select * from emp where deptno=#{deptno} </select> |
2 嵌套结果查询:执行一个表关联查询SQL,然后将查询结果映射成关联对象(查询一次)
Spring事务
1. Spring事务处理
Spring框架能够全面的事务支持,它提供一致的事务管理方式
-提供简单易用的编程时事务管理API
-支持声明式事务管理
1.编程式事务
使用编程式事务时,Spring提供以下两种事务管理的API
-TransactionTemplate
- PlatformTransactionManager
如果采用编程式事务管理,推荐使用TranscationTemplate
TransactionTemplate与Spring中JdbcTemplate等模板类风格相似,它也使用回调机制,将事务代码和业务代码分离便于开发者将精力集中在具体的业务编程上
transactionTemplate.execute(newTransactionCallBack(){
public Object doInTransaction(TransactionStatus status){
//业务操作
updateOperation();
return resultOfUpdateOperation();
}
});
如果不需要返回值,可以创建一个
TransactionCallBackWithoutResult的匿名类
TransactionTemplate.execute(newTransactionCallBackWithoutResult(TransactionStatus status){
//业务操作
updateOperation();
status.setRollbackOnly();
});
声明式事务
Spring的声明式事务管理是通过Spring AOP来实现的,使用时不需要修改原有的业务代码,只需要通过简单配置就可以追加事务控制功能,大多数Spring用户选择声明式事务管理,对程序代码影响最小,也是最符合非侵入的理念。
2. 注解实现声明式事务
1) 在配置文件中声明事务组件,开启事务注解扫描
<!--声明事务管理组件-->
<bean id="" class="">
<propety name="dataSource" ref=" " >
</bean>
<!--开启事务注解扫描-->
<tx:annotation-driven transaction-manager="" >
transaction-manager指定事务管理器,需要根据数据库访问技术的不同选择不同的实现,例如JDBC,MyBatis技术选择DataSourceTransactionManager,而Hibernate技术则选择HibernateTransactionManager
2) 使用@Transactional注解
@Transactional注解标记可以用在类定义前和方法定义前
方法的事务设置将由于类级别注解的事务设置
@Transactional注解标记有以下属性,在使用时可以根据需要做指定
-propagation:事务传播,默认值是propagation_required
-isolation:事务隔离级别,默认值是isolation_default
-readOnly:只读/读写,默认值是可读写
-rollbackFor:遇到哪些异常回滚
-noRollbackFor:遇到哪些异常不回滚
注意:任何RuntimeException将触发事务回滚,但是任何CheckedException将不触发事务回滚
3. XML配置实现声明式事务
-在配置文件中声明事务管理组件,配置事务作用的范围及类型
<!--声明事务管理组件-->
<!--XML配置声明事务范围及类型-->
<tx:advice id="" transaction-manager="" >
<tx:attributes>
<tx:methodname="" propagation=""/>
<tx:methodname="" read-only=""/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:advisor advice-ref="" pointcut="">
</aop:config>
4. 事务回滚
默认情况下RuntimeException异常将触发事务回滚,任何CheckedException将不触发事务回滚,常见RuntimeException和CheckedException如下:
RuntimeException:
NullPointerException
ClassCastException
NumberFormatException
IndexOutOfBoundsException 下标越界异常
CheckedException:
ClassNotFoundException
IOException
NoSuchMethodException
NoSuchFieldException
对于CheckedException,需要手动指定异常类型,才能实现事务回滚
-使用注解实现声明式事务,按如下方式指定异常:
@Transactionnal(rollbackFor=Exception.class)
-使用XML配置实现声明式事务时,按如下方式指定异常:
<tx:method name="" rollback-for="java.lang.exception">
当使用自定义异常,异常类只有继承RuntimeException时才能自动回滚,否则需要指定事务回滚的异常类型
5. 事务传播
是指一个方法调用了另一个带有事务控制的方法,就需要指定事务传播的处理方案
6. 事务隔离
在数据库操作的过程中,如果两个事物并发执行,那么彼此之间的数据会发生影响,为了避免这种并发冲突,需要将两个事物隔离开
Spring与Ajax
1. Spring对Ajax的支持
Spring与Ajax的支持
为了便于接收和处理Ajax请求,SpringMVC提供JSON响应的支持,可以很方便地将数据自动转换成JSON格式字符串给客户端JavaScript返回
在SpringMVC中,与JSON响应相关的注解为@ResponseBody注解
@ResponseBody注解主要用于Controller组件的处理方法前,具体操作如下:
1) 引入jackson开发包,示例代码使用的是
jackson-annotation-2.4.1.jar //注解扫描
jackson-core-2.4.1.jar //核心
jackson-databind-2.4.1.jar //数据
2) 在Spring配置文件中定义<MVC:annotation-driven/>开启对@ResponseBody注解的支持,在Controller处理方法前定义@ResponseBody注解
1.返回单个值
2.返回多个值
3.返回List集合
4.返回对象结果
5.返回对象集合结果
$ajax({
url:""
data:""
Type:""
dataType:""
success:
});
Ajax是什么?
Ajax有什么作用?用来发送异步请求,比如鼠标移开输入框的时候
Ajax的帮助下怎么样?
用在页面局部的刷新,ajax这块是有同步的请求的
ajax返回字符、int值等就直接打印 data alert(data)
ajax返回map 就打印 data.id
ajax返回list 就打印 data[1]
ajax返回对象 就打印data.ename (比如对象实体是emp)
ajax返回对象组 就打印data[1].ename (先返回的是一个数组对象,然后是其中对象的名称)
注意:返回的是写 data. 而不是返回的实体
思考:如果不用JQuery框架,就采用纯粹的js写的时候该怎么写呢?
JQuery 的1.4.3最好
请求成功走到success的时候,通过data接收服务器返回的参数,它只是一个形参
2. Spring AOP
AOP概念和优点
AOP为Aspect OrientedProgramming的缩写,被称为面向切面编程
AOP主要用于处理共通逻辑,例如日志记录,性能统计,安全控制,事务处理,异常处理等等,AOP可以将这些共通逻辑从普通业务逻辑代码中分离出来,这样在以后修改这些逻辑时就不会影响普通业务逻辑代码。
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各个部分之间的耦合度降低,提高程序的可重用性,同时提高开发效率
AOP,OOP在字面上虽然非常相似,但却是不同领域的两种设计思想。
OOP(面向对象编程) 针对业务处理过程中实体的属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分
AOP(面向切面编程) 针对业务处理过程中的切面进行提取,它面对是处理过程中的某个步骤或阶段,以获得逻辑过程中各个部分之间低耦合的隔离效果
AOP需要以OOP为前提和基础。
什么是方面?
方面是指封装共通处理逻辑的组件,此组件被作用到其他目标组件方法上
方面组件就是插入执行的类,里面包含一些方法可以设置那些方法在目标组件执行前或者后
什么是目标?
目标是被一个或多个方面所作用的对象
什么是切入点?
切入点是用于指定哪些组件的方法使用方面功能,在Spring中利用一个表达式指定切入点
Spring提供以下常用的切入点表达式
-方法限定表达式
execution(修饰符?返回类型方法名(参数) throws异常类型?)
-类型限定表达式
within(包名.类型)
-Bean名称限定表达式
Bean("Bean的id或name的属性值")
什么是通知
通知是用于指定方面组件和目标组件作用的时机,例如方面功能在目标方法之前或之后执行等时机
Spring框架提供以下类型的通知:
前置通知:先执行方面功能再执行目标功能
后置通知:先执行目标功能再执行方面功能(目标无异常才执行方面)
最终通知:先执行目标功能再执行方面功能(目标有无异常)
异常通知:先执行目标,抛出异常后执行方面功能
环绕通知:先执行方面的前置部分,然后执行目标,最后执行方面的后置部分
try{
//前置通知
//环绕通知前置部分
//执行目标组件
//环绕通知后置部分
//后置通知
} catch{
//异常通知
} finally{
//最终通知
}
AOP实现原理
Spring AOP实现主要是基于动态代理技术,当Spring采用AOP配置后,Spring容器返回的目标对象,实质上是Spring利用动态代理技术生成的一个代理类型,代理类重写了原目标组件方法的功能,在代理类中调用方面对象功能和目标对象功能。
所谓的方面是指抽取出来的代码可实现功能的共同部分。
比如 A类 为 目标组件 a() 方法
B类为 方面组件 b()方法
C类(代理类)继承a类 定义一个B类 b, 在重写a() 方法中,可以将b.b()方法放在 a()方法前则为前置通知,在后为后置通知
Spring框架采用两种动态代理实现:
1) 利用cglib工具包
目标没有接口时采用此方法,代理类是利用继承方式生成一个目标子类
2) 利用JDK Proxy API
目标有接口时采用此方法,代理类是采用实现目标接口这种方式生成一个子类
3) XMP配置实现AOP
开发步骤
1) 创建一个类,充当方面组件,实现共同逻辑
2) 声明方面组件(在配置文件中)
3) 使用方面组件,在配置文件中,将方面组件作用到目标组件方法上,设置通知类型以确认方面组件调用的时机
通过什么来实现相应的调用时机?
4. 注解实现AOP
开发步骤
1) 创建方面组件
创建一个类,充当方面组件,实现共通逻辑
2) 声明方面组件
-在配置文件中开启AOP注解扫描
-使用@Component注解标识这个类,将其声明为组件
-使用@Aspect注解标识这个类,将其声明为方面组件
3) 使用方面组件
-在方面组件的方法上,使用注解将方面组件作用到目标组件的方法上,并设置通知类型以确认组件调用的时机