以下内容如有侵权请联系删除
Spring第一天
第一章 JavaEE三层架构

第二章 IOC思想推导(难点)
之前的代码逻辑
- servlet中需要调用service : UserService userService = new UserServicelmpl()
耦合关系 代码片段中的依赖关系(如上,UserServicelmpl与UserService耦合关系太强,如何验证代码片段的耦合关系的强弱(依赖关系),例如将UserServicelmpl.java文件删除,看是否会报编译异常,如果会报编译异常,说明耦合关系强;如果不报编译异常,说明没有耦合关系;如何解决这种耦合关系,通过反射或者配置文件)解耦:
反射,配置文件,面向接口编程(创建工厂类的实质就是利用反射和配置文件)
2.1 简化版本
(1)创建工程导入依赖
java
<dependencies>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6</version>
</dependency>
</dependencies>
(2)配置dao接口
(3)创建BeanFactory工具类
java
package cn.itcast.utils;
public class BeanFactory {
/**
* 根据传入的参数名,反射创建对象
* @param name
* @return
* @throws Exception
*/
public static Object getBean(String name) throws Exception{
Class<?> aClass = Class.forName(name);
return aClass.newInstance();
}
}
2.2 升级版本
(1)创建配置文件
(2)在BeanFactory解析配置文件
java
package cn.itcast.utils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 单例工厂:多次调用getBean方法,获取的对象是同一个
* 1、当程序第一次访问BeanFactory,解析Bean.xml配置文件,创建对象
* 2、当调用getBean方法的时候,从map集合中直接获取目标对象
*/
public class BeanFactory {
/**
* map存放:
* userDao = UserDaoImpl对象
*/
private static Map<String,Object> map=new HashMap<String,Object>();
static{
try {
//1.获取配置文件的输入流
InputStream is = BeanFactory.class.getClassLoader().getResourceAsStream("bean.xml");
//2.创建SAXReader对象
SAXReader reader = new SAXReader();
//3.获取Document对象
Document document = reader.read(is);
//4.获取所有的bean节点
Element root = document.getRootElement(); //获取跟节点
List<Element> bean = root.elements("bean");
//5.解析bean节点,获取id和class属性
for (Element element : bean) {
String id = element.attributeValue("id"); //userDao
String cls = element.attributeValue("class"); //全限定类名
Class<?> aClass = Class.forName(cls);
Object obj = aClass.newInstance();
//6.存入map集合
map.put(id, obj);
}
} catch (Exception e) {
}
}
/**
* 根据传入的参数名,反射创建对象
* @param key
* @return
* @throws Exception
*/
public static Object getBean(String key) throws Exception {
return map.get(key);
}
}

2.3 总结
通过两种方式完成了对象的对象(userDaolmpl)
- 最简单的版本:通过手动反射创建对象(手动new对象)
- 第二个版本:所需的目标对象,从map集合(容器)中获取(控制反转:IOC)
ioc:对象的获取方式,由传统的主动实例化对象〈new对象),变为从容器(map)集合中获取
第三章 Spring概述和控制反转
3.1 什么是Spring
- Spring是于2003年兴起的一个full-stack轻量级的Java开源框架,由Rod Johnson创建
- Spring以IOC(控制反转)和AOP(面向切面编程)为核心
- Spring提供了展现层Spring MVC、持久层Spring JDBC、业务层事务管理等众多的企业级应用技术
- Spring还能整合开源世界众多的第三方框架和类库,逐渐成为使用最多的ava EE企业应用开源框架

3.2 认识IOC
IOC(控制反转)不是什么技术,而是一种设计思想。它的目的是指导我们设计出更加松耦合的程序。
- 控制:指的是控制权,在java中可以简单理解为对象的控制权限(比如对象的创建、销毁等权限)
- 反转:指的是将对象的控制权由原来的程序员在类中主动控制反转到由Spring容器来控制。
- 对象的创建交由Spring容器管理,需要对象从容器中获取即可
- 主要功能解耦
- IOC的底层原理:反射
举个例子:找对象
- 传统方式:自己找,想要啥样的自己去大街上找(new) ,主动出击
- l0C方式:婚介所,首先人们将自己的信息注册到婚介所。然后,等你想要对象的时候,婚介所就会帮你找到,然后给你送来。
第四章 SpringIOC的入门案例(重点)
4.1 入门案例
创建工程导入依赖
java
<dependencies>
<!--spring的坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<!--单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
创建Dao接口和实现类
创建Spring配置文件
- spring配置文件约定俗称::applicationContext.xml
- spring配置文件,需要引入名称空间(约束)
- 在spring的配置文件中通过标签,定义对象id和实现类全类名
在resource目录下创建applicationContext.xml配置文件
java
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--创建对象
id:容器中对象的唯---标识(唯---别名)
class:实现类的全限定类名,在springIoc容器中,会通过全类名,反射创建对象
-->
<bean id="userDao" class="cn.itcast.dao.impl.UserDaoImpl"></bean>
</beans>
测试
4.2 执行过程分析

