Spring
安装与应用
安装
直接下载https://repo.spring.io/release/org/springframework/spring/,点击我们想要下载的版本,进去之后下载第一个dist.zip
详细下载步骤:
首先我们要进入spring.io界面,然后找到spring Framework,然后点击右上角的GitHub,之后我们进入页面下滑到Access To Binaries ,那里有个查看spring文件,然后我们点击进去之后,点击小房子下面的文件,然后找到release->org->springframework->spring 点击右边会出现一个链接release/org/springframework/spring/,将这个链接追加到io后面就可以访问到下载页面
应用
我们首先创建一个简单的java类,然后引入jar包,然后加入库,然后创建对象
>package Test; >import Java.hellow; >import org.junit.Test; >import org.springframework.context.ApplicationContext; >import org.springframework.context.support.ClassPathXmlApplicationContext; >public class hellowTest { >@Test >public void Hellow(){ //加载spring配置文件 ApplicationContext context = new ClassPathXmlApplicationContext("xml1.xml"); //获取配置对象文件 hellow hellow = context.getBean("hellow", hellow.class); System.out.println(hellow); hellow.Hello(); >} >} >package Java; >public class hellow { >public void Hello(){ System.out.println("你好spring"); >} >}
IOC
IOC底层原理
- xml配置
- 工厂模式
- 反射
通过这三层,来系统的降低我们的耦合度
IOC接口
- IOC思想基于IOC容器完成的,IOC容器底层就是对象工厂
- spring提供IOC容器实现两种方式(两个接口)
- BeanFactory:IOC基本实现,是spring内部的使用接口,不提供开发人员进行使用(加载配置文件的时候不会创建对象,只有在获取对象的时候才去创建对象)
- ApplicationContext:BeanFactory的子接口,拥有更多更强大的功能,一般由开发人员进行使用(加载配置文件的时候就会将配置文件对象创建出来)
- ApplicationContext接口有实现类
- FileSystemXmlApplicationContext
- ClassPathXmlApplicationContext
IOC中基于xml依赖注入
set方法的注入
public class book{
private String name;
private String author;
public void setName(String name){
this.name=name;
}
public void setAuthor(String author){
this.author=author;
}
}
<Bean id = "book" class="Java.book">
<properties name="name" value="123"></properties>
<properties name="author" value="456"></properties>
</Bean>
public class test{
//加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("book.xml");
//获取配置对象
Book book = context.getBean("book",Book.class);
}
构造方法的注入
默认的是无参构造,所以我们需要用构造器重新构造这个对象
<bean id="book" class="Java.book">
<constructor-arg name="name" value="123"></constructor-arg>
<constructor-arg name="author" value="456"></constructor-arg>
</bean>
特殊字符的注入
<bean id="book" class="Java.book">
<property name="author">
<null></null>
</property>
</bean>
<bean id="book" class="Java.book">
<property name="author">
<value>
<![CDATA[<<南京>>]]]]>
</value>
</property>
</bean>s
对象的注入
package dao;
public class Userimpl implements User{
@Override
public void add() {
System.out.println("add...........");
}
}
package service;
public class UserserviceImpl implements Userservice {
private User user;
public void setUser(User user) {
this.user = user;
}
@Override
public void update() {
System.out.println("update...........");
user.add();
}
}
<bean id="Userimpl" class="dao.Userimpl"></bean>
<bean id="UserserviceImpl" class="service.UserserviceImpl">
<property name="user" ref="Userimpl"></property>
</bean>
</beans>
//这里的name是我们在类中创建的名字
//这里的ref是我们bean标签的id值
级联属性的设置
emp
package Java;
public class emp {
private String ename;
private Dept dept;
public void setEname(String ename) {
this.ename = ename;
}
public void setDept(Dept dept) {
this.dept = dept;
}
public Dept getDept() {
return dept;
}
public void sout(){
System.out.println(ename+" "+dept);
}
}
Dept
package Java;
public class Dept {
private String dname;
public void setDname(String dname) {
this.dname = dname;
}
@Override
public String toString() {
return "Dept{" +
"dname='" + dname + '\'' +
'}';
}
}
Test
public class DeptTest {
@Test
public void Test(){
ApplicationContext context = new ClassPathXmlApplicationContext("xml3.xml");
emp emp = context.getBean("emp", emp.class);
emp.sout();
}
<bean id="dept" class="Java.Dept">
<property name="dname" value="财务部"></property>
</bean>
<bean id="emp" class="Java.emp">
<!--普通属性设置-->
<property name="ename" value="123"></property>
<!--对象属性设置-->
<property name="dept" ref="dept"></property>
<!-- <property name="dept">-->
<!-- <bean id="dept2" class="Java.Dept">-->
<!-- <property name="dname" value="456"></property>-->
<!-- </bean>-->
<!-- </property>-->
//这里要使用dept.dname必须要求有get方法
<!-- <property name="dept.dname" ref="dept"></property>-->
</bean>
数组、集合、map、set属性的注入
package Java;
import java.sql.Array;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class array {
private String [] course;
private List<String> list;
private Map<String,String> map;
private Set<String> set;
public void setCourse(String[] course) {
this.course = course;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public void setSet(Set<String> set) {
this.set = set;
}
public void sout(){
System.out.println(Arrays.toString(course));
System.out.println(list);
System.out.println(map);
System.out.println(set);
}
}
public class arrayTest {
@Test
public void Test(){
ApplicationContext context = new ClassPathXmlApplicationContext("xml4.xml");
array array = context.getBean("array", array.class);
array.sout();
}
<bean id="array" class="Java.array">
<property name="course">
<array>
<value>123</value>
<value>456</value>
</array>
</property>
<property name="list">
<list>
<value>list</value>
<value>list</value>
</list>
</property>
<property name="map">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="PHP" value="php"></entry>
</map>
</property>
<property name="set">
<set>
<value>set</value>
<value>abc</value>
</set>
</property>
</bean>
基于XML的自动装配
<!--基于XML的自动装配注入-->
<!--XML有两种自动装配注入的方法
第一种:通过名称注入 ByName
第二种:通过类型注入 ByType
-->
<bean id="dept" class="Java.Dept"></bean>
<bean id="emp" class="Java.Dept" autowire="byName"></bean>
<bean id="emp" class="Java.Dept" autowire="byType"></bean>
IOC中基于注解的注入
四种注解方式:
- @Component(一般用于bean)
- @Service(一般用于Service层)
- @Controller(一般用于web层)
- @Repository(一般用于dao层)
使用注解的方式:
对象的创建:
1.首先需要引入aop的jar包
2.然后需要在xml文件中添加:
xmlns:context="http://www.springframework.org/schema/context" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
3.然后进行配置
<!--基于注解的配置--> <context:component-scan base-package="service"></context:component-scan>
4.配置完之后,我们需要在相应的类上面添加@注解名称(在注解中,value值默认的是我们类名,首字母小写)
5.运行
属性的注入:
- @Autowired:根据类型进行注入
- @Qualifier:根据名称进行注入
- @Resource:可以类型注入,可以属性注入
- @Value:普通注入
1.首先需要在两个类上面都添加对象创建的注解
2.然后再service中创建dao对象,不需要set方法
3.然后在dao对象上面添加属性注入的注解(
使用@Autowired直接在属性上写
使用Qualifier这个注解,需要和@Autowired一起使用
使用Resource,直接添加到属性上就是根据类型注入,如果加上name属性就是根据名称进行注入
使用Value这个注解,在普通属性上添加,并且设置value值就是它的值)
4.(要注意我们的xml文件的配置中,一定要将我们需要自动装备的包都添加进去)
基于java类的自动装配
@Configuration//作为配置类,替代xml配置文件
@ComponentScan(basePackages = "Java")//路径
public class Config {
}
普通bean和工厂bean的区别
普通bean返回的类型只能是我们定义的类型
工厂bean返回的可以不是我们定义的类型
IOC的生命周期
- 执行无参构造,创建bean的实例
- 调用set方法设置属性值
- 在初始化之前执行的方法
- 执行初始化的方法
- 在初始化之后执行的方法
- 获取创建bean的实例对象
- 执行销毁方法
AOP
概念:不通过修改源码的方式,在主干功能里面添加新的功能
底层原理:使用动态代理
有接口的情况下:创建接口实现类的代理对象,增强类的方法
没有接口的情况下:创建子类的代理对象,增强类的方法
AOP术语:
连接点:类里面那些方法被增强了
切入点:实际被增强的方法
通知(增强):实际被增强的逻辑部分成为通知
1. 前置通知 2. 后置通知 3. 环绕通知 4. 异常通知 5. 最终通知
- 切面:动作,把通知应用到切入点的过程
AOP准备操作:
1. Spring框架一般都是基于AspectJ实现AOP操作的
1. AspectJ不是spring的组成部分,是独立的框架
- 基于AspectJ实现AOP操作
- 基于xml配置文件
- 基于注解方式
- 在项目中引入相关jar包
- springsource.net.sf.cglib
- springsource.org.aopalliance
- springsource..org.aspectj.weaver
- aspectj.release
- 切入点表达式
- 作用:知道对哪个类里面的哪个方法进行增强
- 语法结构:execution(权限修饰符、返回类型、类全路径、方法名称(参数列表))
- 例:execution(* com.dao.add.*)
AOP操作:
基于注解方式开发
创建类:
@Component public class Userimpl { public void add() { System.out.println("add..........."); } }
创建增强类
@Component @Aspect public class UserProxy { //增强类 @Before("execution(* dao.Userimpl.add())") public void before(){ System.out.println("before/........"); } public void after(){ System.out.println("before/........"); } }
创建配置文件
<?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: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"> <!--开启自动扫描 --> <context:component-scan base-package="dao"></context:component-scan> <!--生成AspectJ对象 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
配置不同类型的通知
//增强类 //调用前 @Before("execution(* AspeectJ.User1.add())") public void before(){ System.out.println("before/........"); } //调用后 @After("execution(* AspeectJ.User1.add())") public void after(){ System.out.println("after/........"); } //返回值时 @AfterReturning("execution(* AspeectJ.User1.add())") public void AfterReturning(){ System.out.println("AfterReturning/........"); } //抛异常时 @AfterThrowing("execution(* AspeectJ.User1.add())") public void AfterThrowing(){ System.out.println("AfterThrowing/........"); } //环绕 @Around("execution(* AspeectJ.User1.add())") public void Around(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("环绕前/........"); joinPoint.proceed(); System.out.println("环绕后/........"); }
方法抽取
//公共抽取 @Pointcut(value = "execution(* AspeectJ.User1.add())") public void Pointdemo(){ } @Before(value = "Pointdemo()") public void before(){ System.out.println("before/........"); } //这里报错了,可能是因为jar包版本的错误,也可能是jdk版本的错误
设置优先级
在增强方法的类上面添加@Order(数字值越小,优先级越高)
基于xml配置文件开发
首先创建两个类,一个普通类,一个增强类
然后再写配置文件
<!-- 配置类--> <bean id="user1" class="AspeectJ.User1"></bean> <bean id="userproxy" class="AspeectJ.UserProxy"></bean> <!--aop配置--> <aop:config> <!-- 配置切入点--> <aop:pointcut id="p" expression="execution(* AspeectJ.User1.add())"/> <!-- 配置切面--> <aop:aspect id="proxy" ref="userproxy"> <aop:before method="before" pointcut-ref="p"></aop:before> </aop:aspect> </aop:config>
完全开发,没有配置文件的开发
需要添加一个aop操作的类文件
package AspeectJ; @Configuration//变成配置类文件 @ComponentScan(basePackages = "AspeectJ")//组件扫描 @EnableAspectJAutoProxy(proxyTargetClass = true) public class AspectJConfig { }
JDBCTemplate
概念:JDBCTemplate是spring对JDBC的封装,使用JDBCTemplate对数据库进行操作
准备工作:
引入相关依赖
. druid-1.0.9.jar
2. mysql-connector-java-5.1.6.jar 3. spring-jdbc-5.2.9.RELEASE.jar 4. spring-tx-5.2.9.RELEASE.jar 5. spring-orm-5.2.9.RELEASE.jar 2. 配置数据库连接池
<bean id="datasource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="url" value="jdbc:mysql:///user_db"></property> <property name="username" value="root"></property> <property name="password" value="root"></property> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> </bean>
3. 配置jdbc对象,注入DataSource
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <!-- 注入DataSource--> <property name="dataSource" ref="datasource"></property> </bean>
4. 装配实现的dao以及service层
<!--配置自动装配--> <context:component-scan base-package="service,dao"></context:component-scan>
总结:这里因为我的MySQL版本和驱动版本问题,不能进行数据库连接,无法进行下面的课程学习代码,但是JDBCTemplate在javaweb中都用过,所以这些都是复习性的过一遍
事务
什么是事务:事务是数据库操作的最基本单元,逻辑上一组操作,要么都成功,要么都失败
事务的四个特性(ACID)
- 原子性:操作过程不可分割,要么都成功,要么都失败
- 一致性:操作前和操作后总量是不变的
- 隔离性:多事务操作之间不会产生影响
- 持久性:提交数据后,会进行保存
事务操作
配置事务管理器
//加入tx命名空间 xmlns:tx="http://www.springframework.org/schema/tx" http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd //创建事务操作 <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--注入DataSource--> <property name="dataSource" ref="datasource"></property> </bean> //开启事务注解 <tx:annotation-driven transaction-manager="dataSourceTransactionManager"></tx:annotation-driven>
在类上或者方法上加注解@Transaction
事务管理参数配置
- 事务传播行为:7种
- REQUIRED:如果一个方法本身有事务,在方法里调用另一个方法,那么就都使用这个事务
- REQUIRED_NEW:一个方法调用另一个方法,不管有没有事务,都会创建一个新的事务
- 操作:@Transaction(propagation = propagation.REQUIRED
- 事务隔离性:
- 存在问题:脏读、不可重复读、虚读
- 脏读:一个未提交的事务读取到另一个未提交的事务
- 不可重复读:一个未提交的事务读取到另一个提交的事务
- 虚读:一个未提交的事务读取到另一个提交的添加事务
- 解决:通过隔离级别解决
- read uncommited:读未提交
- read commited:读已提交
- repeatable read:可重复读
- serializable:串行化
- 设置方式:@Transaction(isolation = isolation .serializable)
- 存在问题:脏读、不可重复读、虚读
- 超时时间:timeout
- 事务需要在一定的时间内提交,如果不提交则回滚
- 默认值是-1,设置时间以秒为单位进行计算
- readOnly:是否只读
- 默认设置为false
- 设置为只读,就不能进行增删改操作
- rollbackFor:回滚
- 设置出现哪些异常进行事务回滚
- morollbackFor:不回滚
- 设置哪些事务不回滚
- 事务传播行为:7种
spring5框架新功能
spring框架代码基于java8,运行时兼容jdk9,许多不建议使用的类和方法在代码库中删除
spring5框架自带了通用的日志封装
- 移除了log4j
- 整合了log4j2
- 使用:
- 引入jar包:
- log4j-api
- log4j-core
- log4j-slf4j
- slf4j-api
- 写xml配置文件
- 引入jar包:
spring5框架核心容器支持@Nullable注解:
@Nullable注解可以使用在方法、属性、参数上面,表示它们的返回值可以为空
spring5支持整合JUnit5
整合JUnit4
第一步引入spring-test依赖
创建测试类,使用注解方法
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:bean.xml")
整合JUnit5
第一步引入JUnit5的jar包
第二步创建测试类,使用注解完成
@ExtendWith(SpringExtension.calss) @ContextConfiguration("calsspath:bean.xml") //改进之后 @SpringJUnitConfig(locations="classpath:bean.xml")
Spring5框架新功能:WebFlux
- springwenflux介绍
- 是spring5添加新的模块,用于web开发,功能和springMVC类似的,webflux适用当前一种比较流程响应式编程出现的框架
- 使用传统web框架,比如springMVC,这些基于servlet容器,webflux是一种一步非阻塞的框架,一步非阻塞的框架在servlet3.1以后才支持,核心是基于Reactor的相关API实现的
- 解释什么是异步非阻塞
- 异步和同步针对调用者:调用者发送请求,如果等着对方回应之后才去做其他事情就是同步,如果发送请求之后不等着对方回应就去做其他事情就是异步
- 阻塞和非阻塞对被调用者:被调用者收到请求之后,做完请求任务之后才给出反馈就是阻塞,受到请求之后马上给出反馈然后再去做事情就是非阻塞
- Webflux特点:
- 非阻塞式:在有限的资源下,提高系统吞吐量和伸缩性,以reactor为基础实现响应式编程
- 函数式编程:spring5框架基于java8,webflux使用java8函数式编程方式实现路由请求
- 比较Springmvc
- 两个框架都可以使用注解方式,都运行在Tomcat等容器中
- SpringMVC采用命令式编程,Webflux采用异步响应式编程
- 响应式编程(Reactor实现)
- 响应式编程操作中,Reactor是满足Reactive规范框架
- Reactor有两个核心类,Mono和Flux,这两个类实现接口publiser,提供丰富操作符。flux对象实现发布者,返回N和元素;Mono实现发布者,返回0或者1个元素
- flux和Mono都是数据流的发布者,使用Flux和Mono都可以发出三种数据信号:元素值、错误信号、成功信号,错误信号和完成信号都代表终止信号,终止信号用于告诉订阅者数据流结束了,错误信号终止数据流同时吧错误信息传递给订阅者
- 三种信号特点:
- 错误信号和完成信号都是终止信号,不能共存
- 如果没有发送任何元素值,而是直接发送错误或者完成信号,表示空数据流
- 如果没有错误信号,没有完成信号,表示是无线数据流
- 调用just或者其他方法只是声明了数据流,数据流并不会发出,只有订阅了才会发出,不订阅什么都不会发生
- 操作符
- map:将元素映射成新元素
- flatMap:将元素映射成流
- 将每个元素映射成流,然后将流都合并成一个大流
- springwebflux执行流程和核心api
- springwebflux基于reactor,默认使用容器是Netty,Netty是高性能NIO框架,异步非阻塞框架
- 阻塞和非阻塞
- BIO:阻塞
- NIO:非阻塞
- springwebflux执行过程和springMVC相似的
- springwebflux核心控制器DispatchHandler,实现接口webHandler
- 接口WebHandler有一个方法
- springwebflux里面DispatcherHandler,负责请求的处理:
- HandlerMapping:请求查询到处理的方法
- HandlerAdapter:真正负责请求的处理
- HandlerResultHandler:响应处理结果
- springwebflux实现函数式变成,两个接口:RouterFunction(路由处理)和HandlerFunction(处理函数)