Spring学习记录
DI域属性的注入
给引用属性注入时有三种方式,第一种:使用byType方式注入
第二种:使用byName方式注入
使用byName方式注入的第二种:使用@Resource标签并制定name属性
AOP
前置通知:
定义接口
实现接口的目标对象
新建自己的前置通知类来实现MethodBeforeAdvice接口,其中method是目标对象的方法,args是参数,target是目标对象
在配置文件中注册
后置通知
新建类实现AfterReturningAdvice接口,其中比前置通知多了一个属性 returnValue,该属性是目标方法的返回值,可以使用,但是无法修改该返回值。
配置文件
环绕通知
新建类实现接口MyMethodInterceptor,有两个同名的接口,应该实现aop联盟的那一个
环绕通知有返回值,所以可以修改目标方法的返回值,比如目标方法返回小写的abcdefghijk,可以在环绕方法中把它变成大写的
配置文件
异常处理
新建类实现ThrowsAdvice接口,这个接口有点特殊,实现它后不强制实现任何方法,需要查看其源代码
ThrowsAdvice源代码
只能使用红框中的方法
复制粘贴后如下图
afterThrowing(想要处理的异常 ex),触发想要处理的异常后会执行方法体内的逻辑
目标对象有接口时,自动使用JDK动态代理
目标对象没有接口时,自动使用的是CGLIB动态代理
也可以自己指定使用cglib进行代理
使用通知时,类中的所有方法都被作为了切入点。因为有的时候不需要全部方法都作为切入点,所以引入顾问。
模拟使用顾问的环境
接口中有三个方法
需求:当执行doFirst时给一个后置通知,执行其他方法时不触发通知
使用名称匹配方法切入点顾问
使用正则表达式匹配方法切入点顾问
使用ProxyFactoryBean会造成两个问题:
1.若存在多个目标对象,就需要使用多次ProxyFactoryBean来创建多个代理对象,这会使配置文件变的臃肿
2.用户真正想要调用的是目标对象,而真正可以调用的确实代理对象,这不符合正常的逻辑
所以引入了自动代理生成器
注册自动代理生成器后,不需要再手动创建代理工厂Bean了,自动代理生成器的底层实现是使用了Bean后处理器。
默认自动代理(DefaultAdvisorAutoProxyCreator)存在着三个问题:
1.不能选择目标对象(它把所有的顾问分别给所有的目标对象都绑定上)
2.不能选择切面类型,切面只能是advisor(顾问)
使用BeanNameAutoProxyCreator(名称自动代理生成器)可以解决以上问题
引入AspectJ
环境搭建:添加四个包 1. aop 2. aop 联盟 3. aspects 4. aspectj.weaver
限定xml用aop的
基于注解的AOP编程
定义接口
创建实现类
切面类
配置文件
环绕通知
异常通知
最终通知
定义切入点
基于xml的AOP编程
把刚才用的切面类的注解都删除
配置文件中的aspectj自动代理也删除掉,配置aop config
配置切入点
后置通知
Spring的JDBC模板
环境搭建
导入jar包
jdbc:spring-jdbc-4.2.4.RELEASE.jar
事务: spring-tx-4.2.4.RELEASE.jar
连接数据库驱动:mysql-connector-java-5.1.31.jar
数据库连接池:
com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar
com.springsource.org.apache.commons.dbcp-1.2.2.osgi.jar
com.springsource.org.apache.commons.pool-1.5.3.jar
还有一些spring基础jar包
建立实体
创建数据库表
定义业务层Service
先定义接口,在做实现
实现时,肯定会需要调用dao层
先假设有dao层用着,并且给dao写一个set方法,给后面用容器注入做准备
然后定义dao接口,因为我们只是模拟一下环境,没有具体的业务逻辑,所以dao层的方法和service层是一样的,更改了一些方法名,add ---- insert remove --- delete find --- select modify ----- update
dao层实现
实现dao层的增删改查,正式引入jdbc模板,让实现类继承JdbcDaoSupport,然后使用getJdbcTemplate()得到JdbcDaoSupport的属性jdbcTemplate,用jdbcTemplate对数据库进行增删改查的操作
增删改都是用update方法实现的
定义测试类
因为增删改查都需要使用ApplicationContext对象,所以把它设为成员属性,并且设置before,就不需要写在每一个test方法中了
很显然在测试方法中需要获取到IServiceStudent的实现对象,所以需要编写配置文件
在配置文件中写StudentServiceImpl时需要设值注入dao,所以还要配置dao,配置dao时,需要配置dao继承的
JdbcDaoSupport类中的属性JdbcTemplate,配置JdbcTemplate又需要配置DataSource属性,配置完成后如下图
其它种类的数据源配置如下
把数据库连接四要素存放到properties文件中
在配置文件中配置该文件后,才能使用,使用格式: ${jdbc.****}
使用方式
当进行增删改时
当查询结果为字符串时
当查询结果为对象时,因为对象有很多属性,所以要使用一个实现RowMapper接口的类对那些属性进行封装,
使用rowMapper
可以不手动配置jdbcTemplate,直接把数据源注入给dao时,会自动创建出jdbcTemplate
Spring的事务管理
事务传播拿回家吃饺子的例子来比喻
假设有以下需求:
在进行股票交易时,付钱后得到股票,钱减少,股票增多,如果出现异常要发生回滚。
模拟一个环境,建立实体类以及数据库表
Account类
Stock类
account表
stock类
定义Service层
编写其实现类,当编写其实现类时,肯定要用到dao层,先假设有dao层,并且有我们要用的方法,如下
然后补齐这个实现类所需要的接口,实现类
IAccountDao
AccountDaoImpl
IStockDao
StockDaoImpl
当然这些dao都是通过注入获取到的,而且dao层实现也需要注入数据源,所以编写主配置文件如下
因为需求中要求要抛出异常,所以我们手动制造一个异常抛出去
直接抛出异常时,会报错,因为无法通过编译
我们可以加一个判断,骗过编译器就可以通过编译了
,即
此时执行测试方法test02后会发现,钱少了,股票没加,这肯定是不可以接受的,所以我们要使用事务
有三种方式可以实现事务管理
1.使用事务代理管理实务
这种方法存在的问题是,每一个目标类都得有一个代理对象,冗余太大,而且调用时要调用代理对象,不符合常规逻辑
2.使用注解式
在配置文件中添加
在实现类中
3.使用Aspectj管理实务
根据不同的情况选择不同的sql语句时,下面的写法可以用,但是效率稍微低
下面的写法,先给定一个默认值,再根据不同的情况进行选择不同的sql语句,效率会有所提升