4.3 Spring的API介绍
第五章 对象的生命周期
5.1 对象作用域
java
<!--创建对象的作用域
scope :作用
singleton :单例对象
容器创建的时候,反射创建对象存入map集合中
prototype:多例对象
容器创建的时候,不会反射创建此对象
当调用容器的getBean方法的时候,反射创建一个新的对象
-->
<bean id="userDao" class="cn.itcast.dao.impl.UserDaoImpl" scope="prototype"></bean>
5.2 生命周期
java
<!--对象的生命周期(对象和创建和销毁过程),和对象的作用域息息相关
init-method : 对象实例化之后,自动执行的对象方法
destroy-method:容器关闭,对象被销毁之前,自动执行的对象方法
singleton(单例对象)
1、容器创建(加载配置文件app1icationContext.xm1文件时,容器创建),自动的反射创建UserDaoImp1对象存入容器
2、自动的执行init-method中配置的对象方法
3、容器关闭时,对象销毁之前自动的执行destroy-method配置的对象方法
prototype(多例对象)
1、当调用一次getBean方法,创建一次对象
2、当对象创建,调用init-method中配置的对象方法
3、多例对象(没有存在容器中),自动的进行垃圾回收
-->
<bean id="userDao" class="cn.itcast.dao.impl.UserDaoImpl" scope="prototype"
init-method="initMethod" destroy-method="destoryMethod"></bean>
第六章 依赖注入(重点)
依赖注入:Dependency lnjection (Dl)。它是spring框架核心ioc的具体实现。我们的程序在编写时,通过控制反转,把对象的创建交给了spring,但是代码中不可能出现没有依赖的情况。比如我们的Book中可能引入一个Publish类,在使用了Spring之后,它会为我们解决这些依赖对象的注入。
本质:向对象中的私有属性赋值
构造方法
set万法调用
6.1 构造方法注入
向对象添加有参构造方法
java
package cn.itcast.dao.impl;
import cn.itcast.dao.UserDao;
public class UserDaoImpl implements UserDao {
private String username;
private Integer age;
public UserDaoImpl(){
}
//1.配置有参构造,在new对象的时候,直接对属性赋值
public UserDaoImpl(String username,Integer age) {
this.username = username;
this.age = age;
}
public void save() {
System.out.println("调用dao保存用户");
}
}
在spring的配置文件中,通过bean标签配置对象创建(需要添加构造方法参数)
java
<!--
相当于调用无参构造方法,实例化 UserDaoImpl
new UserDaoImpl();
构造方法注入参数:
在bean标签中,通过constructor-arg配置构造方法参数
new UserDaoImpl("王者荣耀",12);
-->
<bean id="userDao" class="cn.itcast.dao.impl.UserDaoImpl">
<!--配置构造参数
index:指定参数的索引定位,从0开始
type:通过参数的类型定位,Integer
name:通过参数的名称定位,username
以上三个属性,适用于定位构造参数(三选一就可以)
value:对基本数据类型的数据赋值(8个基本数据类型+String)
ref:对java实体类对象赋值
以上两个属性,适用于对参数赋值
-->
<constructor-arg name="username" value="王者荣耀" ></constructor-arg>
<constructor-arg name="age" value="12" ></constructor-arg>
</bean>
6.2 set方法注入
提供属性的set方法
java
package cn.itcast.dao.impl;
import cn.itcast.dao.UserDao;
public class UserDaoImpl implements UserDao {
private String username;
private Integer age;
public UserDaoImpl(){
}
//1.配置有参构造,在new对象的时候,直接对属性赋值
public UserDaoImpl(String username,Integer age) {
this.username = username;
this.age = age;
}
public void setUsername(String username) {
this.username = username;
}
public void setAge(Integer age) {
this.age = age;
}
public void save() {
System.out.println("调用dao保存用户");
}
}
在spring配置文件中,通过bean结合property配置set方法调用
java
<!--set方法注入
通过bean标签结合property标签配置对象创建之后,自动执行的set方法
UserDao userDao = new UserDaoImpl();
userDao.setUsername();
userDao.setAge();
property标签
name :定位待执行的set方法
value:对基本数据类型的属性赋值
ref :对java实体类对象赋值
-->
<bean id="userDao" class="cn.itcast.dao.impl.UserDaoImpl">
<property name="username" value="LOL"></property>
<property name="age" value="15"></property>
</bean>
6.3 注入复杂类型(集合)
(1)注入数组类型
配置set方法
spring配置
(2)注入kv数据
java对象
配置文件
6.4 注入对象(重点)
第七章 配置文件的模块化(了解)
我们现在的配置都集中配在了一个applicationContext.xml文件中,当开发人员过多时,如果所有bean都配置到同一个配置文件中,会使这个文件巨大,而且也不方便维护。针对这个问题,Spring提供了多配置文件的方式,也就是所谓的配置文件模块化。
1、并列的多个配置文件
直接编写多个配置文件,比如说beans1.xml,beans2.xm...然后在创建ApplicationContext的时候,直接传入多个配置文件。
java
ApplicationContext act=new ClassPathXmlApplicationContext("beans1.xml","beans2.xml","...");
2、主从配置文件
先陪一个主配置文件,然后在里面导入其它的配置文件。
java
<import resource="beans1.xml"/>
<import resource="beans2.xml"/>
注意事项:
- 同一个xml文件中不能出现相同名称的bean,如果出现会报错
- 多个xml文件如果出现相同名称的bean,不会报错,但是后加载的会覆盖前加载的bean,所以企业开发中尽量保证bean的名称是唯一的。
Spring第二天
第一章 DbUtils(会用)
1.1 DbUtils介绍
DbUtils是Apache的一款用于简化Dao代码的工具类,它底层封装了JDBC技术。
核心类:
- QueryRunner用于执行增删改查的SQL语句
- ResultSetHandler这是一个接口,主要作用是将数据库返回的记录封装进实体对象-------查询数据封装,结果集处理器
核心方法:
- update()用来执行增、删、改语句executeUpate
- query()用来执行查询语句executeQuery
java
//1.创建datasourcexxX
//2.创建QueryRunner
QueryRunner queryRunner = new QueryRunner(datasource); //update方法,用于执行增删改语句
//第一个参数:sq1语句后面的参数:sq1语句中的所需要的的值
queryRunner.update("insert into account value(nu71,?,?)",1,2);
//query方法,用于执行查询语句
//第一个参数:sq1语句―第一个参数:封装返回值―后面的参数:sq1语句中的所需要的的值
//BeanHandler用于将一条返回数据封装成一个JavaBean,类似的子类还有BeanListHandler等
queryRunner. query("select * from account where aid = ?", new BeanHandler<Account>(Account.class),1);
1.2 DbUtils基本使用
准备数据库环境
create table account(
id int primary key auto_increment,
name varchar(100) not null unique,
money float(10,2)
)
创建工程导入依赖
java
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.15</version>
</dependency>
<!--dbutils-->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.7</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
创建实体类
java
package cn.itcast.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Account {
private Integer id;
private String name;
private Double money;
}
保存
java
/**
* 保存账户数据
* @throws Exception
*/
@Test
public void test() throws Exception {
//1.创建DataSource
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUsername("root");
dataSource.setPassword("root");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///heima31");
//2.创建QueryRunner对象(通过构造参数,传入datasource)
QueryRunner queryRunner = new QueryRunner(dataSource);
//3.调用QueryRunner方法完成数据库操作(update, query)
queryRunner.update("insert into account(name , money) values (?,?)","小张",2);
}
根据名称查询
java
/**
* 根据名称查询账户
*/
@Test
public void testQueryByName() throws Exception {
//1、创建DataSource
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUsername("root");
dataSource.setPassword("root");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///heima31");
//2、创建QueryRunner对象 (通过构造参数,传入datasource)
QueryRunner queryRunner = new QueryRunner(dataSource);
//3、调用QueryRunner方法完成数据库操作(update,query)
/**
* 结果集处理器:
* BeanHandler :处理返回值仅有一条数据,将查询结果封装为唯一的java对象
* BeanListHandler:处理返回值有多条记录,将查询结果封装为List<>对象
* 语法:
* new BeanHandler<封装的对象类型>(返回对象.class)
*/
Account account = queryRunner.query("select * from account where name=?",
new BeanHandler<Account>(Account.class), "小张");//sql语句,结果集处理器,sql语句的参数(不是必须)
System.out.println(account);
}
查询所有
java
/**
* 查询列表记录
*/
@Test
public void testQueryAll() throws Exception {
//1、创建DataSource
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUsername("root");
dataSource.setPassword("root");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///heima31");
//2、创建QueryRunner对象 (通过构造参数,传入datasource)
QueryRunner queryRunner = new QueryRunner(dataSource);
//3、调用QueryRunner方法完成数据库操作(update,query)
/**
* 结果集处理器:
* BeanHandler :处理返回值仅有一条数据,将查询结果封装为唯一的java对象
* BeanListHandler:处理返回值有多条记录,将查询结果封装为List<>对象
* 语法:
* new BeanHandler<封装的对象类型>(返回对象.class)
*/
List<Account> list = queryRunner.query("select * from account", new BeanListHandler<Account>(Account.class));
for (Account account : list) {
System.out.println(account);
}
}
第二章 基于XML配置数据库操作(重点)

