一、前置知识的介绍
1.Spring
轻量级的 DI / IoC 和 AOP 容器的开源框架
容器的开源框架网址:https://spring.io/projects/spring-framework
作用:可简化管理创建和组装对象之间的依赖关系
将controller----->service------->dao层的依赖配置使用Spring注解来实现自动注入。
2.Spring IOC
Inverse of Control(控制反转)是一种设计思想 将程序中手动创建对象的流程,交由Spring框架来管理,即把创建对象的控制权反转给Spring框架,由Spring统一管理。把spring ioc 当成一个容器,里面存储管理的对象称为Bean
3.DI
Dependency Injection ,依赖注入,动态地将对象某种依赖关系注入到对象之中.
4.Bean属性scope
singleton:单例, 默认值,调用getBean方法返回是同一个对象,spring的IOC容器中只会存在一个该bean。
prototype: 多例,调用getBean方法创建不同的对象,会频繁的创建和销毁对象造成很大的开销。
5.AOP
Aspect Oriented Program 面向切面编程,在不改变原有逻辑上增加额外的功能。
把功能分两个部分,核心关注点(业务的主要功能)与横切关注点(非核心、额外增加的功能)
通知 Advice:在特定的切入点上执行的增强处理;类型包括@Before前置通知-在执行目标方法之前运行,@After后置通知、@AfterReturning返回通知-在目标方法正常返回值后运行、@AfterThrowing异常通知-在目标方法出现异常后运行、@Around环绕通知-在目标方法完成前、后做增强处理 。
连接点 JointPoint:业务流程在运行过程中需要插入切面的具体位置
切入点 Pointcut:通过特定的规则来筛选连接点, 就是Pointcut,选中那几个你想要的方法
切面 Aspect:定义了切入点+通知的一个类 。
目标 target:目标类,真正的业务逻辑。
织入 Weaving:把切面(某个类)应用到目标函数的过程称为织入。
AOP代理:对AOP框架创建对象的加强,主要有JDK动态代理与CGLIB代理
//目标类 VideoOrderService; 里面每个方法都是连接点(addOrder,findOrderById,delOrder,updateOder);
//切入点是CUD类型的方法,R读取的不作为切入点 ,CRDU全称:增加(Create)、读取查询(Retrieve)、更新(Update)和删除(Delete)
//目标类
VideoOrderService{
//新增订单
addOrder(){ }
//查询订单
findOrderById(){}
//删除订单
delOrder(){}
//更新订单
updateOrder(){} }
//权限切面类 = 切入点+通知
PermissionAspects{
//切入点 定义了什么地方
@Pointcut("execution(public int net.xdclass.sp.service.VideoOrderService.*(..))")
public void pointCut(){}
//before 通知 表示在目标方法执行前切入, 并指定在哪个方法前切入
//什么时候,做什么事情
@Before("pointCut()") public void permissionCheck(){
System.out.println("在 xxx 之前执行权限校验"); } .... }
//日志切面类 = 切入点+通知 LogAspect{
//切入点 定义了什么地方 @Pointcut("execution(public int net.xdclass.sp.service.VideoOrderService.*(..))")
public void pointCut(){}
//after 通知 表示在目标方法执行后切入, 并指定在哪个方法前切入
//什么时候,做什么事情
@After("pointCut()") public void logStart(){
System.out.println("在 xxx 之后记录日志"); } .... }
6.切入点表达式
格式
execution(访问修饰符 返回值类型 包和类 方法
7.代理
创建代理对象来控制对原对象,通过代理类这中间一层,能有效控制对委托类对象的直接访问
静态代理-由程序创建或特定工具自动生成源代码;
动态代理-在程序运行时,运用反射机制动态创建而成,主要有JDK动态代理与CGLIB代理。
二、搭建项目
1.快速上手搭建
创建maven项目
添加maven依赖可参照网站:https://mvnrepository.com/
在pom.xml中添加依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
开发实体层(domain)
package net.xdclass.sp.domain;
public class Video {
private int id;
private String title;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
创建配置文件
applicationContext.xml:添加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 name="video" class="net.xdclass.sp.domain.Video" scope="prototype">
<property name="name" value="tom"/>
<property name="id" value="23"/>
</bean>
</beans>
开发启动类
获取bean,调用对象中的方法
package net.xdclass.sp;
import net.xdclass.sp.domain.Video;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String [] args){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Video video = (Video)applicationContext.getBean("video");
System.out.println(video.getTitle());
}
}
三、spring的使用介绍
1.使用xml配置
Bean对象的常见注入方式
作用范围通过scope来指定,singleton-单例, 默认值;prototype:-多例
使用set方法注入
<bean id="video" class="net.xdclass.sp.domain.Video" scope="singleton">
<property name="id" value="9"/>
<property name="title" value="Spring 5.X课程" />
</bean>
使用带参的构造函数注入
<bean id="video" class="net.xdclass.sp.domain.Video" >
<constructor-arg name="title" value="面试专题课程第一季"></constructor-arg>
</bean>
POJO类型注入(property 没有使用value属性,而是使用了ref属性)
<bean id="video" class="net.xdclass.sp.domain.Video" >
<constructor-arg name="title" value="面试专题课程第一季"></constructor-arg>
</bean>
<bean id="videoOrder" class="net.xdclass.sp.domain.VideoOrder" >
<property name="id" value="8" />
<property name="outTradeNo" value="23432fnfwedwefqwef2"/>
<property name="video" ref="video"/>
</bean>
list类型与Map类型的注入
<bean id="video" class="net.xdclass.sp.domain.Video" >
<!--list类型注入-->
<property name="chapterList">
<list>
<value>第一章SpringBoot</value>
<value>第二章Mybatis</value>
<value>第三章Spring</value>
</list>
</property>
<property name="videoMap">
<map>
<entry key="1" value="SpringCloud课程"></entry>
<entry key="2" value="面试课程"></entry>
<entry key="3" value="javaweb课程"></entry>
</map>
</property>
</bean>
在实体类中添加返回方法
public class Video {
private int id;
private String title;
private List<String> chapterList;
private Map<Integer,String> videoMap;
//省略set get方法
}
优化配置
两个类之间大多数的属性都相同,可通过parent标签来避免重复配置
<bean id="video" class="net.xdclass.sp.domain.Video" scope="singleton">
<property name="id" value="9"/>
<property name="title" value="Spring 5.X课程" />
</bean>
<bean id="video2" class="net.xdclass.sp.domain.Video2" scope="singleton" parent="video">
<!--只需要配置不同的属性即可-->
<property name="summary" value="这个是summary"></property>
</bean>
两个类之间存在属性依赖,可通过depend-on实现实例化的顺序
<bean id="video" class="net.xdclass.sp.domain.Video" scope="singleton">
<property name="id" value="9"/>
<property name="title" value="Spring 5.X课程" />
</bean>
<!--设置两个bean的关系,video要先于videoOrder实例化-->
<bean id="videoOrder" class="net.xdclass.sp.domain.VideoOrder" depends-on="video">
<property name="id" value="8" />
<property name="outTradeNo" value="23432fnfwedwefqwef2"/>
<property name="video" ref="video"/>
</bean>
Bean生命周期
通过init-method与destroy-method来指定
<bean id="video" class="net.xdclass.sp.domain.Video" scope="singleton" init-method="init" destroy-method="destroy">
自动装配属性autowire
可为一个 bean 定义指定自动装配模式,可设置的值有no-不开启、byName-据id注入对应属性、byType-据类型注入属性、constructor-据构造函数注入属性。
<bean id="videoOrder" class="net.xdclass.sp.domain.VideoOrder" autowire="byName">
2.使用注解配置
开启注解的配置
package net.xdclass.sp;
import net.xdclass.sp.aop.AnnotationAppConfig;
import net.xdclass.sp.domain.Video;
import net.xdclass.sp.domain.VideoOrder;
import net.xdclass.sp.service.VideoService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class App {
public static void main(String[] args) {
//1.加载注解配置类
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AnnotationAppConfig.class);
//2.通过@Component获取bean
VideoService videoService = (VideoService) context.getBean("videoService");
//3.调用Bean对象的业务方法
videoService.findById(2);
}
}
- 配置Bean对象
通过@Component("Bean对象名") 通用组件 细分: @Controller (用于web层) @Service (用于service层) @Repository (用于dao仓库层)
domain层
package net.xdclass.sp.domain;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.List;
import java.util.Map;
@Component
public class Video {
private int id;
private String title;
public void init(){
System.out.println("video类 init 方法被调用");
}
public void destroy(){
System.out.println("video类 destroy 方法被调用");
}
public Video(){
//System.out.println("video 空构造函数被调用");
}
public Video(String title){
//System.out.println("video 带参数构造函数被调用");
this.title = title;
}
public int getId() {
return id;
}
public void setId(int id) {
//System.out.println("Video setId方法被调用");
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
//System.out.println("Video setTitle方法被调用");
this.title = title;
}
}
controller层:未指定时,默认为方法名 + 第一个字母小写 作为bean的名称
package net.xdclass.sp.controller;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
@Controller
public class VideoController {
}
service层
package net.xdclass.sp.service;
import net.xdclass.sp.config.CustomConfig;
import net.xdclass.sp.dao.VideoDao;
import net.xdclass.sp.domain.Video;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
//@Component("videoService")
@Service("videoService")
public class VideoServiceImpl implements VideoService {
@Autowired//实现Bean对象的注入
private VideoDao videoDao;
@Autowired
private CustomConfig customConfig;
public int save(Video video) {
System.out.println("保存video");
return 1;
}
public Video findById(int id) {
System.out.println("根据id找视频");
videoDao.test();
System.out.println(customConfig.getHost());
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new Video();
}
}
dao层
package net.xdclass.sp.dao;
import org.springframework.stereotype.Repository;
@Repository("videoDao")
public class VideoDao {
public void test(){
System.out.println("video Dao test ");
}
}
- 注入Bean对象
类型注入@Autowired;名称注入@Qualifier
bean生命周期
@PostConstruct初始化、@PreDestroy销毁
bean作用范围
@scope注解,singleton-单例, 默认值;prototype:-多例
package net.xdclass.sp.domain;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.List;
import java.util.Map;
@Component
//@Scope("prototype")
@Scope
public class Video {
private int id;
private String title;
@PostConstruct
public void init(){
System.out.println("video类 init 方法被调用");
}
@PreDestroy
public void destroy(){
System.out.println("video类 destroy 方法被调用");
}
}
定义第三方bean
@Configuration标注在类为spring容器(相当于类在spring的xml配置文件中的配置)
@bean标注方法为一个Bean对象,将Bean对象交给Spring管理,Spring将Bean对象放入IOC容器中。
注意:bean都需要在@Configuration注解下进行创建
package net.xdclass.sp.config;
import net.xdclass.sp.domain.VideoOrder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
@Configuration
public class AppConfig {
//使用@bean注解,表明这个bean交个spring 进行管理
// 如果没有指定名称,默认采用 方法名 + 第一个字母小写 作为bean的名称
@Bean(name = "videoOrderName",initMethod = "init",destroyMethod = "destroy")
@Scope
public VideoOrder videoOrder(){
return new VideoOrder();
}
}
自动映射配置文件
@PropertySource,指定加载配置文件,实现将配置文件映射到实体类;
@Value映射到具体的java属性
创建配置文件config.properties
server.host=127.0.0.1
server.port=999
映射到实体类中
package net.xdclass.sp.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration//1.指定这个类是一个配置类
@PropertySource(value = {"classpath:config.properties"})//2.指定配置文件
public class CustomConfig {
@Value("${server.host}")//3.注入配置文件中的属性值
private String host;
@Value("${server.port}")
private int port;
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
}
四、事务管理
1.概念
多个操作,要么同时成功,要么失败后一起回滚。包括A(Atomic-原子性)C(Consistency-一致性)I(Isolation-隔离性)D(Durability-持久性)四种特性.
2.方法
beginTransaction()、commit()、rollback()
3.事务传播
在开始当前事务之前,一个事务上下文已经存在,实现指定一个事务性方法的执行行为
4.事务隔离
是指若干个并发的事务之间的隔离程度