Spring框架概述
-
Spring 是轻量级开源的 JavaEE框架
-
Spring 可以解决企业应用开发的复杂性
-
Spring 有两个核心部分:IOC和AOP
(1)IOC:控制反转,把创建对象过程交给Spring容器进行管理
(2)AOP:面向切面,不修改源代码进行功能增强
-
Spring特点:
(1)方便解耦,简化开发
(2)AOP编程支持
(3)方便程序测试
(4)方便和其他框架进行整合
(5)方便进行事务操作
(6)降低API开发难度
IOC(概念和原理)
1、什么是IOC
- 控制反转、依赖注入,把对象创建和对象之间调用的过程,交给Spring容器进行管理
- 使用IOC目的:为了降低耦合度
2、Ioc底层原理
- xml解析、工厂模式、反射
3、画图讲解IOC底层原理
IOC(接口)
1、IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
2、Spring提供IOC容器实现两种方式:(两个接口)
-
BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供开发人员进行使用
主意:加载配置文件时候不会创建对象,而是在获取对象(使用)才去创建对象
-
ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员进行使用
主意:加载配置文件时候就会把在配置文件对象进行创建
3、ApplicationContext接口由实现类
File开头:就是要写你配置在你系统上的路径
Class开头:就是你配置在src下的
IOC操作Bean管理
基于xml操作
1、什么是Bean管理
Bean管理指的是两个操作:
(1)Spring创建对象
(2)Spring注入属性
2、Bean管理操作有两种方式
(1)基于xml配置文件方式实现
(2)基于注解方式实现
Ioc操作Bean管理(基于xml方式)
1、基于xml方式创建对象
<bean id="user" class="com.dong.mapper.userMapper"></bean>
(1)在spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建
(2)在bean标签有很多属性,介绍常用的属性:
1、id属性:唯一标识
2、class属性:类全路径(包类路径)
(3)创建对象时候,默认也是执行无参构造方法完成对象创建
2、基于xml方式注入属性
DI:依赖注入,就是注入属性
-
第一种注入方式:使用set方法进行注入
<bean id="user" class="com.dong.mapper.userMapper"> <property name="userName" value="小明"></property> </bean>
-
第二种注入方式:使用有参构造进行注入
<bean id="user" class="com.dong.mapper.userMapper"> <constructor-arg name="userName" value="小明"></constructor-arg> <constructor-arg name="address" value="郴州"></constructor-arg> </bean>
-
第三种注入方式:使用p命名空间注入
<bean id="user" class="com.dong.mapper.userMapper" p:userName="小明" p:address="郴州"> </bean>
3、Ioc操作Bean管理(xml注入其他类型属性)
-
字面量
<!--null值注入--> <property name="userName"> <null/> </property>
-
属性值包含特殊符号
<peoperty name="userName"> <value><![CDATA[<<小明>>]]></value> </peoperty>
4、注入属性—外部Bean
-
采用ref实现外部Bean注入
<bean id="userService" class="com.dong.mapper.userMapper"> <!-- name属性:类里面属性名称 ref属性:创建userDao对象bean标签id值 --> <property name="userDao" ref="userDaoImpl"></property> </bean> <bean id="userDaoImpl" class="com.dong.mapper.userMapper"></bean>
//创建UserDao类型属性,生成set方法 private UserDao userDao; public void setUserDao(UserDao userDao){ this.userDao = userDao; }
5、注入属性—内部Bean
-
一对多关系 多对一关系
<!--内部Bean--> <bean id="emp" class="com.dong.bean.Emp"> <!--设置两个普通属性--> <property name="ename" value="lucy"></property> <property name="gender" value="女"></property> <!--设置对象类型属性--> <property name="dept"> <bean id="dept" class="com.dong.bean.Dept"> <property name="dname" value="安保部"></property> </bean> </property> </bean>
6、注入属性级联赋值
-
方式一:
<!--级联赋值--> <bean id="emp" class="com.dong.bean.Emp"> <!--设置两个普通属性--> <property name="ename" value="lucy"></property> <property name="gender" value="女"></property> <!--级联赋值--> <property name="dept" ref="dept"></property> </bean> <bean id="dept" class="com.dong.bean.Dept"> <property name="dname" value="财务部"></property> </bean>
-
方式二: 主意需要生成对象的get方法
<!--级联赋值--> <bean id="emp" class="com.dong.bean.Emp"> <!--设置两个普通属性--> <property name="ename" value="lucy"></property> <property name="gender" value="女"></property> <!--级联赋值--> <property name="dept" ref="dept"></property> <property name="dept.dname" value="技术部"></property> </bean> <bean id="dept" class="com.dong.bean.Dept"> <property name="dname" value="财务部"></property> </bean>
7、注入集合属性
-
注入数组类型属性
-
注入List集合类型属性
-
注入Map集合类型属性
<!--集合类型属性注入--> <bean id="stu" class="com.dong.collectiontype.Stu"> <!--数组类型属性注入--> <property name="courses"> <array> <value>java课程</value> <value>数据库课程</value> </array> </property> <!--list类型属性注入--> <property name="list"> <list> <value>大明</value> <value>小明</value> </list> </property> <!--注入list集合类型,值是对象--> <property name="courseList"> <list> <ref bean="obj1"></ref> <ref bean="obj2"></ref> </list> </property> <!--map类型属性注入--> <property name="maps"> <map> <entry key="JAVA" value="java"></entry> <entry key="PHP" value="php"></entry> </map> </property> <!--set类型属性注入--> <property name="sets"> <set> <value>MySql</value> <value>Redis</value> </set> </property> </bean>
8、把集合注入部分提取出来
-
在spring配置文件中引入名称空间util
<!--1、提取list集合类型属性注入--> <util:list id="bookList"> <value>小明</value> <value>中明</value> <value>大明</value> </util:list> <!--2、提取list集合类型属性注入使用--> <bean id="book" class="com.dong.collectiontype.Book"> <property name="list" ref="bookList"></property> </bean>
9、工厂Bean(FactoryBean)
Spring 有两种类型Bean,一种普通bean,另外一种工厂bean(FactoryBean)
-
普通bean:在配置文件中定义bean类型就是返回类型
-
工厂bean:在配置文件定义bean类型可以和返回类型不一样
(1)创建类,让这个类作为工厂bean,实现接口FactoryBean
(2)实现接口里面的方法,在实现的方法中定义返回的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" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="myBean" class="com.dong.bean.MyBean"></bean> </beans>
package com.dong.bean; import org.springframework.beans.factory.FactoryBean; public class MyBean implements FactoryBean<Doc> { public Doc getObject() throws Exception { Doc doc = new Doc(); doc.setName("abc"); return doc; } public Class<?> getObjectType() { return null; } public boolean isSingleton() { return false; } } @Test public void test1(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Doc doc = context.getBean("myBean", Doc.class); System.out.println(doc.getName()); }
10、Bean作用域
(1)在Spring里面,设置创建bean实例是单实例还是多实例
(2)在Spring里面,默认情况下,bean是单实例对象
(3)如何设置单实例还是多实例
-
在spring配置文件bean标签里面有属性(scope)用于设置单实例还是多实例
-
scope属性值
*第一个值 默认值,singleton,表示是单实例对象
*第二个值 prototype,表示是多实例对象
<bean id="doc" class="com.dong.bean.Doc" scope="prototype"></bean>
*singleton和prototype区别
第一 singleton单实例,prototype多实例
第二 设置scope值是singleton时候,加载spring配置文件时候就会创建单实例对象
设置scope值是prototype时候,不是在加载spring配置文件时候创建对象,在调用getBean方式时候创建多实例对象
11、Bean生命周期
1、生命周期
(1)从对象创建到对象销毁的过程
2、bean生命周期
(1)通过构造器创建bean实例(无参构造)
(2)为bean的属性设置值和对其他bean引用(调用set方法)
(3)调用bean的初始化的方法(需要进行配置初始化的方法)
(4)bean可以使用了(对象获取到了)
(5)当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁的方法)
package com.dong.bean;
public class Orders {
private String oname;
public Orders() {
System.out.println("第一步 执行无参构造创建bean实例");
}
public void setOname(String oname) {
this.oname = oname;
System.out.println("第二步 调用set方法设置属性值");
}
//创建执行的初始化的方法
public void initMethod(){
System.out.println("第三步 执行初始化的方法");
}
//创建执行的销毁的方法
public void destroyMethod(){
System.out.println("第五步 执行销毁的方法");
}
}
<bean id="orders" class="com.dong.bean.Orders" init-method="initMethod" destroy-method="destroyMethod">
<property name="oname" value="手机"></property>
</bean>
@Test
public void test3(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Orders orders = context.getBean("orders", Orders.class);
System.out.println("第四部 获取创建bean实例对象");
//手动让bean实例销毁
context.close();
}
在调用bean初始化之前和之后可以添加处理器,也就是说生命周期有七步
主意:配置了后置处理器,在调用每个bean都会在bean初始化之前和之后执行!
package com.dong.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPost implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之前执行的方法");
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之后执行的方法");
return bean;
}
}
<!--配置后置处理器-->
<bean id="myBeanPost" class="com.dong.bean.MyBeanPost"></bean>
12、xml自动装配
(1)什么是自动装配
- 根据指定装配规则(属性名称或者属性类型),spring自动将配置的属性值进行注入
(2)演示
<!--
实现自动装配:
bean标签属性autowire,配置自动装配
autowire属性常用两个值:
byName根据属性名称注入,注入值bean的id值和类属性名称一样
byType根据属性类型注入,注入值bean的class值和类路径一样
-->
<bean id="emp" class="com.dong.autowire.Emp" autowire="byName"></bean>
<bean id="dept" class="com.dong.autowire.Dept"></bean>
13、外部属性文件
(1)直接配置数据库信息(JDBC配置)
- 配置德鲁伊连接池
- 引入德鲁伊连接池依赖或jar包
xml操作结束!
14、注解实现bean创建
1、什么是注解
(1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值...)
(2)使用注解,注解作用在类上面、方法上面、属性上面
(3)使用注解目的:简化xml配置
2、Spring针对Bean管理中创建对象提供注解
(1)@Component 主键
(2)@Service 业务逻辑主键
(3)@Controller 控制器
(4)@Repository 数据库控制主键
主意:上面四个注解功能是一样的,都可以用来创建bean实例
3、基于注解方式实现对象创建
(1)引入依赖
spring-aop-5.2.6.RELEASE
(2)开启组件扫描
<!--
开启组件扫描
1 如果扫描多个包,多个包使用逗号隔开
2 扫描包上层目录
-->
<context:component-scan base-package="com.dong"></context:component-scan>
(3)使用注解
(4)开启组件扫描细节配置
<!--实例一
use-default-filters="false" 表示现在不使用默认filter,自己配置filer
context:include-filter,设置扫描指定内容
-->
<context:component-scan base-package="com.dong" use-default-filters="false">
<context:include-filter type="annotation"
expression="org.dong.Controller"/>
</context:component-scan>
<!--实例二
下面配置扫描包所有内容
context:exclude-filter:设置指定内容不进行扫描
-->
<context:component-scan base-package="com.dong">
<context:exclude-filter type="annotation"
expression="org.dong.Controller"/>
</context:component-scan>
15、注解方式实现属性注入
(1)@Autowired:根据属性类型进行自动装配
(2)@Qualifier:根据属性名称进行注入
(3)@Resource:可以根据类型注入,可以根据名称注入
(4)@Value:注入普通类型属性
16、完全注解开发
(1)创建配置类
@Configuration //作为配置类,替代xml配置文件
@ComponentScan(basePackages={"com.dong"}) //替代扫描包
public class SpringConfig(){
}
(2) 测试修改
//加载配置类
ApplicationContext context = new AnnotaionConfigApplicationContext(SpringConfig.class);
AOP
1、什么是AOP(概念)
(1)面向切面编程(方面),利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
(2)通俗描述:不通过修改源代码方式,在主干功能里面添加新功能
2、AOP(底层原理)
1、AOP底层使用动态代理
有两种情况动态代理
(1)有接口的情况,使用JDK动态代理
-
创建接口实现类代理对象,增强类的方法
(2)没有接口的情况,使用CGLIB动态代理
-
创建子类的代理对象,增强类的方法
3、AOP(JDK动态代理)
1、使用JDK动态代理,使用Proxy类里面的方法创建代理对象
调用newProxyInstance方法
此方法有三个参数
(1)类加载器
(2)增强方法所在的类,这个类实现的接口,支持多个接口
(3)实现这个接口InvocationHandler,创建代理对象,写增强的方法
2、编写JDK动态代理代码
(1)创建接口,定义方法
package com.dong.demo;
//创建接口,定义方法
public interface UserDao {
int add (int a,int b);
String update(String id);
}
(2)创建接口实现类,实现方法
package com.dong.demo;
//创建接口实现类,实现方法
public class UserDaoImpl implements UserDao{
public int add(int a, int b) {
System.out.println("执行了add方法....");
return a+b;
}
public String update(String id) {
System.out.println("执行了update方法....");
return id;
}
}
(3)使用Proxy类创建接口代理对象
package com.dong.demo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
//使用Proxy类创建接口代理对象
public class JDKProxy {
public static void main(String[] args) {
//创建接口实现类代理对象
Class[] interfaces = {UserDao.class};
UserDaoImpl userDao = new UserDaoImpl();
UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new userDaoProxy(userDao));
int result = dao.add(1, 2);
System.out.println("result:"+result);
}
//创建代理对象代码
static class userDaoProxy implements InvocationHandler{
//把创建的是谁的代理对象,把谁传递过来
//有参构造传递
private Object obj;
public userDaoProxy(Object obj){
this.obj = obj;
}
//增强的逻辑
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法之前
System.out.println("方法之前执行...."+method.getName()+":传递的参数..."+ Arrays.toString(args));
//被增强的方法执行
Object res = method.invoke(obj,args);
//方法之后
System.out.println("方法之后执行...."+obj);
return res;
}
}
}
4、AOP(术语)
(1)连接点
- 类里面哪些方法可以被增强,这些方法就称为连接点
(2)切入点
- 实际被真正增强的方法,称为切入点
(3)通知(增强)
- 实际增强的逻辑部分称为通知(增强)
- 增强有多种类型
- 前置增强
- 后置增强
- 环绕增强
- 异常增强
- 最终增强
(4)切面
- 把增强应用到切入点的过程就叫做切面,他是个动作
5、AOP操作(准备工作)
(1)Spring框架一般都是基于AspectJ实现AOP操作
- AspectJ不是Spring组成部分,是一个独立AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作
(2)基于AspectJ实现AOP操作
- 基于xml配置文件实现
- 基于注解方式实现(使用)
(3)在项目工程里面引入AOP相关依赖
<!--AOP-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
(4)切入点表达式
- 切入点表达式作用:知道对哪个类里面的哪个方法进行增强
- 语法结构:
- execution([权限修饰符] [返回类型] [类全路径] [方法名称] ([参数列表]))
举例一:对com.dong.BookDao类里面的add方法进行增强
execution(* com.dong.BookDao.add(..))
举例二:对com.dong.BookDao类里面的所有方法进行增强
execution(* com.dong.BookDao.*(..))
举例三:对com.dong包里面所有类,类里面所有方法进行增强
execution(* com.dong..(..))
6、AOP操作(AspectJ注解)
1、创建类,在类里面定义方法
package com.dong.aopanno;
public class User {
public void add(){
System.out.println("add......");
}
}
2、创建增强类(编写增强逻辑)
- 在增强类里面,创建方法,让不同方法代表不同通知类型
package com.dong.aopanno;
//增强的类
public class UserProxy {
//前置增强
public void before(){
System.out.println("before....");
}
}
3、进行通知的配置
(1)在spring配置文件中,开启注解扫描
<!--开启扫描包-->
<context:component-scan base-package="com.dong.aopanno"></context:component-scan>
(2)使用注解创建User和UserProxy对象
@Component
public class User
@Component
public class UserProxy
(3)在增强类上面添加注解@Aspect
@Aspect
public class UserProxy
(4)在spring配置文件中开启生成代理对象
<!--开启Aspect生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
4、配置不同类型的通知
-
在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置
package com.dong.aopanno; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; //增强的类 @Component @Aspect public class UserProxy { //定义切入点 @Pointcut("execution(* com.dong.aopanno.User.*(..))") public void pointcut(){} //前置增强 @Before(value = "pointcut()") public void before(){ System.out.println("前置增强before...."); } //最终增强 @After(value = "pointcut()") public void after(){ System.out.println("最终增强after...."); } //后置增强 @AfterReturning(value = "pointcut()") public void afterReturning(){ System.out.println("后置增强AfterReturning...."); } //异常处理 @AfterThrowing(value = "pointcut()") public void afterThrowing(){ System.out.println("异常处理afterThrowing...."); } //环绕增强 @Around(value = "pointcut()") public void around(ProceedingJoinPoint jp) throws Throwable { System.out.println("环绕之前...."); Object proceed = jp.proceed(); System.out.println("环绕之后...."); } }
5、有多个增强类同一个方法进行增强,设置增强类的优先级
- 在增强类上面添加注解@Order(数字类型值),数字类型值越小优先级越高
6、完全使用注解开发
-
创建配置类,不需要xml配置文件
@Configuration @ComponentScan(basePakcages={"com.dong"}) @EnableAspectJAutoProxy(proxyTargetClass=true) public class ConfigAop{ }
7、AOP操作(AspectJ配置文件)
1、创建两个类,增强类和被增强类,创建方法
2、在spring 配置文件中创建两个类对象
3、在spring配置文件中配置切入点
JdbcTemplate
1、什么是JdbcTemplate(概念和准备)
(1)Spring框架对JDBC进行封装,使用JdbcTemplate方便实现对数据库操作
(2)在spring配置文件中配置数据库连接池
<!--引入properties文件-->
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="location">
<value>classpath:database.properties</value>
</property>
</bean>
<!--配置数据池-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
(3)配置JdbcTemplate对象,注入DataSource
<!--JdbcTemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入dataSource-->
<property name="dataSource" ref="dataSource"/>
</bean>
(4)创建service类,创建dao类,在dao注入jdbcTemplate对象
<!--组件扫描-->
<context:component-scan base-package="com.dong.jdbc"></context:component-scan>
//dao
@Repository
public class BookDaoImpl implements BookDao{
//注入JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
}
//service
@Service
public class BookService {
//注入dao
@Autowired
private BookDao bookDao;
}
2、实现CRUD操作
(1)dao层
package com.dong.jdbc.dao;
import com.dong.jdbc.entity.Book;
import java.util.List;
public interface BookDao {
//添加
int add(Book book);
//修改
int update(Book book);
//删除
int delete(int id);
//查询表总记录
int queryCount();
//查询总数据
List<Book> queryBookList();
//批量添加
void batchAddBook(List<Object[]> batchArgs);
//批量修改
void batchUpdateBook(List<Object[]> batchArgs);
//批量删除
void batchDeleteBook(List<Object[]> batchArgs);
}
(2)dao实现类
package com.dong.jdbc.dao;
import com.dong.jdbc.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.List;
@Repository
public class BookDaoImpl implements BookDao{
//注入JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
//添加
public int add(Book book) {
String sql = "insert into book value(?,?,?,?)";
int result = jdbcTemplate.update(sql, book.getUserId(),book.getUserName(), book.getUserAge(), book.getUserSex());
return result;
}
//修改
public int update(Book book) {
String sql = "update book set userName = ? where userId = ?";
int result = jdbcTemplate.update(sql, book.getUserName(), book.getUserId());
return result;
}
//删除
public int delete(int id) {
String sql = "delete from book where userId = ?";
int result = jdbcTemplate.update(sql, id);
return result;
}
//查询表总记录数
public int queryCount() {
String sql = "select count(*) from book";
Integer result = jdbcTemplate.queryForObject(sql, Integer.class);
return result;
}
//查询总数据
public List<Book> queryBookList() {
String sql = "select * from book";
List<Book> books = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Book>(Book.class));
return books;
}
//批量添加
public void batchAddBook(List<Object[]> batchArgs) {
String sql = "insert into book value(?,?,?,?)";
int[] ints = jdbcTemplate.batchUpdate(sql,batchArgs);
System.out.println(Arrays.toString(ints));
}
//批量修改
public void batchUpdateBook(List<Object[]> batchArgs) {
String sql = "update book set userName = ? where userId = ?";
int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
System.out.println(Arrays.toString(ints));
}
//批量删除
public void batchDeleteBook(List<Object[]> batchArgs) {
String sql = "delete from book where userId = ?";
int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
System.out.println(Arrays.toString(ints));
}
}
(3)service层
package com.dong.jdbc.service;
import com.dong.jdbc.dao.BookDao;
import com.dong.jdbc.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class BookService {
//注入dao
@Autowired
private BookDao bookDao;
//添加操作
public int add(Book book){
int result = bookDao.add(book);
return result;
}
//修改操作
public int update(Book book){
int result = bookDao.update(book);
return result;
}
//删除操作
public int delete(int id){
int result = bookDao.delete(id);
return result;
}
//查询表总记录
public int queryCount(){
int result = bookDao.queryCount();
return result;
}
//查询总数据
public List<Book> queryBookList(){
List<Book> books = bookDao.queryBookList();
return books;
}
//批量添加
public void batchAddBook(List<Object[]> batchArgs){
bookDao.batchAddBook(batchArgs);
}
//批量修改
public void batchUpdateBook(List<Object[]> batchArgs){
bookDao.batchUpdateBook(batchArgs);
}
//批量删除
public void batchDeleteBook(List<Object[]> batchArgs){
bookDao.batchDeleteBook(batchArgs);
}
}
(4)测试
package com.dong;
import com.dong.jdbc.entity.Book;
import com.dong.jdbc.service.BookService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.ArrayList;
import java.util.List;
public class TestCRUD {
@Test
//添加
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = context.getBean("bookService", BookService.class);
Book book = new Book(3,"小明",18,"男");
int result = bookService.add(book);
System.out.println(result);
}
@Test
//修改
public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = context.getBean("bookService", BookService.class);
Book book = new Book(1,"小小",18,"男");
int result = bookService.update(book);
System.out.println(result);
}
@Test
//删除
public void test3(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = context.getBean("bookService", BookService.class);
int result = bookService.delete(2);
System.out.println(result);
}
@Test
//查询表总记录数
public void test4(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = context.getBean("bookService", BookService.class);
int result = bookService.queryCount();
System.out.println(result);
}
@Test
//查询表总数据
public void test5(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = context.getBean("bookService", BookService.class);
List<Book> books = bookService.queryBookList();
System.out.println(books.toString());
}
@Test
//批量添加
public void test6(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = context.getBean("bookService", BookService.class);
List<Object[]> batchArgs = new ArrayList<Object[]>();
Object[] o1 = {3,"胡话",15,"男"};
Object[] o2 = {4,"小娜",22,"女"};
Object[] o3 = {5,"慧慧",18,"女"};
batchArgs.add(o1);
batchArgs.add(o2);
batchArgs.add(o3);
bookService.batchAddBook(batchArgs);
}
@Test
//批量修改
public void test7(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = context.getBean("bookService", BookService.class);
List<Object[]> batchArgs = new ArrayList<Object[]>();
Object[] o1 = {"胡话h",3};
Object[] o2 = {"小娜n",4};
Object[] o3 = {"慧慧h",5};
batchArgs.add(o1);
batchArgs.add(o2);
batchArgs.add(o3);
bookService.batchUpdateBook(batchArgs);
}
@Test
//批量删除
public void test8(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = context.getBean("bookService", BookService.class);
List<Object[]> batchArgs = new ArrayList<Object[]>();
Object[] o1 = {3};
Object[] o2 = {4};
Object[] o3 = {5};
batchArgs.add(o1);
batchArgs.add(o2);
batchArgs.add(o3);
bookService.batchDeleteBook(batchArgs);
}
}
事务
1、事务概念
(1)什么是事务?
- 事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败所有操作都失败
- 典型场景:银行转账 比如 lucy转账100元给mary lucy少100,mary多100
(2)事务四个特性(ACID)
- 原子性:要么都成功,要么都失败。
- 一致性:操作之前和操作之后的总量还是一致的。
- 隔离性:多人操作,不会受到影响。
- 持久性:将数据持久化存储。
2、事务操作(环境)
3、事务操作(Spring事务管理介绍)
(1)事务添加到JavaEE三层结构里面Service层(业务逻辑层)
(2)在Spring 进行事务管理操作
- 有两种方式:编程式事务管理和声明式事务管理(推荐)
(3)声明式事务管理
- 基于注解方式(推荐)
- 基于xml配置文件方式
(4)在Spring进行声明式事务管理,底层使用AOP原理
(5)Spring事务管理API
-
提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类
4、事务操作(注解声明式事务管理)
(1)在Spring配置文件配置事务管理器
<!--创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据库-->
<property name="dataSource" ref="dataSource"/>
</bean>
(2)在Spring配置文件,开启事务注解
-
在spring 配置文件中引入名称空间tx
xmlns:tx="http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd
-
开启事务注解
<!--开启事务注解--> <tx:annotation-driven transaction-manager="transactionManager"/>
(3)在service类上面(或者service类中方法上面)添加事务注解
-
@Transactional,这个注解添加到类上面,也可以添加方法上面
-
如果把这个注解添加类上面,这个类里面所有的方法都添加事务
-
如果把这个注解添加方法上面,只为这个方法添加事务
@Service @Transactional public class UserService { }
5、事务操作(声明式事务管理参数配置 事务传播)
事务参数配置:https://blog.csdn.net/qq_42388853/article/details/108331607
(1)propagationo 事务的传播行为
6、事务隔离级别
ioslation:事务隔离级别
(1)事务有特性成为隔离性,多事务操作之间不会产生影响,不考虑隔离性产生很多问题
(2)有三个读问题:脏读、不可重复读、虚(幻)读
- 脏读:一个未提交事务读取到另一个未提交事务的数据
-
不可重复读:一个未提交事务读取到另一个提交事务修改数据
-
虚度:一个未提交事务读取到另一个提交事务添加数据
-
解决:通过设置事务隔离性,解决读问题
-
@Service @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ) public class UserService { }
(1)timeout:超时时间
- 事务需要在一定时间内进行提交,如果不提交进行回滚
- 默认值是-1,设置时间以秒单位进行计算
(2)readOnly:是否只读
- 读:查询操作,写:添加修改删除操作
- readOnly默认值false,表示可以查询,可以添加修改删除操作
- 设置readOnly值是true,设置成true之后,只能查询
(3)rollbackFor:回滚
- 设置出现哪些异常进行事务回滚
(4)noRollbackFor:不回滚
-
设置出现哪些异常不进行事务回滚
@Service @Transactional(rollbackFor = Exception.class,readOnly = false,timeout = -1,propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ) public class UserService { }
事务操作(xml声明式事务管理)
(1)在srping配置文件中进行配置
-
配置事务管理器
-
配置通知
-
配置切入点和切面
<!--1 创建事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--注入数据库--> <property name="dataSource" ref="dataSource"></property> </bean> <!--2 配置通知--> <tx:advice id="txadvice"> <!--配置事务参数--> <tx:attributes> <!--指定那种规则的方法上面添加事务--> <tx:method name="accountMoney" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!--3 配置切入点和切面--> <aop:config> <!--配置切入点--> <aop:pointcut id="pt" expression="execution(* com.dong.shiwu.service.UserService(..))"/> <!--配置切面--> <aop:advisor advice-ref="txadvice" pointcut-ref="pt"/> </aop:config>
完全使用注解开发
package com.dong.shiwu;
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.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
@Configuration //配置类
@ComponentScan(basePackages = "com.dong.shiwu") //组件扫描
@EnableTransactionManagement // 开启事务
public class TxConfig {
//创建数据库连接池
@Bean
public DruidDataSource getDruidDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///mybatis_plus");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
@Bean
public JdbcTemplate getJdbcTemplate(DataSource dataSource){
//到ioc容器中根据类型找到dataSource
JdbcTemplate jdbcTemplate = new JdbcTemplate();
//注入dataSource
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
//创建事务管理器
@Bean
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}
Spring框架新功能
1、log4j2
1、整个Spring5框架的代码基于Java8,运行时兼容JDK9,许多不建议使用的类和方法在代码库中删除
2、Spring5.0框架自带了通用的日志封装
(1)Spring5已经移除了Log4jConfigListener,官方建议使用Log4j2
(2)Spring5框架整合Log4j2
第一步引入依赖
<!--log4j2-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.18.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.1</version>
</dependency>
第二步 创建log4j2.xml配置文件(必须这个名称)
<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序:0FF >EATAL >ERROR >WARNV〉 INFO〉DEBUG > TRACE> ALL -->
<!--Configuration后面的status用于设置log4.2自身内部的信息输出,可以不设置,当设置成trace时,可以看到log4j2内部各种详细输出-->
<configuration status="INFO">
<!--一先定义所有的appender-->
<appenders>
<!--输出日志信息到控制台-->
<console name="Console" target="SYSTEM_OUT">
<!--控制日志输出的格式-->
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger {36} -%msg%n"/>
</console>
</appenders>
<!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
<!--root:用于指定项目的根日志,如果没有单独指定Logger,则会使用root作为默认的日志输出-->
<loggers>
<root level="info">
<appender-ref ref="Console"/>
</root>
</loggers>
</configuration>
2、核心容器支持@Nullable注解
(1)@Nullable注解可以使用在方法上面,属性上面,参数上面,表示方法返回可以为空,属性值可以为空,参数值可以为空
(2)注解用在方法上面,方法返回值可以为空
3、核心容器支持函数式风格GenericApplicationContext
//函数式风格创建对象,交给spring进行管理
@Test
public void testGenericApplicationContext(){
//1、创建GenericApplicationContext对象
GenericApplicationContext context = new GenericApplicationContext();
//2、调用context的方法对象注册
context.refresh();
context.registerBean("user1", User.class,() -> new User());
//3、获取在spring注册的对象
User user = (User) context.getBean("com.dong.User"); //User对象
User user = (User) context.getBean("user1");
System.out.println(user);
}
4、Spring5支持整合JUnit5
(1)整合JUnit4
第一步:引入Spring相关针对测试依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
第二步:创建测试类,使用注解方式完成
@RunWith(SpringJUnit4ClassRunner.class) //单元测试框架
@ContextConfiguration("classpath:applicationContext.xml") //加载配置文件
public class Testa {
@Autowired
private UserService userService;
@Test
public void test1(){
userService.accountMoney();
}
}
(2)Spring5整合JUnit5
第一步:引入JUnit5的依赖
第二步:创建测试类,使用注解完成
@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath:applicationContext.xml")
//@SpringJUnitConfig(locations="classpath:applicationContext.xml") //使用复合注解替代上面两个注解完成整合
public class Testa {
@Autowired
private UserService userService;
@Test
public void test1(){
userService.accountMoney();
}
}
Spring5框架新功能(Webflux)
1、SpringWebflux介绍
(1)是Spring5添加新的模块,用于web开发的,功能和SpringMVC类似的,Webflux使用当前一种比较流行响应式编程出现的框架
(2)使用传统web框架,比如SpringMVC,这些基于Servlet容器,Webflux是一种异步非阻塞的框架,
异步非阻塞的框架在Servlet 3.1 以后才支持,核心是基于Reactor的相关API实现的
(3)解释什么是异步非阻塞
- 异步与同步 非阻塞与阻塞 都是针对对对象不一样
- 异步和同步针对调用者,调用者发送请求,如果等着对方回应之后才去做其他事情就是同步,如果发送请求之后不等着对方回应就去做其他事情就是异步
- 阻塞和非阻塞针对被调用者,被调用者收到请求之后,做完请求任务之后才给出反馈就是阻塞,收到请求之后马上给出反馈然后再去做事情就是非阻塞。
(4)Webflux特点
- 第一 :非阻塞式在有限资源下,提高系统吞吐量和伸缩性,以Reactor为基础实现响应式编程
- 第二 :函数式编程 Spring5框架基于Java8,Webflux使用Java8函数式编程方式实现路由请求
(5)SpringMVC和Webflux的区别
- 第一 :两个框架都可以使用注解方式,都运行在Tomcat等容器中
- 第二 :SpringMVC采用命令式编程,Webflux采用异步响应式编程
2、响应式编程
(1)什么是响应式编程
- 响应式编程是一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。
- 电子表格程序就是响应式编程的一个例子。单元格可以包含字面值或类似"=B1+C1"的公式,而包含公式的单元格的值会依据其他单元格的值的变化而变化。
(2)Java8及其之前版本
-
提供的观察者模式两个类Observer和Observable
package com.dong.demoreactory.reactor8; import java.util.Observable; public class ObserverDemo extends Observable { public static void main(String[] args) { ObserverDemo observer = new ObserverDemo(); //添加观察者 observer.addObserver((o,arg)->{ System.out.println("发生改变"); }); observer.addObserver((o,arg)->{ System.out.println("被观察者通知,准备改变"); }); observer.setChanged(); //数据变化 observer.notifyObservers(); //通知 } }
基本配置依赖
<!-- 1.Spring核心依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- 2.Spring dao依赖-->
<!-- spring-jdbc包括了一些如jdbcTemplate的工具类-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- 3.Spring web依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- 4.Spring test依赖:方便做单元测试和集成测试 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
spring整合mybatis
1、导入相关依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
<!--mybatis-spring-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
<!--jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
2、创建database.properties文件
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/security?serverTimezone=GMT-8&useUnicode=true&characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
3、配置mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--配置别名-->
<typeAliases>
<package name="com.dong.pojo"/>
</typeAliases>
</configuration>
4、配置ApplicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--扫描service包中注解-->
<context:component-scan base-package="com.dong.service"/>
<!--1、关联数据链接文件-->
<context:property-placeholder location="classpath:database.properties"/>
<!--2、创建数据源-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--3、配置SqlSessionFactory对象-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--注入数据库连接池-->
<property name="dataSource" ref="dataSource"/>
<!--配置MyBaties全局配置文件:mybatis-config.xml-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!--4、配置扫描Dao接口包,动态实现Dao接口注入到spring容器中-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--注入sqlSessionFactory-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!--需要扫描dao接口包-->
<property name="basePackage" value="com.dong.mapper"/>
</bean>
</beans>
MapperScannerConfigurer 的作用
- MapperFactoryBean的出现为了代替手工使用SqlSessionDaoSupport或SqlSessionTemplate编写数据访问对象(DAO)的代码,使用动态代理实现。
- 不需要去手动注册Bean访问mapper层,也不需要扫描mapper层和注解