2.1 环境搭建
创建工程导入坐标
java
<dependencies>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.15</version>
</dependency>
<!--dbutils-->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.7</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<!--spring-junit-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
</dependencies>
创建实体
java
package cn.itcast.domain;
public class Account {
private Integer id;
/**
* 账户名称
*/
private String name;
/**
* 账户金额
*/
private Float money;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Float getMoney() {
return money;
}
public void setMoney(Float money) {
this.money = money;
}
}
创建dao接口
java
package cn.itcast.dao;
import cn.itcast.domain.Account;
import java.util.List;
public interface AccountDao {
/**
* 1、保存账户
* @param account
*/
public void saveAccount(Account account);
/**
* 2、更新账户
* @param account
*/
public void updateAccount(Account account);
/**
* 3、根据名称查询账户
*/
public Account findByName(String name);
/**
* 4、查询所有账户
* @return
*/
public List<Account> findA1l();
/**
* 5、根据i d删除账户
* @param id
*/
public void de1eteById(Integer id) ;
}
创建dao接口实现类
java
package cn.itcast.dao.impl;
import cn.itcast.dao.AccountDao;
import cn.itcast.domain.Account;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import java.sql.SQLException;
import java.util.List;
/**
* 在dao层中,使用QueryRunner完成数据库操作
*/
public class AccountDaoImpl implements AccountDao {
/**
* 依赖属性
*/
private QueryRunner queryRunner;
public void setQueryRunner(QueryRunner queryRunner) {
this.queryRunner = queryRunner;
}
/**
* 保存
* @param account
*/
public void saveAccount(Account account) {
try {
queryRunner.update("insert into account(name,money) values(?,?)", account.getName(),account.getMoney());
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 根据用户名称更新金额
* @param account
*/
public void updateAccount(Account account) {
try {
queryRunner.update("update account set money=? where name=?", account.getMoney(),account.getName());
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 根据名称查询
* @param name
* @return
*/
public Account findByName(String name) {
try {
return queryRunner.query("select * from account where name=?", new BeanHandler<Account>(Account.class),name);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
/**
* 查询所有
* @return
*/
public List<Account> findAll() {
try {
return queryRunner.query("select * from account", new BeanListHandler<Account>(Account.class));
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
/**
* 删除
* @param id
*/
public void deleteById(Integer id) {
try {
queryRunner.update("delete from account where id=?",id);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
创建service接口
java
package cn.itcast.service;
import cn.itcast.domain.Account;
import java.util.List;
public interface AccountService {
/**
* 1、保存账户
* @param account
*/
public void saveAccount (Account account);
/**
* 2、更新账户
* @param account
*/
public void updateAccount(Account account) ;
/**
* 3、根据名称查询账户
* @param name
* @return
*/
public Account findByName (String name) ;
/**
* 4、查询所有账户
* @return
*/
public List<Account> findAll();
/**
* 5、根据id删除账户
* @param id
*/
public void deleteById(Integer id);
}
创建service接口实现类
java
package cn.itcast.service.impl;
import cn.itcast.dao.AccountDao;
import cn.itcast.domain.Account;
import cn.itcast.service.AccountService;
import java.util.List;
public class AccountServiceImpl implements AccountService {
/**
* 依赖属性(依赖注入)
*/
private AccountDao accountDao;
/**
* 用于property的set注入
* @param accountDao
*/
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
/**
* 保存
* @param account
*/
public void saveAccount(Account account) {
accountDao.saveAccount(account);
}
/**
* 更新
* @param account
*/
public void updateAccount(Account account) {
accountDao.updateAccount(account);
}
/**
* 根据名称查询
* @param name
* @return
*/
public Account findByName(String name) {
return accountDao.findByName(name);
}
/**
* 查询全部
* @return
*/
public List<Account> findAll() {
return accountDao.findAll();
}
/**
* 根据id删除
* @param id
*/
public void deleteById(Integer id) {
accountDao.deleteById(id);
}
}
2.2 Spring配置(重点)

2.3 测试
java
/**
* 调用Userservice完成数据库CRUD操作
* @throws Exception
*/
@Test
public void testOne() throws Exception {
//1、创建spring容器
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//2、从容器中获取对象
AccountService accountService = (AccountService)ac.getBean( "accountService");
List<Account> list = accountService.findAll();
for (Account account : list) {
System.out.println(account);
}
}
第三章 Spring中的常见注解
3.1 环境搭建
(1)案例拷贝
(2)xml配置文件删除bean配置
使用注解替换bean标签的配置,我们将applicationContext.xml中的bean标签删除
java
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
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">
</beans>
(3)xml中加入包扫描
java
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
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">
<!--包扫描:扫描指定包下的所有java类,扫描类中的Spring注解,帮助我们自动的创建对象存入容器-->
<!--扫描路径:当前包及子包-->
<context:component-scan base-package="cn.itcast"></context:component-scan>
</beans>
包扫描:扫描指定包下的所有java类,扫描类中的Spring注解,帮助我们自动的创建对象存入容器
3.2 对象创建的注解
语法规则
创建对象交给spring容器管理,语义话的形式代码分层
<bean id="userDao" class="cn.itcast.dao.impl. userDaoImpl"></bean>
@Component(组件):
@Controller:在web层使用
@Service:在service层
@Repository:在dao层使用
当spring容器启动时,根据包扫描配置自动的扫描到@Component注解,反射创建注解标注的对象,存入容器
默认存入容器的id(唯一标识)=当前类名首字母小写(userDaoImpl)
value属性:自定义容器中对象的唯一标识
java代码如下
java
@Repository(value="userDao")
public class UserDaoImpl implements UserDao{
public void save(){
System.out.println("调用dao11111完成保存");
}
}
3.3 生命周期的注解
语法规则
对象的生命周期的注解
@Scope:配置到类上,生命对象的生命周期
singleton:单例(默认)
prototype:多例
@PostConstruct:相当于xml中的init-method
对象初始化方法:配置到对象的方法上
@PreDestory:相当于xml中的destory-method
对象的销毁方法:配置到对象的方法上
java代码如下
java
@Repository(value = "userDao1")
@Scope("prototype")
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("调用dao11111保存用户");
}
/**
* 初始化方法
*/
@PostConstruct
public void initMethod(){
System.out.println("对象执行了init方法");
}
/**
* 销毁方法
*/
@PreDestroy
public void destoryMethod(){
System.out.println("对象执行了destory方法");
}
}
3.4 依赖注入的注解
@Autowired
@Reource
@value
3.5 注解总结
使用注解编程之前,必须执行包扫描
第四章 注解结合XML完成案例(重点)
注解结合XML:
自定义的java对象通过注解配置(service, dao)---service,repository,autowired
第三方对象通过XML配置(QueryRunner,DataSource)
4.1 环境搭建

4.2 持久层代码

4.3 业务层代码

4.4 XML配置

第五章 第五章 Spring案例之纯注解版(了解)
注解版:使用注解配置第三方对象交给spring容器管理
Bean
5.1 开发步骤
环境搭建
删除XML配置文件
新建配置类
java
package cn.itcast.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
/**
* 通过SpringConfig替换之前的xml配置项
* 1、声明配置类,在类上配置一个注解
* @Configuration
* 2、开启包扫描
* @ComponentScan(basePackages = "cn.itcast")
* basePackages: 指定需要扫描的包
* 3、将第三方jar包对象,创建并交给容器管理
* @Bean
*/
@Configuration
@ComponentScan(basePackages = "cn.itcast")
public class SpringConfig {
@Bean
public DataSource getDataSource() {
DruidDataSource dataSource = new DruidDataSource();
//四元素
dataSource.setUsername("root");
dataSource.setPassword("root");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///heima31");
return dataSource;
}
//创建QueryRunner
@Bean
public QueryRunner getQueryRunner(DataSource dataSource) {
//dataSource : 从容器中获取的对象
QueryRunner queryRunner = new QueryRunner(dataSource);
return queryRunner;
}
}
新的注解
@Configuration---声明配置
@ComponentScan---指定包扫描
@Bean---创建第三方jar包中的对象
测试
5.2 案例优化
从外部加载配置文件
(1)准备properties文件
jdbc.username=root
jdbc.password=root
jdbc.driver=com.mysql.jdbc. Driver
jdbc.url=jdbc :mysql: ///heima31
(2)通过注解将此文件交给spring容器管理
java
@Propertysource(value="jdbc.properties ")
(3)通过@Value,获取文件中的属性,赋值到变量中
java
package cn.itcast.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
/**
* 通过SpringConfig替换之前的xml配置项
* 1、声明配置类,在类上配置一个注解
* @Configuration
* 2、开启包扫描
* @ComponentScan(basePackages = "cn.itcast")
* basePackages: 指定需要扫描的包
* 3、将第三方jar包对象,创建并交给容器管理
* @Bean
* 4、将properties配置文件,交给spring容器管理
* @PropertySource("jdbc.properties")
* value : properties路径
*/
@Configuration
@ComponentScan(basePackages = "cn.itcast")
@PropertySource(value="jdbc.properties")
public class SpringConfig {
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
/**
* @Bean : 创建第三方jar包对象,交给容器管理
* 语法:
* 1、@Bean注解需要配置到方法上
* 2、方法需要返回值
* 3、在Spring容器启动的时候,自动的扫描所有配置了@Bean的方法
* 4、自动执行被@Bean扫描的方法,将返回值存入Spring容器
* 5、如果方法需要参数,Spring会从容器中根据类型获取对象,再调用
* 在@Bean标注的方法中,可以配置依赖的属性参数
* spring会从容器中获取到依赖的对象,自动调用方法
*/
@Bean
public DataSource getDataSource() {
DruidDataSource dataSource = new DruidDataSource();
//四元素
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
return dataSource;
}
//创建QueryRunner
@Bean
public QueryRunner getQueryRunner(DataSource dataSource) {
//dataSource : 从容器中获取的对象
QueryRunner queryRunner = new QueryRunner(dataSource);
return queryRunner;
}
}
模块化
配置类臃肿,Spring支持多配置类(配置类的模块)
拆分配置类SpringConfig,添加一个新的子配置类JdbcConfig
java
package cn.itcast.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import javax.sql.DataSource;
public class JdbcConfig {
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
/**
* @Bean : 创建第三方jar包对象,交给容器管理
* 语法:
* 1、@Bean注解需要配置到方法上
* 2、方法需要返回值
* 3、在Spring容器启动的时候,自动的扫描所有配置了@Bean的方法
* 4、自动执行被@Bean扫描的方法,将返回值存入Spring容器
* 5、如果方法需要参数,Spring会从容器中根据类型获取对象,再调用
* 在@Bean标注的方法中,可以配置依赖的属性参数
* spring会从容器中获取到依赖的对象,自动调用方法
*/
@Bean
public DataSource getDataSource() {
DruidDataSource dataSource = new DruidDataSource();
//四元素
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
return dataSource;
}
}
在主配置类中,通过Import引入其他的配置类
java
package cn.itcast.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
@Configuration
@ComponentScan(basePackages = "cn.itcast")
@PropertySource(value="jdbc.properties")
//引入其他的配置类
@Import(value=JdbcConfig.class)
public class SpringConfig {
//创建QueryRunner
@Bean
public QueryRunner getQueryRunner(DataSource dataSource) {
//dataSource : 从容器中获取的对象
QueryRunner queryRunner = new QueryRunner(dataSource);
return queryRunner;
}
}
5.3 新注解总结

第六章 Spring整合单元测试(会用)
当在单元测试中,点击run的时候,底层工作的其实是一个运行器,默认是ParentRunner.这个运行器是junit提供的,它是不认识Spring的环境.这也就意味着,它无法从spring的容器中获取bean.
如果想要从Spring的容器中获取对象,那就必须先认识Spring环境.这时候,Spring提供了一个运行器,这个运行器就认识Spring环境,也就可以获取对象了
6.1 导入坐标
java
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--spring-junit 整合单元测试-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
6.2 配置注解
java
package cn.itcast.test;
import cn.itcast.domain.Account;
import cn.itcast.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* 1、指定单元测试环境:指定spring提供的单元测试环境
* @RunWith(SpringJUnit4ClassRunner.class)
* 2、指定spring的容器配置信息
* @ContextConfiguration
* locations : 配置文件路径
* classes : 配置类
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class AccountJunitTest {
@Autowired
private AccountService accountService;
//测试保存
@Test
public void testInsert() {
//3、调用方法保存
Account account = new Account();
account.setMoney(100.0);
account.setName("小李1");
accountService.saveAccount(account);
}
}
Spring第三天
第一章 转账案例(练习)
介绍:通过spring结合serivce,dao,dbuitils完成转账工程
转入账户:加款
转出账户:扣款
配置:采用流行的xml+注解的方式
效果:张三,向李四转账100元
1.1 代码开发
准备数据环境(略)
创建工程导入坐标
编写domain
编写dao接口
编写dao实现
编写service接口
编写service实现
加入spring的配置文件
java
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
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="cn.itcast"></context:component-scan>
<!--配置queryrunner-->
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
<constructor-arg name="ds" ref="dataSource"></constructor-arg>
</bean>
<!--配置datasource-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql:///spring"></property>
</bean>
</beans>
测试
java
import cn.itcast.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class AccountServiceTest {
@Autowired
private AccountService accountService;
@Test
public void testTransfer() {
accountService.transfer("小张","小李",1f);
}
}
1.2 问题分析

1.3 解决思路
1想办法让同一个业务中的所有sql使用同一个connection
2想办法禁止自动提交,然后手动控制事务的提交和回滚
1.4 传统解决方案
service层代码
java
package cn.itcast.service.impl;
import cn.itcast.dao.AccountDao;
import cn.itcast.domain.Account;
import cn.itcast.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
/**
* 已经配置好了数据源 datasource,可以通过datasource获取一个连接
*/
@Autowired
private DataSource dataSource;
//转账:转出账户名,转入账户名,转账金额
public void transfer(String sourceName, String targetName, Double money) throws SQLException {
//获取数据库连接
Connection connection = dataSource.getConnection();
//开启事务
connection.setAutoCommit(false);
try {
//1、根据账户名称,查询两个账户
Account sourceAccount = accountDao.findByName(connection,sourceName); //转出
Account targetAccount = accountDao.findByName(connection,targetName); //转入
//2、对于转出账户,扣款
sourceAccount.setMoney(sourceAccount.getMoney() - money);
//3、对于转入账户,加款
targetAccount.setMoney(targetAccount.getMoney() + money);
//4、更新转出账户和转入账户到数据库中
accountDao.update(connection,sourceAccount);
int i = 1/0;
accountDao.update(connection,targetAccount);
//提交事务
connection.commit();
}catch (Exception e) {
e.printStackTrace();
//回滚事务
connection.rollback();
}finally {
//释放资源
connection.close();
}
}
}
dao层代码
传统的解决方法,随着业务代码的不断增多,参数会越来越多且传递复杂
1.5 Threadlocal
Threadlocal:将数据绑定到当前线程上,同一个线程中。进过的不同方法都可以从Threadlocal获取数据,并且获取的数据是同一个对象
Threadlocal使用方法很简单
大致意思就是ThreadLocal提供了线程内存储变量的能力,这些变量不同之处在于每一个线程读取的变量是对应的互相独立的。通过get和set方法就可以得到当前线程对应的值。
java
ThreadLocal<T> sThreadLocal=new ThreadLocal<T>();
//将数据绑定到当前线程
sThreadLocal.set();
//从当前线程中获取数据
sThreadLocal.get();

第二章 开发事务管理器
2.1 代码开发
复制一个工程
编写事务管理器(copy)
java
package cn.itcast.utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
//事务管理器
@Component
public class TxManager {
@Autowired
private DataSource dataSource;
//准备好本地存储Connection对象的ThreadLocal
private ThreadLocal<Connection> th = new ThreadLocal<Connection>();
//获取Connection对象
public Connection getConnection() throws SQLException {
Connection connection = th.get();
if (connection == null){
connection = dataSource.getConnection();
th.set(connection);
}
return connection;
}
//开启
public void begin(){
try {
getConnection().setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
//提交
public void commit(){
try {
getConnection().commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
//回滚
public void rollback(){
try {
getConnection().rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
//关闭
public void close(){
try {
getConnection().close();
th.remove();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
修改dao
修改service
2.2 问题分析
现在的事务代码和业务代码严重耦合在一起了,我们希望的是这样
在不改动原来业务代码的前提下,给代码添加事务管理功能
即:在不修改源代码的情况下,给代码增强功能
2.3 解决思路
动态代理
第三章 动态代理优化转账
动态代理:在不改变源代码的前提下,对功能进行增强(对指定类中方法进行业务增强)
- java代码中只需要重点关注业务逻辑即可
- 增强部分内容,通过动态代理添加
动态代理在目前两种实现方式
- jdk动态代理
- cglib动态代理
3.1 jdk动态代理
复制工程
制作被代理对象
制作增强功能
产生代理对象(JDK)
java
package cn.itcast.test;
import cn.itcast.service.AccountService;
import cn.itcast.utils.TxManager;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AccountServiceTest {
@Autowired
private AccountService accountService;
@Autowired
private TxManager txManager;
@Test
public void testTransfer() {
// 产生目标对象(注入)
// 编写代理逻辑
InvocationHandler invocationHandler = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object obj = null;
try {
//开启事务
txManager.begin();
//调用目标对象的方法
obj = method.invoke(accountService, args);
//提交事务
txManager.commit();
} catch (Exception e) {
e.printStackTrace();
//回滚事务
txManager.rollback();
} finally {
txManager.close();
}
return obj;
}
};
// 创建代理对象
AccountService instance = (AccountService) Proxy.newProxyInstance(
accountService.getClass().getClassLoader(),
accountService.getClass().getInterfaces(),
invocationHandler
);
//让代理对象去工作
instance.transfer("B01", "B02", 10.0);
}
}
3.2 cglib动态代理(了解)
复制工程
去掉接口相关所有代码
只需要删除AccountService接口即可(注意修改实现类)
使用cglib的方式创建代理对象
java
package cn.itcast.test;
import cn.itcast.service.impl.AccountServiceImpl;
import cn.itcast.utils.TxManager;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.InvocationHandler;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.lang.reflect.Method;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AccountServiceTest {
@Autowired
private AccountServiceImpl accountService;
@Autowired
private TxManager txManager;
@Test
public void testTransfer() {
// 产生目标对象(注入)
// 编写代理逻辑
InvocationHandler invocationHandler = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object obj = null;
try {
//开启事务
txManager.begin();
//调用目标对象的方法
obj = method.invoke(accountService, args);
//提交事务
txManager.commit();
} catch (Exception e) {
e.printStackTrace();
//回滚事务
txManager.rollback();
} finally {
txManager.close();
}
return obj;
}
};
// 使用cglib的方式创建代理对象
// 1 创建增强器
Enhancer enhancer = new Enhancer();
// 2 设置父类
enhancer.setSuperclass(AccountServiceImpl.class);
// 3 设置代理逻辑
enhancer.setCallback(invocationHandler);
// 4 产生代理对象
AccountServiceImpl instance = (AccountServiceImpl) enhancer.create();
//5 让代理对象去工作
instance.transfer("B01", "B02", 10.0);
}
}
3.3 jdk和cglib两种代理方式的选择(面试)
首先明确在创建代理实现类时, jdk的速度要高于cglib,所以选择的时候:
当被代理类有接口的时候,使用jdk动态代理,因为它的效率高
当被代理类没有接口的时候,使用cglib动态代理,因为没办法
3.4 总结
当核心业务(转账)和增强业务(事务)同时出现时,我们可以在开发时对他们分别开发,运行时再组装在一起(使用动态代理的方式)。这样做的好处是:
1.逻辑清晰,开发核心业务的时候,不必关注增强业务的代码
2.代码复用性高:增强代码不用重复书写
这就是一种AOP的思想。
我的总结:
开发阶段分离开发,运行阶段组装运行
第四章 AOP概述

4.1 概念
AOP(面向切面编程)是一种思想,它的目的就是在不修改源代码的基础上,对原有功能进行增强.
Spring AOP是对AOP思想的一种实现,Spring底层同时支持jdk和cglib动态代理.
Spring会根据被代理的类是否有接口自动选择代理方式:
如果有接口,就采用jdk动态代理(当然,也可以强制使用cglib)
没有接口就采用cglib的方式
4.2 术语(难点)
目标对象--target:被代理的对象
连接点--jointPoint:被代理对象中的所有方法
切入点--pointCut:被增强的方法
增强(通知)
advice: 一个具体的增强功能
通知分为5种类型:
前置通知,后置通知,异常通知,最终通知,环绕通知
代理对象--proxy :生成的动态代理对象
切面
aspect
切面是一种描述,描述了一件事:一个什么样的功能添加到了哪个切入点的什么位置上
切面=切点+增强
第五章 SpringAOP的入门案例(重点)
在AccountDaolmpl类中的方法上打印日志
5.1 思路分析
目标对象(target) ----AccountDaolmpl类
被增强方法(pointcut) --- AccountDaolmpl类中的方法
增强功能(advice) ----打印日志
切面配置(aspect)-切点+增强日志在目标对象中的哪个方法的哪个位置上执行
5.2 代码开发
创建工程,引入坐标
java
<dependencies>
<!--spring aop-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<!--切点表达式的解析坐标-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>
<!--test-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
创建AccountDao的接口和实现类
开发增强功能
基于XML配置切面
切面类需要交给Spring容器管理
通过aop:config开启AOP配置
(1)配置切入点(被增强的类和方法)
(2)配置切面
第六章 SpringAOP配置详解
6.1 切入点表达式

6.2 四大通知
四大通知描述的就是增强方法在切点方法的什么位置上执行
前置通知(before):在切点运行之前执行
后置通知(after-returning):在切点正常运行结束之后执行
异常通知(after-throwing):在切点发生异常的时候执行
最终通知(after):在切点的最终执行
java
try{
前置通知(before) :在切点运行之前执行
//切点执行,被代理对象方法调用
后置通知(after-returning):在切点正常运行结束之后执行
}catch(Exception e){
异常通知(after-th rowing):在切点发生异常的时候执行
}finally{
最终通知(after):在切点的最终执行
}
方法
配置
由于多个通知类的配置顺序不同,导致不一样样的执行效果!!!
6.3 环绕通知
它是一种特殊的通知,他允许你以编码的形式实现四大通知(和手动定义动态代理类似)
方法
配置
6.4 AOP工作原理
开发阶段分别开发运行阶段组装运行
开发阶段
开发共性功能,制作成增强
开发非共性功能,制作成切点
在配置文件中,声明切点与增强间的关系,即切面
容器启动阶段
Spring读取配置文件中的切面信息,根据切面中的描述,
将增强功能增加在目标对象的切点方法上,动态创建代理对象
最后将经过代理之后对象放入容器中(存入容器的是动态代理对象!!!!!)
Spring第四天
第一章 SpringAOP注解版(重点)
AOP注解版
基于XML结合注解的配置方式(重点)
基于纯注解的配置方式(了解)
1.1 基于XML结合注解的配置
环境准备
XML配置文件
java
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--
基于XML结合注解配置
IOC的注解:开启包扫描
自定义的java对象,通过注解配置
第三方jar包对象,通过XML配置
AOP的注解:开启AOP注解的支持
在切面类方法上,通过注解的形式配置AOP
* 开启IOC的包扫描,开启AOP的自动代理
* 在切面类中完成
* 声明切面类
* 配置AOP通知类型
-->
<!--包扫描-->
<context:component-scan base-package="cn.itcast"></context:component-scan>
<!--开启AOP注解的支持,开启自动代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
修改dao
修改Logger切面类
java
package cn.itcast.dao.utils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* Logger : 切面类,增强类
* 基于注解的形式配置AOP
* 1、声明切面类 (Spring知道此类中具有增强通知方法)
* @Aspect
* 2、在增强通知方法上,通过注解配置通知类型
* @before:前置通知
* @afterReturning:后置通知
* @afterThrowing:异常通知
* @after:最终通知
* @around:环绕通知
*/
@Component
@Aspect
public class Logger {
/**
* 前置通知:在被代理对象方法之前,增强日志
*/
@Before(value="execution(* cn.itcast.dao.impl.*.*(..))")
public void before() {
System.out.println("执行前置通知:before方法");
}
/**
* 后置通知:被代理对象方法正常执行,获取返回值之后
*/
@AfterReturning(value="execution(* cn.itcast.dao.impl.*.*(..))")
public void afterReturining() {
System.out.println("执行后置通知:afterReturining");
}
/**
* 异常通知:调用过程中抛出异常时执行
*/
@AfterThrowing(value="execution(* cn.itcast.dao.impl.*.*(..))")
public void afterThrowing() {
System.out.println("执行异常通知:afterThrowing");
}
/**
* 最终通知:在最终代码块中需要执行的逻辑
*/
@After(value="execution(* cn.itcast.dao.impl.*.*(..))")
public void after() {
System.out.println("执行最终通知:after");
}
//环绕通知
public Object around(ProceedingJoinPoint pjp) throws Throwable {
Object obj = null;
try {
System.out.println("执行前置通知");
obj = pjp.proceed(); //执行被代理对象的方法
System.out.println("执行后置通知");
}catch (Exception e) {
System.out.println("执行异常通知");
}finally {
System.out.println("执行最终通知");
}
return obj;
}
}
四大通知类型的问题
通过注解配置四大通知类型,存在小BUG。执行顺序和XML配置不一致。在正常企业开发中不用
环绕通知(重点)
1.2 基于纯注解的配置(了解)
环境准备
编写配置类
第二章 SpringAOP实现事务管理
SpringAOP实现事务管理:基于AOP完成转账案例,通过AOP配置事务增强
2.1 基于XML的AOP事务配置
四个通知类型配置
(1)工程准备,导入依赖
java
<dependencies>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.15</version>
</dependency>
<!--dbutils-->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.7</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--spring ioc依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<!--spring-junit 整合单元测试-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<!--切点表达式的解析坐标-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>
</dependencies>
(2)修改AccountServiceImpl
(3)修改AccountDaoImpl
(4)配置切面类
(5)配置AOP
java
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
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 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--对象创建IOC-->
<bean id="accountService" class="cn.itcast.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
<bean id="accountDao" class="cn.itcast.dao.impl.AccountDaoImpl">
<property name="queryRunner" ref="queryRunner"></property>
<property name="txManager" ref="txManager"></property>
</bean>
<bean id="txManager" class="cn.itcast.utils.TxManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
<constructor-arg name="ds" ref="dataSource"></constructor-arg>
</bean>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="root"></property>
<property name="password" value="root"></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql:///heima31"></property>
</bean>
<!--AOP配置-->
<aop:config>
<!--切入点表达式 : 查找需要增强的方法-->
<aop:pointcut id="pt" expression="execution(* cn.itcast.service.impl.*.*(..))"/>
<!--配置切面-->
<aop:aspect ref="txManager">
<!--前置通知-->
<aop:before method="begin" pointcut-ref="pt"></aop:before>
<!--后置通知-->
<aop:after-returning method="commit" pointcut-ref="pt"></aop:after-returning>
<!--异常通知-->
<aop:after-throwing method="rollback" pointcut-ref="pt"></aop:after-throwing>
<!--最终通知-->
<aop:after method="close" pointcut-ref="pt"></aop:after>
</aop:aspect>
</aop:config>
</beans>
借助环绕通知配置(重点)
(1)切面类添加环绕通知方法
(2)XML中配置环绕通知
2.2 基于XML结合注解的AOP事务配置
搭建环境
(1)Dao层代码
(2)Service层代码
配置
(1)XML配置文件
(2)切面类配置
第三章 JdbcTemplate(会用)
3.1 JdbcTemplate介绍
方法介绍
java
package cn.itcast.test;
import cn.itcast.domain.Account;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
public class JdbcTemplateTest {
/**
* 练习JdbcTemplate的基本使用
*/
public static void main(String[] args) {
//1、创建DataSource
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUsername("root");
dataSource.setPassword("root");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///heima31");
//2、创建JdbcTemplate对象
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
//3、调用方法完成数据库操作
//3.1 保存,删除(update)
//jdbcTemplate.update("insert into account (name,money) values (?,?)" ,"小王",100f);
//3.2 查询数据列表(query)
//BeanPropertyRowMapper : 结果集处理器 (查询列表和唯一的时候,都使用同一个)
// List<Account> list = jdbcTemplate.query("select * from account", new BeanPropertyRowMapper<Account>(Account.class));
// for (Account account : list) {
// System.out.println(account);
// }
//3.3 根据id查询唯一的对象( queryForObject)
Account account = jdbcTemplate.queryForObject("select * from account where id=?", new BeanPropertyRowMapper<Account>(Account.class), 1);
System.out.println(account);
}
}
3.2 JdbcTemplate案例
使用dbcTemplate完成一个crud和转账的案例,使用xml结合注解的形式配置
(1)准备数据环境
和之前的数据库一模一样,账户操作
(2)创建工程,导入坐标
java
<dependencies>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.15</version>
</dependency>
<!--spring-jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<!--spring-context-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--spring-test-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<!--添加切点表达式-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>
</dependencies>
(3)创建实体类
(4)创建dao接口
(5)创建dao实现
(6)创建service接口
(7)创建service实现
(8)加入Spring的配置文件
(9)测试
java
package cn.itcast.test;
import cn.itcast.domain.Account;
import cn.itcast.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class AccountServiceTest {
@Autowired
private AccountService accountService;
@Test
public void testFindAll() {
List<Account> list = accountService.findAll();
for (Account account : list) {
System.out.println(account);
}
}
@Test
public void testTransfer() throws Exception {
accountService.transfer("小张", "小李",1f);
}
}
第四章 Spring中的事务管理(了解)
Spring中的事务管理:根据SpringAOP拓展出来的事务控制功能
4.1 事务管理方式
Spring支持两种事务管理方式:编程式事务和声明式事务
编程式事务就是将业务代码和事务代码放在一起书写,它的耦合性太高,开发中不使用
声明式事务通过一段配置让程序组装运行,最后达到事务控制的目的
声明式事务就是通过AOP原理实现的
4.2 Spring事务管理相关的API
PlateformTransactionManager
TransactionDefinition
TransactionDefinition这个API是用来做事务定义的
面向配置(事务隔离级别,传播行为,是否只读事务,超时时间)
隔离级别(*)
传播行为(理解)
是否只读事务
超时时长
配置项总结
第五章 声明式事务(重点)
5.1 思路
目标对象[业务类]service
增强[事务管理器]DataSourceTransactionManager
事务配置:[事务隔离级别事务传播行为事务是否只读事务超时时长]
5.2 xml版(重点)

5.3 注解结合XML(重点)

(1)复制工程
(2)删除xml中的tx:advice和aop:config
(3)添加一个事务注解驱动
(4)在方法上添加声明式事务的注解
5.4 纯注解版(了解)

java
package cn.itcast.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
/**
* 1、声明配置类
* 2、开启包扫描
* 3、开始事务注解管理
* @EnableTransactionManagement
* 4、第三方对象
*/
@Configuration
@ComponentScan(basePackages = "cn.itcast")
@EnableTransactionManagement
public class SpringConfig {
/**
* @Bean:配置到方法上,表明此方法的返回值交给Spring容器管理
* 在Spring容器启动时,自动的扫描所有@Bean的方法
* 自动执行并获取返回值,存入Spring容器
* 在方法上配置参数,Spring会自动的从容器中获取对象,自动调用方法
*/
/**
* DataSource
*/
@Bean
public DataSource getDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUsername("root");
dataSource.setPassword("root");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///heima31");
return dataSource;
}
/**
* JdbcTemplate
*/
@Bean
public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
/**
* 事务管理器
*/
@Bean
public PlatformTransactionManager getTransactionManager(DataSource dataSource) {
DataSourceTransactionManager tm = new DataSourceTransactionManager();
tm.setDataSource(dataSource);
return tm;
}
}
第六章 事务补充
6.1 准备

sql
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
`age` smallint(3) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
CREATE TABLE `role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`role_name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
6.2 测试
6.3 try catch影响
6.4 事务嵌套影响
上面的代码可以改造成如下代码:
java
@Transactional
public void out() throws Exception{
Role role=new Role();
Role.setRoleName("roleName:"+new Random().nextInt(100));
roleService.save(role);
int age=random.nextInt(100);
User user=new User().setAge(age).setName("name:"+age);
userService.save(user);
throw new Exception();
}
这个是inner的方法没有抛出异常,out的代码抛出了异常,所以代码可以改造成如上样子。所以结合结论一,事务回滚都失败。