1.Spring框架的概述
1.概述
- Spring框架是一个轻量级开源的javaEE开发框架
- Spring解决企业应用开发的复杂性
- Spring两个核心IOC和AOP
- IOC:控制反转,把创建对象交给Spring管理
- AOP:面向切面编程,不修改源代码的情况下进行功能增强
- Spring特点:
- 方便解耦
- aop支持
- 方便测试
- 方便集成框架
- 降低java API使用难度
- 方便进行事务处理
2.IOC容器
1.入门案例
1.创建maven项目
2.添加依赖
<dependencies>
<!-- 1. Spring IOC依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
</dependencies>
3.创建对象
package com.xjggb.demo;
public class HelloSpring {
public void show(){
System.out.println("来了老弟");
}
}
4.编写配置文件
<?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">
<!--创建bean-->
<bean id="helloSpring" class="com.xjggb.demo.HelloSpring"></bean>
</beans>
5.编写测试类
package com.xjggb;
import com.xjggb.demo.HelloSpring;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class HelloTest {
public static void main(String[] args) {
//加载配置文件
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
//获取配置文件对象
HelloSpring helloSpring = context.getBean("helloSpring", HelloSpring.class);
//调用对象方法
helloSpring.show();
}
}
2.ioc
1.IOC容器(IOC:实体类确定好类间的关系, 使用xml文件按照实体类配置对象的各种属性,工厂根据XML文件创建对象。 )
- IOC底层原理
- IOC 接口(BeanFactory)
- IOC操作Bean管理(基于xml)
2.什么是ioc ?
- 控制反转,目的:降低耦合,高内聚低耦合,把对象的创建和对象之间的调用过程,交给Spring进行管理
3.IOC接口
- ioc基于IOC容器完成,ioc容器底层就是对象工厂
- spring提供了IOC容器实现的两种方式:两个接口,一个是BeanFactory:IOC容器基本实现,是spring内部使用接口,不提供开发人员使用。加载配置文件时不会创建对象,使用对象时才会创建对象(懒汉式加载对象)。另一个是ApplicationContext:BeanFatory的子接口,提供更多更强大的功能,一般供开发人员进行使用,加载配置文件时就创建对象(饥汉式加载对象)
- pplicationContext接口实现类
- FileSystemXmlApplicationContext(“盘符路径(绝对路径)”)
- ClassPathXmlApplicationContext(“src目录下类路径”)
- 子接口ConfigurableApplicationContext()扩展功能
4.IOC注入
1.ioc注入两种方式
- 无参构造和有参构造注入,
- set方法注入
1实现构造方法注入
1.创建类,定义属性,创建属性的有参构造
package com.xjggb.entity;
public class Student {
private int num;
private String name;
//无参构造
public Student(){
}
//有参构造
public Student(int num ,String name){
this.num=num;
this.name=name;
}
@Override
public String toString() {
return "Student{" +
"num=" + num +
", name='" + name + '\'' +
'}';
}
}
2.Spring配置文件配置
<!--创建bean-->
<bean id="student" class="com.xjggb.entity.Student">
<!--无参构造注入-->
<constructor-arg name="name" value="行健乖乖霸"></constructor-arg>
<constructor-arg name="num" value="1"></constructor-arg>
<!--或者-->
<!-- <constructor-arg index="0" value="2"></constructor-arg>
<constructor-arg index="1" value="来了老弟"></constructor-arg>-->
</bean>
小结:
有参构造注入:一定要记得写无参构造
2.P命名空间注入
1.在配置文件钟添加p命名空间
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
2.进行属性的注入
<bean id="student" class="com.xjggb.entity.Student" p:num="1" p:name="来了老弟"></bean>
3.测试
public static void show(){
//加载配置文件
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo01.xml");
Student student = context.getBean("student", Student.class);
System.out.println("student = " + student);
}
3.IOC操作Bean管理(xml注入其他类型属性)
1.编写类
package com.xjggb.entity;
public class Book {
private String name;
private String author;
private String address;
public void setName(String name) {
this.name = name;
}
public void setAuthor(String author) {
this.author = author;
}
public void setAddress(String address) {
this.address = address;
}
public void show(){
System.out.println(name+":"+author+":"+address);
}
}
2.编写配置文件(默认也是null)
<bean id="book" class="com.xjggb.entity.Book">
<!-- 注入空值-->
<property name="name">
<null/>
</property>
</bean>
3.属性包含特殊字符( <北京> )
<bean id="book" class="com.xjggb.entity.Book">
<!--方式一-->
<property name="name" value="<北京 <"></property>
<!--方式二-->
<property name="address">
<value><![CDATA[<北京>]]]></value>
</property>
</bean>
4.测试
public static void show1(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo02.xml");
Book book = context.getBean("book", Book.class);
book.show();
}
4.注入外部bean(使用引用,注入其他类的对象)
1.创建两个类service类和dao类
创建接口
public interface Dao {
void add();
}
实现接口
package com.xjggb.dao.impl;
import com.xjggb.dao.Dao;
public class DaoImpl implements Dao {
@Override
public void add() {
System.out.println("\"来了老弟\" = " + "来了老弟");
}
}
编写Userservice
package com.xjggb.service;
import com.xjggb.dao.impl.DaoImpl;
public class UserService {
private DaoImpl dao;
public void setDao(DaoImpl dao) {
this.dao = dao;
}
public void show(){
dao.add();
}
}
2.spring配置文件钟进行配置
<!--创建service-->
<bean id="userService" class="com.xjggb.service.UserService">
<!--注入dao对象-->
<property name="dao" ref="dao"/>
</bean>
<!--创建dao实现类-->
<bean id="dao" class="com.xjggb.dao.impl.DaoImpl"></bean>
3.测试
//注入对象
public static void show3(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo03.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.show();
}
5.注入集合
- 注入数组类型
- 注入LIst集合
- 注入Map集合
1.创建类
package com.xjggb.entity;
import org.springframework.scheduling.concurrent.ScheduledExecutorTask;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Student {
//数组类型
private String[] course;
//注入List类型
private List<String> list;
//map类型
private Map<String,String> map;
//set类型
private Set<String> sets;
public void setSets(Set<String> sets) {
this.sets = sets;
}
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;
}
@Override
public String toString() {
return "Student{" +
"course=" + Arrays.toString(course) +
", list=" + list +
", map=" + map +
", sets=" + sets +
'}';
}
}
2.编写配置文件
<bean id="student" class="com.xjggb.entity.Student">
<!--注入数组-->
<property name="course" >
<array>
<value>c</value>
<value>c++</value>
<value>java</value>
<value>python</value>
</array>
</property>
<!--注入map-->
<property name="map">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="PHP" value="php"></entry>
</map>
</property>
<!--注入list-->
<property name="list">
<list>
<value>中山路美食街</value>
<value>建政路小吃街</value>
<value>农院路美食街</value>
<value>南铁美食街</value>
</list>
</property>
<!--注入set-->
<property name="sets">
<set>
<value>张三</value>
<value>李四</value>
<value>王五</value>
<value>马六</value>
</set>
</property>
</bean>
3.测试
//注入集合
public static void show5(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo05.xml");
Student student = context.getBean("student", Student.class);
System.out.println("student = " + student);
}
6.集合里设置对象类型值
1.创建类
package com.xjggb.entity;
public class Course {
private String CourseName;
public void setCourseName(String courseName) {
CourseName = courseName;
}
public String getCourseName() {
return CourseName;
}
}
package com.xjggb.entity;
import org.springframework.scheduling.concurrent.ScheduledExecutorTask;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Student {
private List<Course> courses;
public void setCourses(List<Course> courses) {
this.courses = courses;
}
public List<Course> getCourses() {
return courses;
}
@Override
public String toString() {
return "Student{" +
"courses=" + courses +
'}';
}
}
2.配置文件
<?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">
<bean id="student" class="com.xjggb.entity.Student">
<property name="courses">
<list>
<!--引用外部bean-->
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
</bean>
<bean id="course1" class="com.xjggb.entity.Course">
<property name="courseName" value="来了老弟"></property>
</bean>
<bean id="course2" class="com.xjggb.entity.Course">
<property name="courseName" value="我是行健乖乖霸"></property>
</bean>
</beans>
7.把集合诸如部分提取出来
1.编写配置文件
<!--
1.xml中引入新的命名空间util
2.使用util标签
-->
<util:list id="bookList">
<value>三国演</value>
<value>水浒传</value>
<value>西游记</value>
<value>红楼梦</value>
</util:list>
<bean id="book" class="com.xjggb.entity.Book">
<property name="list" ref="bookList"></property>
</bean>
2.编写类
public class Book {
private List<String> list;
public void setList(List<String> list) {
this.list = list;
}
public List<String> getList() {
return list;
}
}
5.FactoryBean
1.Spring有两种Bean,一种普通Bean,另一种是 工厂Bean
-
普通bean,在配置文件中,定义bean类型就是返回类型
-
工厂bean,在配置文件中定义bean类型可以和返回类型不一样
第一步创建类,让这个类作为工厂Bean,实现接口FactoryBean
第二步实现接口里的方法,在实现方法中定义返回的bean类型。
实现接口类
public class MyBean implements FactoryBean<Course>{
@override
public Course getObject() throws Exceptions{
Course course = new Course();
course.setCourse("java");
return course;
}
@override
public Class<?> getObjectType(){
return NULL;
}
@override
public Boolean isSingleton(){
return false;
}
}
配置文件
//配置类
<bean id = "mybean" class="com.zhh.entity.MyBean"></bean>
测试
//测试类
@test
public void test2(){
ApplicationContext application = new classPathXpthXmlApplicationContext("bean4.xml");
Course course = context.getBean("MyBean",Course.class);
}
6.bean的作用域
-
在spring里,设置创建Bean实例是单实例还是多实例。
-
在spring里,默认设置创建Bean实例是单实例。
-
如何设置单实例还是多实例。
-
spring配置文件bean标签里scope属性用于设置单实例还是多实例。
-
scope属性值:第一个,默认值,singleton,表示单实例对象;第二个值:prototype,表示多实例对象。
-
//配置 <bean id="book" class="com.zhh.entity.Book" scope="prototype"> <property name="list" ref = "booklist"></property> </bean>
第一: singleton表示单实例,prototype表示多实例。
第二: 设置Scope是singleton时,加载spring配置文件时侯就会创建单实例对象; 设置Scope是prototype时,不是加载spring配置文件时侯创建对象,而是在调用getBean方法时创建多实例对象。 request,表示一次请求,每次创建对象放到request域对象中。 session,表示一次会话,每次创建对象放到session域对象中。
-
7.Bean生命周期
1.从对象创建到对象销毁的过程
2.Bean的生命周期
- 通过构造器创建Bean实例(无参构造)
- 为bean的属性设置值和其他的bean的引用(调用set方法)
- 调用bean的初始化方法(需要进行配置初始化的方法)
- bean可以使用(获取到对象)
- 当容器关闭的时候,调用bean的销毁方法(需要进行配置销毁)
1.Bean的生命周期
1.编写实体类
package com.xjggb.demo;
public class Orders {
public Orders(){
System.out.println("第一步,调用无参构造方法");
}
private String order_name;
public void setOrder_name(String order_name) {
this.order_name = order_name;
System.out.println("第二步,调用see方法,设置属性值");
}
//创建初始化方法
public void initMethod(){
System.out.println("第三步执行初始化方法");
}
//创建执行初始化方法
public void destoryMethod(){
System.out.println("第五步:执行销毁方法");
}
}
2.编写配置
<!--配置-->
<bean id="orders" class="com.xjggb.demo.Orders" init-method="initMethod" destroy-method="destoryMethod">
<!--
init-method 调用初始化方法
destroy-method 调用销毁方法
-->
<property name="order_name" value="来了老弟"></property>
</bean>
3.测试
//生命周期
public static void show9(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo09.xml");
Orders orders = context.getBean("orders", Orders.class);
System.out.println("第四步:获取创建Bean实例"+ orders);
//手动销毁
context.close();
}
2.bean后置处理器生命周期7步
- 通过构造器创建Bean实例(无参数构造)
- 为bean的属性设置值和对其他bean的引用(调用set方法)
- 把bean实例传到bean后置处理器的方法
- 调用bean的初始化方法(需要进行配置初始化的方法)
- 把bean实例传到bean后置处理器的方法
- bean可以使用(获取到对象)
- 当容器关闭的时候,调用bean的销毁的方法(需要进行配置销毁的方法)
编写实现类
package com.xjggb.demo;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之前完成");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之后完成");
return bean;
}
}
添加配置
<!--
配置后置处理器,当前配置文件的所有bean都会执行该后置处理器
-->
<bean id="myBeanPost" class="com.xjggb.demo.MyBeanPost"></bean>
8.xml方式自动注入
1.什么是自动装配
- 根据指定的装配规则(属性名或者属性类型)Spring自动装配将匹配的属性值进行注入
2.实体类
package com.xjggb.autowie;
public class Emp {
private Dep dep;
public void setDep(Dep dep) {
this.dep = dep;
}
@Override
public String toString() {
return "Emp{" +
"dep=" + dep +
'}';
}
}
package com.xjggb.autowie;
import javafx.scene.DepthTest;
public class Dep {
private String Dept;
public void setDept(String dept) {
Dept = dept;
}
@Override
public String toString() {
return "Dep{" +
"Dept='" + Dept + '\'' +
'}';
}
}
配置文件
<!--手动装配-->
<!-- <bean id="dep" class="com.xjggb.autowie.Dep">
<property name="dept" value="来了老弟"></property>
</bean>
<bean id="emp" class="com.xjggb.autowie.Emp">
<property name="dep" ref="dep"></property>
</bean>-->
<!--
1.自动装配
2.自动装配autowire属性
byName 根据属性名注入,注入值bean的id值和类属性名称一样
byType只能有一个该类型实例,多个实例会报错
-->
<bean id="dep" class="com.xjggb.autowie.Dep">
<property name="dept" value="来了老弟"></property>
</bean>
<bean id="emp" class="com.xjggb.autowie.Emp" autowire="byName">
</bean>
9.引入外部属性文件(数据库为例)
1.第一种方法
<!--直接配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/day10"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
2.第二钟方法
- properties文件引入到spring配置文件中
- 引入名称空间context
编写jdbc.properties文件引入到spring配置文件中
prop.driverClass = com.mysql.jdbc.Driver
prop.url = jdbc:mysql://localhost:3306/userDataBase
prop.user = root
prop.password = root
引入配置文件
<!--spring配置文件中部进行引入-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClass}"/>
<property name="url" value="${prop.url}"/>
<property name="username" value="${prop.user}"/>
<property name="password" value="${prop.password}"/>
</bean>
10.基于注解方式
格式: @注解名称(属性名=属性值,属性名=属性值)
使用注解:注解作用在类(方法,属性)上
使用目的:简化xml配置
1.创建对象注解(4个)
- @Component 普通用法
- @Service 用于service业务逻辑层
- @Controller 用于web层
- @Repository 用于DAO持久层
上面四个注解功能一样,都可以用来创建bean对象
基于对象注解方式实现对象创建例子
1.编写类
@Controller
public class HelloController {
public void show(){
System.out.println("来了老弟");
}
}
2.编写配置
<!--开启注解扫描-->
<context:component-scan base-package="com.xjggb.controller"></context:component-scan>
3.编写测试
//基于注解实现对象创建
public static void show11(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo12.xml");
HelloController helloController = context.getBean("helloController", HelloController.class);
helloController.show();
}
11.基于注解方式实现属性注入
- @Autowired :根据属性类型进行注入
- @Qualifier :根据名称注入
- @Resource :可以根据类型注入也可以根据名称注入
- @Value:注入普通类型属性
编写类
package com.xjggb.autowie.controller;
import com.xjggb.autowie.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class Hello {
@Autowired
private UserDao userDao;
public void show(){
userDao.add();
}
}
编写接口
package com.xjggb.autowie.dao;
public interface UserDao {
void add();
}
编写实现类
package com.xjggb.autowie.dao.impl;
import com.xjggb.autowie.dao.UserDao;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
@Component
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("来了老弟");
}
}
配置文件
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!--开启注解扫描-->
<context:component-scan base-package="com.xjggb.autowie"></context:component-scan>
</beans>
12.完全注解开发
1.编写配置类
//完全注解开发
@Configuration
//配置类,代替配置文件
@ComponentScan(basePackages = {"com.xjggb.completely"})
public class SpringCongif {
}
2.编写业务类
@Component(value = "user")
public class UseService {
public void show(){
System.out.println("来了老弟");
}
}
3.编写测试
//完全注解配置
public static void show13(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringCongif.class);
UseService useService = context.getBean("user", UseService.class);
useService.show();
}
无接口,使用CGLIB动态代理,创建子类的代理对象,增强类的方法
3.AOP
1.AOP概述
1.AOP:面向切面编程,对业务逻辑的各个部分进行隔离,从而降低耦合,提高代码可用性和开发效率,将日志记录,事务处理,异常处理,性能统计,安全控制等代码从业务逻辑代码中划分出来,改变这些行为的时候不影响业务逻辑代码
也就是说,:在不修改源代码的情况下,在主干功能里面添加新的功能
2.AOP原理
-
有接口,使用JDK动态代理,创建接口实现类的代理对象,增强类的方法
-
JDK动态代理 ,使用Proxy类 java.lang.reflect.Proxy代理类。
-
newProxyInstance(Classloader loader, 类<?>[ ]… interfaaces,InvocationHandler h)
- 三个参数
- 第一个参数 :类加载器
- 第二个参数:增强方法所在的类,这个类实现的接口,支持多个接口
- 第三个参数:实现这个接口 InvocationHandler,创建代理对象,写增强方法
1.编写接口
public interface UserDao {
void add();
}
2.实现类
package com.xjggb.proxy;
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println(" 我是Add方法");
}
}
3.代理方法
package com.xjggb.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;
public class UserDaoProxy implements InvocationHandler {
private Object object;
public UserDaoProxy(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法执行前
System.out.println("方法执行前"+method.getName()+"传递参数"+ Arrays.toString(args));
//被增强的方法执行
Object invoke = method.invoke(object, args);
//方法执行后
System.out.println("方法执行后"+invoke);
return invoke;
}
}
4.测试
package com.xjggb.proxy;
import java.lang.reflect.Proxy;
public class Demo {
public static void main(String[] args) {
UserDaoImpl userDao = new UserDaoImpl();
Object o = Proxy.newProxyInstance(
Demo.class.getClassLoader(),
new Class[]{UserDao.class},
new UserDaoProxy(userDao));
//真实对象调用方法
userDao.add();
System.out.println("o = " + o);
}
}
有接口 使用JDK动态代理
无接口,使用CGLIB动态代理,创建子类的代理对象,增强类的方法
2.AOP术语
- 连接点:类里面可以被增强的方法
- 切入点:实际被增强的方法
- 通知(增强):实际增加的逻辑部分
- 通知有多中类型:前置通知,后置通知,环绕通知,异常通知,最终通知
- 切面:把通知引用到切入点的过程
3.AOP操作
1.spring框架中一般都是基于AspectJ实现AOP操作 AspectJ,本身是单独的框架,不属于Spring组成部分,独立于AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作
2.基于AspectJ实现AOP操作
- 基于xml配置文件
- 基于注解方式实现
4.切入点表达式
- 切入点表达式作用:知道对哪个类的哪个方法进行增强
- 语法结构execution([权限修饰符][返回类型][类全路径]方法名称)
5.操作
1.注解版
1.创建类,类里面定义方法
package com.xjggb.aop;
import org.springframework.stereotype.Component;
@Component
public class User {
public void show(){
System.out.println("add");
}
}
2.增强类
package com.xjggb.aop;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class UserProxy {
//前置通知
@Before("execution(* com.xjggb.aop.User.show(..))")
public void before(){
System.out.println("Before 我是前置通知");
}
//返回通知,有异常不执行
@AfterReturning(value = "execution(* com.xjggb.aop.User.show(..))")
public void afterReturning(){
System.out.println("返回通知");
}
//后置通知,有没有异常都会执行
@After(value = "execution(* com.xjggb.aop.User.show(..))")
public void after(){
System.out.println("我是后置通知");
}
//异常通知
@AfterThrowing(value = "execution(* com.xjggb.aop.User.show(..))")
public void afterThrowing(){
System.out.println("我是异常通知");
}
//环绕通知
// @Around(value = "execution(* com.xjggb.aop.User.show(..))")
public void around(){
System.out.println("我是环绕通知");
}
}
3.测试
@Test
public void show(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("aop.xml");
User user = context.getBean("user", User.class);
user.show();
}
相同接入点抽取
//相同的接入点抽取
@Pointcut(value = "execution(* com.xjggb.aop.User.show(..))")
public void pointcut(){
System.out.println();
}
//前置通知
//使用公共方法
@Before("pointcut()")
public void before(){
System.out.println("Before 我是前置通知");
}
有多个增强类对同一个方法进行增强,设置增强类的优先级,在增强类上面添加@Order(数字类型),数字类型值越小优先级越高,
@Component
@Aspect
@Order(1)
public class UserProxy {
}
2.完全注解版
1.编写配置类
//完全注解开发
@Configuration
//配置类,代替配置文件
@ComponentScan(basePackages = {"com.xjggb.aop"})
@EnableAspectJAutoProxy(proxyTargetClass = true) //开启代理自动创建代理类
public class SpringCongif {
}
2.测试
@Test
public void show(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("aop.xml");
User user = context.getBean("user", User.class);
user.show();
}
3.XML版
1.编写类
package com.xjggb.bookaop;
public class UserBook {
public void show(){
System.out.println("来了老弟");
}
}
2.增强类
package com.xjggb.bookaop;
public class BookProxy {
public void before(){
System.out.println("你好呀");
}
}
3.xml配置
<!--创建对象-->
<bean id="userBook" class="com.xjggb.bookaop.UserBook"></bean>
<bean id="bookProxy" class="com.xjggb.bookaop.BookProxy"></bean>
<!--配置AOP的增强-->
<aop:config>
<!--切入点-->
<aop:pointcut id="p" expression="execution(* com.xjggb.bookaop.UserBook.show(..))"/>
<!--配置切面-->
<aop:aspect ref="bookProxy" >
<aop:before method="before" pointcut-ref="p" ></aop:before>
</aop:aspect>
</aop:config>
4.JdbcTemplate
1.导入依赖
<!-- 2. Spring Jdbc 依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--添加mysql依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
2.添加数据
CREATE TABLE `payment` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`serial` varchar(200) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
-- 添加数据
insert into payment values(1,"来了老弟")
3.创建接口和实现类
package com.xjggb.jdbc.dao;
import com.xjggb.jdbc.entity.Payment;
public interface PaymentDao {
//添加方法
void add(Payment payment);
//删除方法
void delete(int id);
//修改方法
void update(Payment payment);
}
实现类
package com.xjggb.jdbc.dao.impl;
import com.xjggb.jdbc.dao.PaymentDao;
import com.xjggb.jdbc.entity.Payment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class PaymentDaoImpl implements PaymentDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void add(Payment payment) {
String sql="insert into payment values(?,?)";
Object[] args={payment.getId(),payment.getSerial()};
int update = jdbcTemplate.update(sql, args);
System.out.println("update = " + update);
}
@Override
public void delete(int id) {
//编写sql
String sql="DELETE FROM payment WHERE id=?";
jdbcTemplate.update(sql,id);
}
@Override
public void update(Payment payment) {
String sql="update payment set serial =? where id=?";
Object [] args={payment.getSerial(),payment.getId()};
int update = jdbcTemplate.update(sql, args);
System.out.println("update = " + update);
}
}
4.业务层
package com.xjggb.jdbc.service;
import com.xjggb.jdbc.dao.PaymentDao;
import com.xjggb.jdbc.entity.Payment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class PaymentService {
@Autowired
private PaymentDao paymentDao;
//删除数据
public void delete(int id){
paymentDao.delete(id);
}
//添加数据
public void add(Payment payment){
paymentDao.add(payment);
}
//根据id修改数据
public void update(Payment payment){
paymentDao.update(payment);
}
}
5.测试
//jdbc
@Test
public void show4(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("jdbc.xml");
PaymentService paymentService = context.getBean("paymentService", PaymentService.class);
//paymentService.delete(1); 删除
Payment payment = new Payment();
payment.setId(20);
payment.setSerial("你好啊小老弟");
//paymentService.add(payment); 添加元素
// paymentService.update(payment); //修改元素
}
6.返回某个值
- 查询表中有多少条记录,返回某个值
- 使用iJdbcTemplate实现查询返回某个值的代码queryForObject(String sql,Class requiredType )
两个参数一个是sql语句另一个是返回类型的Class
//接口
//返回某个值
Integer selectCount();
//实现类
//查询某个返回值
public Integer selectCount(){
String sql="select count(*) from payment";
Integer integer = jdbcTemplate.queryForObject(sql, Integer.class);
return integer;
}
7.返回对象
1.使用jdbc查询返回对象
queryForObject(String sql, RowMapper rowMapper, Object… args)
三个参数
- 第一个参数 sql
- 第二个参数 RowMapper,是接口,返回不同类型数据,使用这个接口里面实现完成数据封装
- 第三个参数 sql值
//接口
//返回查询对象
Payment findPayment(int id);
//实现类
@Override
public Payment findPayment(int id) {
String sql="select * from payment where id=?";
Payment payment = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(Payment.class), id);
return payment;
}
8.返回集合
1.使用jdbc Template实现查询饭返回集合
query(String sql, RowMapper rowMapper, Object… args )
三个参数
- 第一个参数 ,sql语句
- 第二个参数 RowMapper,是接口,返回不同类型数据,使用这个接口里面实现完成数据封装
- 第三个参数,sql语句的值
//接口
//返回集合
List<Payment> findAllBook();
//实现类
//返回全部数据
@Override
public List<Payment> findAllBook() {
String sql="select * from payment";
List<Payment> query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Payment.class));
return query;
}
业务类
//返回一个集合
public List<Payment> findAllBook(){
List<Payment> allBook = paymentDao.findAllBook();
return allBook;
}
5.事务管理
1.什么是事务?
事务时数据库操作的最近本单元,逻辑上一组操作,要么都成功,如果有一个失败所有的操作都失败
典型场景:银行转账
2.事务的四个特性(ACID)
- 原子性:要么成功,要么失败
- 一致性:操作之前和操作之后总量不变
- 隔离性:多事务之间不会相互影响
- 持久性:事务提交之后,表中的数据发生变化保存起来
3.事务操作
1.创建数据库,添加记录
2.创建service 搭建dao 完成对象创建和注入关系
1.接口
package com.xjggb.jdbc.dao;
public interface UserDao {
void addMoney();
void reduceMoney();
}
2.实现类
package com.xjggb.jdbc.dao.impl;
import com.xjggb.jdbc.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoImpl implements UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void addMoney() {
String sql="update user set mary=mary+ ? where name=?";
jdbcTemplate.update(sql, 100, "小明");
}
@Override
public void reduceMoney() {
String sql="update user set mary=mary- ? where name=?";
jdbcTemplate.update(sql, 100, "小红");
}
}
3.测试
//jdbc
@Test
public void show4(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("jdbc.xml");
//PaymentService paymentService = context.getBean("paymentService", PaymentService.class);
UserService userService = context.getBean("userService", UserService.class);
userService.show();
4.上面代码,如果正常秩序没有问题,但是代码执行过程中出现异常,就会有问题
模拟异常
@Service
public class UserService {
@Autowired
private UserDao userDao;
public void show(){
userDao.addMoney();
//模拟异常
int i=10/0;
userDao.reduceMoney();
}
}
5.代码出现异常 问题就是小明加了,小红却没有减
6.解决
- 开启事务
- 进行业务操作
- 没有发生异常,事务提交
- 出现异常,事件回滚
4.Spring事务管理介绍
- 事务添加到javaEE三层结构Service层(业务逻辑层)
- 在Spring进行事务管理操作
- 编程事务管理’
- 声明式事务管理
- 基于注解方式
- 基于xml方式
- Spring进行声明式事务管理,底层使用AOP原理
提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类
编写配置
<!--创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
业务类添加注解
@Transactional
public void show(){
userDao.addMoney();
//模拟异常
int i=10/0;
userDao.reduceMoney();
}
5.声明事务管理参数
事务的传播行为可以由传播属性指定,Spring定义了7种类传播行为
- 多事务方法直接进行调用,这个过程中事务如何进行管理的
6.事务的隔离级别
事务有特性称为隔离级别,多事务操作之间不会产生影响,不考虑隔离性产生很多问题
有三个读问题:脏读,不可重复读,幻读
1.脏读
脏读指事务A读取到了事务B更新了但是未提交的数据,然后事务B由于某种错误发生回滚,那么事务A读取到的就是脏数据。
2.不可重复读
一个未提交事务读取到另一提交事务修改数据
不可重复读指在数据库访问时,一个事务在前后两次相同的访问中却读到了不同的数据内容。
3.幻读
幻读指的是事务A在查询完记录总数后,事务B执行了新增数据的操作,事务A再次查询记录总数,发现两次查询的结果不一致,平白无故的多了几条记录,这种现象称为幻读。
// 添加事务注解
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
timeout:超时时间
事务需要在一定时间内进行提交,如果不提交就进行回滚
默认值为-1设置时间以秒为单位计算
@Transactional(timeout = -1,propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
readOnly:是否只读
- 读:查询操作,写:添加修改删除操作
- readOnly默认值false,表示可以查询,可以添加修改删除操作
- 设置readOnly值为true后,只能查询
@Transactional(readOnly = true,timeout = -1,propagation = Propagation.REQUIRED,isolation =Isolation.REPEATABLE_READ)
- rollbackFor:不回滚
- 设置出现哪些异常进行事务回滚
- noRollbackFor:不回滚
- 设置出现哪些异常不进行事务回滚
7.事务操作(XML声明式事务管理)
第一步配置事务管理器
<!--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.xjggb.jdbc.service.*(..)))"/>
<!--配置切面-->
<aop:advisor advice-ref="txadvice" pointcut-ref="pt"></aop:advisor>
</aop:config>
8.完全注解声明式事务
package com.xjggb.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.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
@Configuration
@ComponentScan(basePackages = "com.xjggb.jdbc")
@EnableTransactionManagement //开启事务
public class TxConfig {
// 创建数据库连接池
@Bean
public DruidDataSource getDruidDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/cloud");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
//创建JdbcTemplate对象
@Bean
public JdbcTemplate getJdbcTemplate(DataSource 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;
}
}
测试
//测试全注解
@Test
public void show6(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TxConfig.class);
UserService userService = context.getBean("userService", UserService.class);
userService.show();
}
6.Spring5新特性
1.整合JUnit5单元测试框架
添加依赖
<!-- log4j2日志依赖 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<!-- log4j2 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.6.2</version>
</dependency>
<!-- 用于slf4j与log4j2桥接 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.6.2</version>
</dependency>
<!-- commons-logging与log4j2桥接 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jcl</artifactId>
<version>2.6.2</version>
</dependency>
<!-- 使用log4j2的异步日志需要的依赖 -->
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.3.5</version>
</dependency>
<!-- web工程需要的log4j2 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-web</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-1.2-api</artifactId>
<version>2.6.2</version>
</dependency>
编写xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后面的status用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,可以看到log4j2内部各种详细输出-->
<configuration status="DEBUG">
<!--先定义所有的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.Webflux-基本概念
1.SpringWebfiux介绍
-
是Spring5添加的新的模块,用于web开发的,功能和SpringMVC类似的,Webflux使用当前一种比较流行程响应式编程出现的框架
-
使用传统web框架,比如SpringMVC,这些机遇Servlet容器,Webflux是一种异步非阻塞的框架,异步非阻塞的框架在Servlet3.1以后才支持,核心是基于Reactor的相关API实现的
-
什么是异步非阻塞模
- 异步和同步:异步和同步针对调用者,调用者发送请求,如果等着对方回应之后才去做其他事情就是同步,如果发送请求之后不等着对方回应就去做其他事情就是异步
- 阻塞和非阻塞针对被调用者,被调用者受到请求之后,做完请求任务之后才给出反馈就是阻塞,收到请求之后马上给出反馈然后再去做事情就是非阻塞
-
Webflux特点
- 非阻塞模型:在有限资源下,提供系统吞吐量和伸缩性,以Reacto为基础实现响应式编程
- 函数式编程: Spring5框架基于java8,Webflux使用Java8函数式编程方式实现路由请求
-
比较SpringMVC
- 两个框架都可以使用注解方式,都运用在Tomet等容器中
- SpringMAC采用命令式编程,Webflux采用异步响应式编程
响应式编程
响应式编程式一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流二相关的计算模型会自动将变化的值通过数据流进行传播
提供的观察这模式两个类Observer和Observable
public class ObserverDemo extends Observable {
public static void main(String[] args) {
ObserverDemo observerDemo = new ObserverDemo();
// 添加观察者
observerDemo.addObserver((o,arg)->{
System.out.println("发生变化"+arg);
});
observerDemo.addObserver((o,arg)->{
System.out.println("收到被观察者通知,准备改变"+arg);
});
observerDemo.setChanged();// 数据变化
observerDemo.notifyObservers();//通知
}
}
响应式编程(Reactor实现)
- 响应式编程操作中,Reactor是满足Reactive规范框架
- Reactor有两个核心类,Mono和Flux,这两个实现接口Publisher,提供丰富操作符。flux对象实现发布者,返回N个元素;Mono实现发布者,返回0或者1个元素
代码演示Flux和Mono
// 第一步 引入依赖
<dependencies>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>3.1.5.RELEASE</version>
</dependency>
</dependencies>
12345678
public static void main(String[] args) {
// just方法直接声明
Flux.just(1,2,3,4);
Mono.just(1);
// 其他方法
Integer[] array = {1,2,3,4};
Flux.fromArray(array);
List<Integer> list = Arrays.asList(array);
Flux.fromIterable(list);
Stream<Integer> stream = list.stream();
Flux.fromStream(stream);
}
三中信号特点
错误信号和完成信号都是终止信号,不能共存的
如果没有发送任何信号元素值,而是直接发送错误或者完成信号,表示是空数据流
如果没有错误信号,没有完成信号,表示是无限数据流
调用just或者其他方法只是声明数据流,数据流并没有发出,只有进行订阅之后才会触发数据流,不订阅声明都不会发生的
public static void main(String[] args) {
// just方法直接声明
Flux.just(1,2,3,4).subscribe(System.out::print);
Mono.just(1).subscribe(System.out::println);
}
3.SpringWebflux执行流程和核心API
SpringWebflux就Reactor,默认使用容器Netty,Netty是高性能的NIO框架,异步非阻塞的框架
SpringWebflux 里面 DispatcherHandler,负责请求的处理
- HandlerMapping:请求查询到处理的方法
- HandlerAdapter:真正负责请求处理
- HandlerResultHandler:响应结果处理
- SpringWebflux 实现函数式编程,两个接口:RouterFunction(路由处理)和 HandlerFunction(处理函数)
4.SpringWebflux(基于注解编程模型)
- SpringWebflux 实现方式有两种:
- 注解编程模型
- 使用注解编程模型方式,和之前 SpringMVC 使用相似的,只需要把相关依赖配置到项目中,SpringBoot 自动配置相关运行容器,默认情况下使用 Netty 服务器
- 函数式编程模型
- 注解编程模型
- 演示
1.创建SpringBoot项目
2.引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
3.实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private String gender;
private Integer age;
}
4.编写业务类
接口
package com.xjggb.service;
import com.xjggb.entuty.User;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public interface UserService {
/*根据id查询用户*/
Mono<User> findById(int id);
/*查询所有用户*/
Flux<User> getAllUser();
/*添加用户*/
Mono<Void> saveUserInfo(Mono<User> user);
}
实现类
@Service
public class UserServiceImpl implements UserService {
/*创建map集合存储数据*/
private final HashMap<Integer, User> userMap = new HashMap<>();
public UserServiceImpl(){
this.userMap.put(1, new User("lucy","nan",20));
this.userMap.put(2, new User("mary","nv",30));
this.userMap.put(3, new User("jack","nan",40));
this.userMap.put(4, new User("WeiSanJin","nan",50));
}
@Override
public Mono<User> findById(int id) {
//根据id查询
return Mono.justOrEmpty(this.userMap.get(id));
}
/*返回多个用户*/
@Override
public Flux<User> getAllUser() {
//查询多个
return Flux.fromIterable(this.userMap.values());
}
/** 添加用户*/
@Override
public Mono<Void> saveUserInfo(Mono<User> user) {
return user.doOnNext(p->{
int id=userMap.size()+1;
userMap.put(id,p);
}).thenEmpty(Mono.empty());
}
5.编写控制器
@RestController
public class UserController {
@Autowired
private UserService userService;
/** id查询*/
@GetMapping("/user/{id}")
public Mono<User> getUserId(@PathVariable int id){
return userService.findById(id);
}
/** 查询所有*/
@GetMapping("/user")
public Flux<User> getUser(){
return userService.getAllUser();
}
/** 添加*/
@PostMapping("/saveUser")
public Mono<Void> saveUser(@RequestBody User user){
Mono<User> userMono = Mono.just(user);
return userService.saveUserInfo(userMono);
}
6.访问
5.SpringWebflux(基于函数式编程模型)
1)在使用函数式编程模型操作时候,需要自己初始化服务器
(2)基于函数式编程模型时候,有两个核心接口:RouterFunction(实现路由功能,请求转发给对应的 handler)和 HandlerFunction(处理请求生成响应的函数)。核心任务定义两个函数式接口的实现并且启动需要的服务器。
( 3 ) SpringWebflux 请 求 和 响 应 不 再 是 ServletRequest 和 ServletResponse , 而 是ServerRequest 和 ServerResponse
-
创建 Handler(具体实现方法)
public class UserHandler { private final UserService userService; public UserHandler(UserService userService){ this.userService = userService; } /** 根据id查询*/ public Mono<ServerResponse> getUserById(ServerRequest request){ /* 获取id*/ int userId = Integer.valueOf(request.pathVariable("id")); /* 空值处理*/ Mono<ServerResponse> notFound = ServerResponse.notFound().build(); /* 调用service方法得到数据*/ Mono<User> userMono = this.userService.getUserById(userId); /* userMono进行转换返回*/ /* 使用Reactor操作符fluxMap*/ return userMono .flatMap(person -> ServerResponse.ok().contentType(MediaType.APPLICATION_JSON) .body(BodyInserters.fromObject(person))) .switchIfEmpty(notFound); } /** 查询所有*/ public Mono<ServerResponse> getAllUser(){ /* 调用service得到结果*/ Flux<User> userFlux = this.userService.getAllUser(); return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(userFlux,User.class); } /** 添加*/ public Mono<ServerResponse> saveUser(ServerRequest request){ /* 得到user对象*/ Mono<User> userMono = request.bodyToMono(User.class); return ServerResponse.ok().build(this.userService.saveUserInfo(userMono)); }
初始化服务器,编写 Router
创建路由的方法
public class Server {
/** 创建Router路由*/
public RouterFunction<ServerResponse> routerFunction(){
/* 创建hanler对象*/
UserService userService = new UserServiceImpl();
UserHandler handler = new UserHandler(userService);
/* 设置路由*/
return RouterFunctions.route(
GET("/user/{id}").and(accept(APPLICATION_JSON)),handler::getUserById)
.andRoute(GET("/user").and(accept(APPLICATION_JSON)),handler::getAllUser);
}
}
创建服务器完成适配
public class Server {
/** 创建服务器完成配置*/
public void createReactorServer(){
/*路由和handler适配*/
RouterFunction<ServerResponse> route = routerFunction();
HttpHandler httpHandler = RouterFunctions.toHttpHandler(route);
ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);
/* 创建服务器*/
HttpServer httpServer = HttpServer.create();
httpServer.handle(adapter).bindNow();
}
}
使用 WebClient 调用
public class Client {
public static void main(String[] args) {
/* 调用服务器地址*/
WebClient webClient = WebClient.create("http://127.0.0.1:8080");
/* 根据ID查询*/
String id = "1";
User userResult = webClient.get().uri("/user/{id}",id)
.accept(MediaType.APPLICATION_JSON).retrieve().bodyToMono(User.class)
.block();
System.out.println(userResult.getName());
/* 查询所有*/
Flux<User> results = webClient.get().uri("/user").accept(MediaType.APPLICATION_JSON).retrieve().bodyToFlux(User.class);
results.map(stu ->stu.getName()).buffer().doOnNext(System.out::println).blockFirst();
}
}
学习总结
1.Spring框架概述
- Spring是一个轻量的级开源javaEE框架
- Spring解决企业应用开发的复杂性
- 两个核心IOC和AOP
2.IOC容器
- IOC底层原理(工厂和反射)
- IOC的接口(BeanFactory)
- IOC操作Bean管理(1.基于xml,2.基于注解)
3.AOP
- Aop底层原理:动态代理,有接口(JDK动态代理),没有接口(CGLIB动态代理)
- 术语:切入点,增强(通知),切面
- 基于AspectJ实现AOP
4.JdbcTemplate
使用JdbcTemplate操作数据库实现crud
5.事务管理
- 对事务概念的理解
- 事务概念(传播行为和隔离级别)
- 注解实现声明式事务
- 完全注解实现注解方式实现声明事务
6.Spring5的新功能
(1)整合日志框架
(2)@Nullable 注解
(3)函数式注册对象
(4)整合 JUnit5 单元测试框架
(5)SpringWebflux 使用