Spring5框架学习

1.IOC容器

控制反转

1.1 IOC底层原理

  • xml解析
  • 工厂模式
  • 反射

1.2 IOC两种实现方式(两个接口)

1.2.1 BeanFactory

  • spring内部使用接口
  • 加载配置文件的时候不会创建对象,在获取对象的时候才去创建对象

1.2.2 ApplicationContext

  • BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员使用
  • 加载配置文件的时候就会创建对象
  • 实现类:
    1)FileSystemXmlApplicationContext:盘路径
    2)ClassPathXmlApplicationContext:类路径

1.3 IOC操作

1.3.1 Bean管理

  • Spring创建对象
  • Spring注入属性

1.3.2 Bean管理实现方式

1.3.2.1 基于xml配置文件方式实现
1.3.2.1.1 创建对象
<bean id="user" class="com.lyl.spring5.entity.User"></bean>
  • 使用bean标签
  • bean标签常用属性
  1. id:获取对象唯一标识
  2. class:全限定类名
  3. name:类似id,不推荐用
  • 创建对象时,默认执行无参构造
1.3.2.1.2 注入属性

1)DI:依赖注入

  • 使用set方法注入
<!--方式一 -->
<bean id="book" class="com.lyl.spring5.entity.Book">
        <property name="bname" value="三国演义"></property>
        <property name="bauthor" value="吴承恩"></property>
</bean>
<!--方式二:pp名称空间注入-->
xmlns:p="http://www.springframework.org/schema/p"
<bean id="book" class="com.lyl.spring5.entity.Book" p:bname="三国演义" p:bauthor="吴承恩">
</bean>
  • 使用有参构造注入
<bean id="order" class="com.lyl.spring5.entity.Order">
        <constructor-arg name="oname" value="iphone13"></constructor-arg>
        <constructor-arg name="address" value="中南海"></constructor-arg>
</bean>
  • xml注入其他类型属性
<!--向属性中设置null值 -->
<bean id="book" class="com.lyl.spring5.entity.Book">
        <property name="bname" value="三国演义"></property>
        <property name="bauthor" value="吴承恩"></property>
        <property name="address">
            <null></null>
        </property>
</bean>
<!--向属性中设置特殊符号 -->
<bean id="book" class="com.lyl.spring5.entity.Book">
        <property name="bname" value="三国演义"></property>
        <property name="bauthor" value="吴承恩"></property>
        <!--属性值包含特殊符号
            1 把<>进行转义:&lt;或者&gt;
            2 把带特殊符号内容写入CDATA
        -->
        <property name="address">
            <value><![CDATA[<<北京>>]]></value>
        </property>
</bean>
  • 注入属性-外部bean
<bean id="userService" class="com.lyl.spring5.service.UserService">
   <property name="userDao" ref="userDao"></property>
</bean>
<bean id="userDao" class="com.lyl.spring5.dao.UserDaoImpl"></bean>
  • 注入属性-内部bean和级联赋值
<!--方式一 -->
<bean id="emp" class="com.lyl.spring5.entity.Emp">
    <property name="ename" value="刘亦菲"></property>
    <property name="gender" value=""></property>
    <property name="dept">
        <bean id="dept" class="com.lyl.spring5.entity.Dept">
            <property name="dname" value="经纪部门"></property>
        </bean>
    </property>
</bean>
<--方式二 -->
<bean id="emp" class="com.lyl.spring5.entity.Emp">
    <property name="ename" value="刘亦菲"></property>
    <property name="gender" value=""></property>
    <property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.lyl.spring5.entity.Dept">
    <property name="dname" value="经纪部门"></property>
</bean>
<--方式三 -->
<bean id="emp" class="com.lyl.spring5.entity.Emp">
    <property name="ename" value="刘亦菲"></property>
    <property name="gender" value=""></property>
    <property name="dept" ref="dept"></property>
    <property name="dept.dname" value="公关部"></property>
</bean>
<bean id="dept" class="com.lyl.spring5.entity.Dept"></bean>
  • 注入属性-注入集合属性
<bean id="student" class="com.lyl.spring5.entity.Student">
     <!--数组类型属性注入 -->
     <property name="courses">
         <array>
             <value>juc课程</value>
             <value>Spring5课程</value>
             <value>SpringCloud课程</value>
         </array>
     </property>
     <!--list类型属性注入 -->
     <property name="list">
         <list>
             <value>张三</value>
             <value>李四</value>
         </list>
     </property>
     <!--map类型属性注入 -->
     <property name="map">
         <map>
             <entry key="JAVA" value="java"></entry>
             <entry key="PHP" value="php"></entry>
             <entry key="C" value="c"></entry>
         </map>
     </property>
     <!--set类型属性注入 -->
     <property name="set">
         <set>
             <value>MYSQL</value>
             <value>REDIS</value>
         </set>
     </property>
 </bean>
  • 注入属性-注入集合属性,在集合里面设置对象类型
<property name="courseList">
  <list>
      <ref bean="course1"></ref>
      <ref bean="course2"></ref>
  </list>
</property>
<bean id="course1" class="com.lyl.spring5.entity.Course">
	<property name="cname" value="SpringBoot"></property>
</bean>
<bean id="course2" class="com.lyl.spring5.entity.Course">
    <property name="cname" value="SpringCloud"></property>
</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"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <util:list id="gameList">
        <value>英雄联盟</value>
        <value>三国志13</value>
        <value>三国群英传</value>
    </util:list>

    <bean id="game" class="com.lyl.spring5.entity.Game">
        <property name="list" ref="gameList"></property>
    </bean>
</beans>
1.3.2.2 基于注解方式实现
  • @Component
  • @Controller
  • @Service
  • @Repository
    上面注解功能都是一样的
1.3.2.2.1 创建对象
  • 开启组件扫描
<?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 http://www.springframework.org/schema/context/spring-context.xsd">

    <!--开启组件扫描 -->
    <context:component-scan base-package="com.lyl.spring5"></context:component-scan>

</beans>
package com.lyl.spring5.service;

import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;

/**
 * @ClassName UserService
 * @Description TODO
 * @Author liyulong
 * @Date 2021/11/21 20:55
 * @Version 1.0
 **/
//@Component
//@Controller
@Service
//@Repository
public class UserService {

    public void add(){
        System.out.println("service add ......");
    }

}

@Test
public void test1(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
    UserService userService = applicationContext.getBean("userService", UserService.class);
    System.out.println(userService);
    userService.add();
}
  • 组件扫描细节说明
<?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 http://www.springframework.org/schema/context/spring-context.xsd">

    <!--开启组件扫描 -->
    <!--<context:component-scan base-package="com.lyl.spring5"></context:component-scan>-->

    <!--示例1
        use-default-filters="false":表示不使用默认filter,自己配置filter
        context:include-filter:设置扫描哪些内容
    -->
    <context:component-scan base-package="com.lyl.spring5" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"></context:include-filter>
    </context:component-scan>

    <!--示例2
        context:exclude-filter:设置不扫描哪些内容
    -->
    <context:component-scan base-package="com.lyl.spring5">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"></context:exclude-filter>
    </context:component-scan>
</beans>
1.3.2.2.2 属性注入
  • @AutoWired:根据属性类型进行自动注入
  • @Qualifier:根据属性名称进行自动注入,需要和@AutoWired一起使用
  • @Resource:可以根据类型注入,可以根据名称进行注入
  • @Value:注入普通类型属性
package com.lyl.spring5.dao;

public interface UserDao {

    public void add();

}

package com.lyl.spring5.dao;

import org.springframework.stereotype.Repository;

/**
 * @ClassName UserDaoImpl
 * @Description TODO
 * @Author liyulong
 * @Date 2021/11/21 21:13
 * @Version 1.0
 **/
@Repository
public class UserDaoImpl implements UserDao{

    @Override
    public void add() {
        System.out.println("UserDaoImpl ...add()");
    }
}

package com.lyl.spring5.service;

import com.lyl.spring5.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;

/**
 * @ClassName UserService
 * @Description TODO
 * @Author liyulong
 * @Date 2021/11/21 20:55
 * @Version 1.0
 **/
//@Component
//@Controller
@Service
//@Repository
public class UserService {

    @Value(value = "abc")
    private String name;

//    @Autowired
//    @Qualifier(value = "userDaoImpl")
//    @Resource
    @Resource(name="userDaoImpl")
    private UserDao userDao;

    public void add(){
        System.out.println("service add ......");
        userDao.add();
    }

}

@Test
    public void test1(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
        UserService userService = applicationContext.getBean("userService", UserService.class);
        System.out.println(userService);
        userService.add();
    }

执行结果

1.3.2.2.3 完全注解开发
package com.lyl.spring5.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @ClassName SpringConfig
 * @Description TODO
 * @Author liyulong
 * @Date 2021/11/21 21:27
 * @Version 1.0
 **/
@Configuration
@ComponentScan(basePackages = {"com.lyl.spring5"})
public class SpringConfig {

}

@Test
public void test2(){
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
    UserService userService = applicationContext.getBean("userService", UserService.class);
    System.out.println(userService);
    userService.add();
}

1.3.3 Bean管理-FactoryBean

1.3.3.1 普通Bean

 在配置文件中定义bean的类型就是返回类型

1.3.3.2 工厂Bean

 在配置文件中定义bean类型可以和返回类型不一致

package com.lyl.spring5.factoryBean;

import com.lyl.spring5.entity.Course;
import com.lyl.spring5.entity.Game;
import org.springframework.beans.factory.FactoryBean;

/**
 * @ClassName MyBean
 * @Description 工厂Bean
 * @Author liyulong
 * @Date 2021/11/21 17:53
 * @Version 1.0
 **/
public class MyBean implements FactoryBean<Course> {

    @Override
    public Course getObject() throws Exception {
        Course course = new Course();
        course.setCname("abc");
        return course;
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}
<?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="myBean" class="com.lyl.spring5.factoryBean.MyBean">
    </bean>

</beans>

1.3.4 Bean管理-Bean作用域

 Spring可以设置创建的Bean是单实例还是多实例
 Spring默认创建的Bean是单实例

@Test
    public void test3() {
        //1.加载spring配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean3.xml");
        //2.获取bean对象
        Game game1 = applicationContext.getBean("game", Game.class);
        Game game2 = applicationContext.getBean("game", Game.class);
        System.out.println(game1 == game2 ? "单实例" : "多实例");
    }

单实例

1.3.4.1 如何设置单实例或者多实例
  • 在Spring配置文件中bean标签属性scope用于设置单实例或者多实例
  • scope属性值
    默认值:singleton(单实例)
    prototype:多实例
    request:不常用
    session:不常用
<bean id="game" class="com.lyl.spring5.entity.Game" scope="prototype">
   <property name="list" ref="gameList"></property>
</bean>

多实例

1.3.4.2 singleton和prototype区别
  • singleton单实例,prototype多实例
  • singleton加载Spring配置文件时就会创建单实例对象;prototype不是在加载Spring配置文件时创建对象,而是在调用getBean方法时创建多实例对象

1.3.5 Bean管理-Bean生命周期

 对象从创建到销毁的过程

  • 通过构造器创建Bean实例(无参构造)
  • 为Bean的属性设置值和引用其他Bean(调用set方法)
  • 把Bean实例传递给Bean的后置处理器方法postProcessBeforeInitialization
  • 调用Bean的初始化方法(需要进行配置)
  • 把Bean实例传递给Bean的后置处理器方法postProcessAfterInitialization
  • Bean使用
  • Bean销毁(当容器关闭时,调用Bean的销毁方法,需要进行配置)
package com.lyl.spring5.entity;

/**
 * @ClassName Orders
 * @Description TODO
 * @Author liyulong
 * @Date 2021/11/21 19:50
 * @Version 1.0
 **/
public class Orders {

    private String oname;

    public Orders() {
        System.out.println("第一步:执行无参构造");
    }

    public void setOname(String oname) {
        this.oname = oname;
        System.out.println("第二步:调用set方法");
    }

    public void init(){
        System.out.println("第三步:执行初始化方法");
    }

    public void destroy(){
        System.out.println("第五步:执行销毁方法");
    }

    @Override
    public String toString() {
        return "Orders{" +
                "oname='" + oname + '\'' +
                '}';
    }
}

package com.lyl.spring5.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
 * @ClassName MyBeanPost
 * @Description Bean后置处理器
 * @Author liyulong
 * @Date 2021/11/21 20:01
 * @Version 1.0
 **/
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;
    }

}

<?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="orders" class="com.lyl.spring5.entity.Orders" init-method="init" destroy-method="destroy">
        <property name="oname" value="WATCH"></property>
    </bean>
    <!--配置后置处理器 -->
    <bean id="myBeanPost" class="com.lyl.spring5.bean.MyBeanPost"></bean>
</beans>
@Test
    public void test5() {
        //1.加载spring配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean5.xml");
        //2.获取bean对象
        Orders orders = applicationContext.getBean("orders", Orders.class);
        System.out.println("第四步:获取Bean对象");
        System.out.println(orders);
        //3.销毁
        ((ClassPathXmlApplicationContext) applicationContext).close();
    }

在这里插入图片描述

1.3.6 Bean管理-xml自动装配

 根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入

<?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标签属性autowire配置自动装配
        byName:根据属性名称注入
        byType;根据属性类型注入
    -->
    <bean id="emp" class="com.lyl.spring5.autowire.Emp" autowire="byName"></bean>

    <bean id="dept" class="com.lyl.spring5.autowire.Dept"></bean>

</beans>

1.3.6 Bean管理-引入外部属性文件

1.3.6.1 直接配置

<?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="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/userDb"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>

</beans>

1.3.6.2 引入外部属性文件

prop.driverClassName=driverClassName
prop.url=jdbc:mysql://localhost:3306/userDb
prop.username=root
prop.password=root
<?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 http://www.springframework.org/schema/context/spring-context.xsd">

    <!--引入外部属性文件 -->
    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>

    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${prop.driverClassName}"></property>
        <property name="url" value="${prop.url}"></property>
        <property name="username" value="${prop.username}"></property>
        <property name="password" value="${prop.password}"></property>
    </bean>
</beans>
@Test
    public void test7() {
        //1.加载spring配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean7.xml");
        //2.获取bean对象
        DruidDataSource druidDataSource = applicationContext.getBean("druidDataSource", DruidDataSource.class);
        System.out.println(druidDataSource.getDriverClassName());
        System.out.println(druidDataSource.getUrl());
        System.out.println(druidDataSource.getUsername());
        System.out.println(druidDataSource.getPassword());
    }

在这里插入图片描述

2.AOP

面向切面编程

2.1 AOP底层原理

2.1.1 动态代理

2.1.1.1 有接口情况

JDK动态代理

package com.lyl.spring5;

public interface UserDao {

    public int add(int a,int b);

    public String update(String id);

}

package com.lyl.spring5;

/**
 * @ClassName UserDaoImpl
 * @Description TODO
 * @Author liyulong
 * @Date 2021/11/21 22:55
 * @Version 1.0
 **/
public class UserDaoImpl implements UserDao {

    @Override
    public int add(int a, int b) {
        System.out.println("UserDaoImpl...add方法执行");
        return a + b;
    }

    @Override
    public String update(String id) {
        System.out.println("UserDaoImpl...update方法执行");
        return id;
    }
}

package com.lyl.spring5;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

/**
 * @ClassName JDKProxy
 * @Description TODO
 * @Author liyulong
 * @Date 2021/11/21 22:56
 * @Version 1.0
 **/
public class JDKProxy {

    public static void main(String[] args) {
        //创建接口实现类代理对象
        Class[] interfaces = {UserDao.class};
        UserDaoImpl userDaoImpl = new UserDaoImpl();
        UserDao userDao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {

            //目标对象
            private Object obj;

            {
                this.obj = userDaoImpl;
            }

            /**
             * 增强逻辑
             * @param proxy
             * @param method
             * @param args
             * @return
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                //方法之前
                System.out.println("方法之前执行..." + method.getName() + ",传递的参数..." + Arrays.toString(args));

                Object result = method.invoke(obj, args);

                //方法之后
                System.out.println("方法之后执行..." + obj);

                return result;
            }
        });
        int result = userDao.add(1, 2);
        System.out.println("result:" + result);
    }
}

2.1.1.2 没有接口情况

CGLIB动态代理


2.2 AOP术语

  • 连接点:可以被增强的方法
  • 切入点:实际真正被增强的方法
  • 通知(增强):实际增加的增强逻辑
    1)前置通知
    2)后置通知
    3)环绕通知
    4)异常通知
    5)最终通知
  • 切面:把通知应用到切入点的过程,是一个动作

2.3 AOP操作

Spring框架一般都是基于AspectJ实现AOP操作

2.3.1 基于AspectJ实现AOP操作

2.3.1.1 切入点表达式
  • 表示对那个类的那个方法进行增强
  • 语法结构
    execution([权限修饰符][返回类型][全限定类名]方法名称)
2.3.1.2 基于注解方式实现
package com.lyl.spring5.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * @ClassName SpringConfig
 * @Description 配置类
 * @Author liyulong
 * @Date 2021/11/22 20:15
 * @Version 1.0
 **/
@Configuration
@ComponentScan(basePackages = {"com.lyl.spring5"})
@EnableAspectJAutoProxy
public class SpringConfig {
}

package com.lyl.spring5.annoaop;

import org.springframework.stereotype.Component;

/**
 * @ClassName User
 * @Description 目标类(被增强类)
 * @Author liyulong
 * @Date 2021/11/22 20:13
 * @Version 1.0
 **/
@Component
public class User {

    public void add() {
//        int a = 10/0;
        System.out.println("User...add()");
    }

}

package com.lyl.spring5.annoaop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @ClassName UserPro
 * @Description 增强类
 * @Author liyulong
 * @Date 2021/11/22 20:14
 * @Version 1.0
 **/
@Component
@Aspect
public class UserPro {

    //前置通知
    @Before(value = "execution(* com.lyl.spring5.annoaop.User.add(..))")
    public void before(){
        System.out.println("UserPro...before()");
    }


    //后置通知
    @AfterReturning(value = "execution(* com.lyl.spring5.annoaop.User.add(..))")
    public void afterReturning(){
        System.out.println("UserPro...afterReturning()");
    }

    //最终通知
    @After(value = "execution(* com.lyl.spring5.annoaop.User.add(..))")
    public void after(){
        System.out.println("UserPro...after()");
    }

    //异常通知
    @AfterThrowing(value = "execution(* com.lyl.spring5.annoaop.User.add(..))")
    public void afterThrowing(){
        System.out.println("UserPro...afterThrowing()");
    }

    //环绕通知
    @Around(value = "execution(* com.lyl.spring5.annoaop.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("UserPro...around()前");
        proceedingJoinPoint.proceed();
        System.out.println("UserPro...around()后");
    }

}

package com.lyl.spring5;

import com.lyl.spring5.annoaop.User;
import com.lyl.spring5.config.SpringConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @ClassName Test
 * @Description 测试类
 * @Author liyulong
 * @Date 2021/11/22 20:22
 * @Version 1.0
 **/
public class Test {

    @org.junit.Test
    public void test1() {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
        User user = applicationContext.getBean("user", User.class);
        user.add();
    }

}

执行结果

  • 重用切入点定义
    @Pointcut
package com.lyl.spring5.annoaop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @ClassName UserPro
 * @Description 增强类
 * @Author liyulong
 * @Date 2021/11/22 20:14
 * @Version 1.0
 **/
@Component
@Aspect
public class UserPro {

    @Pointcut(value = "execution(* com.lyl.spring5.annoaop.User.add(..))")
    public void pointDemo(){

    }

    //前置通知
    @Before(value = "pointDemo()")
    public void before(){
        System.out.println("UserPro...before()");
    }


    //后置通知
    @AfterReturning(value = "pointDemo()")
    public void afterReturning(){
        System.out.println("UserPro...afterReturning()");
    }

    //最终通知
    @After(value = "pointDemo()")
    public void after(){
        System.out.println("UserPro...after()");
    }

    //异常通知
    @AfterThrowing(value = "pointDemo()")
    public void afterThrowing(){
        System.out.println("UserPro...afterThrowing()");
    }

    //环绕通知
    @Around(value = "pointDemo()")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("UserPro...around()前");
        proceedingJoinPoint.proceed();
        System.out.println("UserPro...around()后");
    }

}
  • 多个增强类对同一个方法进行增强
    @Order
package com.lyl.spring5.annoaop;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @ClassName UserProX
 * @Description TODO
 * @Author liyulong
 * @Date 2021/11/22 20:39
 * @Version 1.0
 **/
@Component
@Aspect
@Order(1)
public class UserProX {

    //前置通知
    @Before(value = "execution(* com.lyl.spring5.annoaop.User.add(..))")
    public void before(){
        System.out.println("UserProX...before()");
    }

}

package com.lyl.spring5.annoaop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @ClassName UserPro
 * @Description 增强类
 * @Author liyulong
 * @Date 2021/11/22 20:14
 * @Version 1.0
 **/
@Component
@Aspect
@Order(2)
public class UserPro {

    @Pointcut(value = "execution(* com.lyl.spring5.annoaop.User.add(..))")
    public void pointDemo(){

    }

    //前置通知
    @Before(value = "pointDemo()")
    public void before(){
        System.out.println("UserPro...before()");
    }


    //后置通知
    @AfterReturning(value = "pointDemo()")
    public void afterReturning(){
        System.out.println("UserPro...afterReturning()");
    }

    //最终通知
    @After(value = "pointDemo()")
    public void after(){
        System.out.println("UserPro...after()");
    }

    //异常通知
    @AfterThrowing(value = "pointDemo()")
    public void afterThrowing(){
        System.out.println("UserPro...afterThrowing()");
    }

    //环绕通知
    @Around(value = "pointDemo()")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("UserPro...around()前");
        proceedingJoinPoint.proceed();
        System.out.println("UserPro...around()后");
    }

}

执行结果

2.3.1.3 基于xml配置文件实现

不推荐

<?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 ">


    <bean id="user" class="com.lyl.spring5.annoaop.User"></bean>
    <bean id="userPro" class="com.lyl.spring5.annoaop.UserPro"></bean>

    <!--配置aop增强 -->
    <aop:config>

        <!--配置切入点 -->
        <aop:pointcut id="ap" expression="execution(* com.lyl.spring5.annoaop.User.add(..))"></aop:pointcut>

        <!--配置切面 -->
        <aop:aspect ref="userPro">
            <!--配置通知 -->
            <aop:before method="before" pointcut-ref="ap"></aop:before>
        </aop:aspect>

    </aop:config>
</beans>
@org.junit.Test
    public void test2() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
        User user = applicationContext.getBean("user", User.class);
        user.add();
    }

执行结果

3.jdbcTemplate

 xml配置

<?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">

	<!--开启注解扫描 -->
    <context:component-scan base-package="com.lyl.spring5"></context:component-scan>

    <!--配置数据源 -->
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3307/user_db"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>

    <!--配置jdbcTemplate -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入数据源 -->
        <property name="dataSource" ref="druidDataSource"></property>
    </bean>

</beans>

4.Spring事务

底层使用到了AOP原理

4.1 事物的四个特性(ACID)

  • 原子性
  • 一致性
  • 隔离性
  • 持久性

4.2 声明式事务管理

4.2.1 基于注解方式

<!--配置事务管理器 -->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="druidDataSource"></property>
</bean>

<!--开启事务注解 -->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"></tx:annotation-driven>
package com.lyl.spring5.service;

import com.lyl.spring5.dao.BookDao;
import com.lyl.spring5.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @ClassName UserService
 * @Description TODO
 * @Author liyulong
 * @Date 2021/11/22 21:23
 * @Version 1.0
 **/
@Service
@Transactional
public class UserService {

    @Autowired
    private UserDao userDao;

    public void add(User user){
        userDao.add(user);
    }
}

4.2.2 基于xml配置文件方式

<?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:tx="http://www.springframework.org/schema/tx"
       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/tx http://www.springframework.org/schema/tx/spring-tx.xsd
                          http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--开启注解扫描 -->
    <context:component-scan base-package="com.lyl.spring5"></context:component-scan>

    <!--配置数据源 -->
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3307/user_db"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>

    <!--配置jdbcTemplate -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入数据源 -->
        <property name="dataSource" ref="druidDataSource"></property>
    </bean>

    <!--配置事务管理器 -->
    <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="druidDataSource"></property>
    </bean>
    
    <!--配置通知 -->
    <tx:advice id="txAdvice">
        <!--配置事务参数 -->
        <tx:attributes>
            <!--指定那种规则的方法添加事务 -->
            <tx:method name="add*" isolation="DEFAULT" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    
    <!--配置切入点和切面 -->
    <aop:config>
        <!--配置切入点 -->
        <aop:pointcut id="ap" expression="execution(* com.lyl.spring5.service.UserService.*(..))"></aop:pointcut>
        <!--配置切面 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="ap"></aop:advisor>
    </aop:config>
</beans>

4.2.3 完全注解方式

package com.lyl.spring5.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Autowired;
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;

/**
 * @ClassName TxConfig
 * @Description TODO
 * @Author liyulong
 * @Date 2021/11/22 23:02
 * @Version 1.0
 **/
@Configuration
@ComponentScan(basePackages = {"com.lyl.spring5"})
@EnableTransactionManagement
public class TxConfig {

    /**
     * 创建数据源
     *
     * @return
     */
    @Bean
    public DruidDataSource getDruidDataSource() {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql://localhost:3307/user_db");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("root");
        return druidDataSource;
    }

    /**
     * 创建JdbcTemplate
     *
     * @param dataSource
     * @return
     */
    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

    /**
     * 创建事务管理器
     *
     * @param dataSource
     * @return
     */
    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource) {
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }

}

4.3 事务管理API

PlatformTransactionManager
在这里插入图片描述

4.4 事务的传播行为

Propagation.REQUIRED(默认)
Propagation.SUPPORTS
Propagation.MANDATORY
Propagation.REQUIRES_NEW
Propagation.NOT_SUPPORTED
Propagation.NEVER
Propagation.NESTED

在这里插入图片描述

4.4 事务的隔离级别

解决的三个问题:

  • 脏读:一个未提交事务读取到了另一个未提交事务的数据
  • 不可重复读:一个未提交事务读取到了另一个提交事务修改的数据
  • 幻读:一个未提交事务读取到了另一个提交事务添加的数据
Isolation.READ_UNCOMMITTED
Isolation.READ_COMMITTED(Oracle默认)
Isolation.REPEATABLE_READ(mysql默认)
Isolation.SERIALIZABLE

5.Spring5新功能

基于java8

5.1 自带通用的日志封装

详情参考这篇文章,
特别说明:web.xml中可以不配置

5.2 支持@Nullable注解

  • 用在方法上:方法返回值可以为空
  • 用在方法参数上:参数可以为空
  • 用在属性上:属性值可以为空

5.3 支持函数式风格

/**
 * 函数式风格创建对象,并交给Spring容器管理
 */
@org.junit.Test
public void test3(){
    //1 创建GenericApplicationContext对象
    GenericApplicationContext context = new GenericApplicationContext();
    //2 注册对象
    context.refresh();
    context.registerBean("user",User.class,()->new User());
    User user = context.getBean("user", User.class);
//        User user = context.getBean("com.lyl.spring5.entity.User", User.class);
    System.out.println(user);
}

5.3 支持整合JUnit5

  • 回顾Spring整合JUnit4
package com.lyl.spring5;

import com.lyl.spring5.service.BookService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * @ClassName TestJUint
 * @Description TODO
 * @Author liyulong
 * @Date 2021/11/23 20:08
 * @Version 1.0
 **/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:bean.xml")
public class TestJUnit {

    @Autowired
    private BookService bookService;
    
}
  • spring5整合JUnit5
    1)方式一
package com.lyl.spring5;

import com.lyl.spring5.service.BookService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

/**
 * @ClassName TestJUnit5
 * @Description Spring5整合JUnit5
 * @Author liyulong
 * @Date 2021/11/23 20:14
 * @Version 1.0
 **/
@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath:bean.xml")
public class TestJUnit5 {

    @Autowired
    private BookService bookService;

    @Test
    public void test() {
    }

}

2)方式二:使用复合注解

package com.lyl.spring5;

import com.lyl.spring5.service.BookService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;

/**
 * @ClassName TestJUnit5
 * @Description Spring5整合JUnit5
 * @Author liyulong
 * @Date 2021/11/23 20:14
 * @Version 1.0
 **/
@SpringJUnitConfig(locations = "classpath:bean.xml")
public class TestJUnit5 {

    @Autowired
    private BookService bookService;

    @Test
    public void test() {
    }

}

5.4 SpringWebflux

5.4.1 介绍

  • 用于web开发,功能和SpringMVC类似.WebFlux使用当前一种比较流行的响应式编程来实现
  • 传统web框架,如SpringMVC,都是基于Servlet容器;而WebFlux是一种异步非阻塞的框架,而该框架在Servlet3.1以后才支持,核心是基于Reactor的相关API来实现的

5.4.2 异步非阻塞

  • 异步和同步针对调用者,调用者发送请求,如果发送请求之后不等待对方回应就去做其他事情就是异步,否则就是同步
  • 阻塞和非阻塞针对被调用者,被调用者收到请求之后,做完请求任务之后才给出反馈,就是阻塞;收到请求之后马上给出反馈然后再去做事情就是非阻塞

5.4.3 WebFlux的优势

  • 非阻塞:在有限资源下,提高系统吞吐量和伸缩性,以Reactor为基础实现响应式编程
  • 函数式编程

5.4.4 响应式编程

5.4.4.1 介绍

  响应式编程是一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。
  电子表格程序就是响应式编程的一个例子。单元格可以包含字面值或类似"=B1+C1"的公式,而包含公式的单元格的值会依据其他单元格的值的变化而变化。

5.4.4.2 java8实现

观察者模式,两个类:Observer和Observable

package com.lyl.reactordemo.reactor8;

import java.util.Observable;

/**
 * @ClassName ObserverDemo
 * @Description TODO
 * @Author liyulong
 * @Date 2021/11/23 21:04
 * @Version 1.0
 **/
public class ObserverDemo extends Observable {

    public static void main(String[] args) {
        ObserverDemo observerDemo = new ObserverDemo();
        //添加观察者
        observerDemo.addObserver((o,e)->{
            System.out.println("发生变化");
        });
        observerDemo.addObserver((o,e)->{
            System.out.println("收到被观察者通知,准备改变");
        });
        //监测数据变化
        observerDemo.setChanged();
        //通知
        observerDemo.notifyObservers();
    }

}
5.4.4.3 Reactor实现
  • 响应式编程需要满足Reactive
  • Reactor是满足Reactive规范的框架
  • Reactor两个核心类,Mono和Flux,都实现了Publisher.
  • Flux实现发布者:返回N个元素
  • Mono实现发布者:返回0或者1个元素
  • Flux和Mono都是数据流的发布者,都可以发出三种数据信号:
    1)元素值
    2)错误信号
    3)完成信号
     错误信号和完成信号都代表终止信号,终止信号告诉订阅者数据流结束了
     错误信号终止数据流的同时会把错误信息传递给订阅者
  • 代码演示
package com.lyl.reactordemo.reactor8;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

/**
 * @ClassName TestReactor
 * @Description TODO
 * @Author liyulong
 * @Date 2021/11/23 21:26
 * @Version 1.0
 **/
public class TestReactor {

    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流
        Stream<Integer> stream = list.stream();
        Flux.fromStream(stream);

        //异常信号
        NullPointerException nullPointerException = new NullPointerException();
        Flux.error(nullPointerException);

    }
}
  • 调用just或者其他方法只是声明数据流,数据流并没有发出,只有进行订阅之后才会触发数据流,不订阅什么都不会发生
Flux.just(1, 2, 3, 4).subscribe(System.out::println);
Mono.just(1).subscribe(System.out::println);

在这里插入图片描述

  • 三种信号特点
    1)错误信号和完成信号都是终止信号,不能共存
    2)如果没有发送任何元素值,而是直接发送错误或者完成信号,表示是空数据流
    3)如果没有错误信号也没有完成信号,表示是无限数据流
  • 操作符
    对数据流进行操作,就称为操作符
    1)map:元素映射为新的元素
    2)flatMap:元素映射为流

5.4.5 SpringWebFlux执行流程和核心API

SpringWebFlux基于Reactor,默认容器是Netty,Netty是一个高性能的NIO(异步非阻塞)框架

5.4.5.1 Netty

5.4.5.2 SpringWebFlux执行流程(类似SpringMVC)

SpringWebFlux核心控制器DispatchHandler,实现接口WebHandler

  • DispatchHandler负责请求的处理
  • HandlerMapping:根据请求查询到具体处理方法
  • HandlerAdapter:处理请求
  • HandlerResultHandler:响应结果处理
5.4.5.3 SpringWebFlux实现函数式编程两个接口
  • RouterFunction:路由处理
  • HandlerFunction:处理函数

5.4.6 SpringWebFlux基于注解编程

SpringBoot自动配置了相关允许容器,默认情况下使用Nett容器

package com.lyl.webfluxdemo1.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @ClassName User
 * @Description TODO
 * @Author liyulong
 * @Date 2021/11/23 22:36
 * @Version 1.0
 **/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    private String name;
    private String gender;
    private Integer age;

}


package com.lyl.webfluxdemo1.controller;

import com.lyl.webfluxdemo1.entity.User;
import com.lyl.webfluxdemo1.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

/**
 * @ClassName UserController
 * @Description TODO
 * @Author liyulong
 * @Date 2021/11/23 22:52
 * @Version 1.0
 **/
@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/user/{id}")
    public Mono<User> getUserById(@PathVariable int id) {
        return userService.getUserById(id);
    }

    @GetMapping("/user")
    public Flux<User> getAllUser() {
        return userService.getAllUser();
    }

    @PostMapping("/user/save")
    public Mono<Void> saveUser(@RequestBody User user) {
        Mono<User> userMono = Mono.just(user);
        return userService.saveUserInfo(userMono);
    }

}

package com.lyl.webfluxdemo1.service;

import com.lyl.webfluxdemo1.entity.User;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

public interface UserService {

    Mono<User> getUserById(int id);

    Flux<User> getAllUser();

    Mono<Void> saveUserInfo(Mono<User> userMono);

}

package com.lyl.webfluxdemo1.service.impl;

import com.lyl.webfluxdemo1.entity.User;
import com.lyl.webfluxdemo1.service.UserService;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName UserServiceImpl
 * @Description TODO
 * @Author liyulong
 * @Date 2021/11/23 22:40
 * @Version 1.0
 **/
@Service
public class UserServiceImpl implements UserService {

    private final Map<Integer, User> users = new HashMap<>();

    public UserServiceImpl() {
        this.users.put(1, new User("lyl", "nan", 18));
        this.users.put(2, new User("wbx", "gou", 20));
        this.users.put(3, new User("haha", "weizhi", 8));
    }

    @Override
    public Mono<User> getUserById(int id) {

        return Mono.justOrEmpty(this.users.get(id));
    }

    @Override
    public Flux<User> getAllUser() {
        return Flux.fromIterable(this.users.values());
    }

    @Override
    public Mono<Void> saveUserInfo(Mono<User> userMono) {

        return userMono.doOnNext(person -> {
            int id = users.size() + 1;
            this.users.put(id, person);
        }).thenEmpty(Mono.empty());
    }


}

说明:

  • SpringMVC:同步阻塞方式,基于SpringMVC+Servlet+Tomcat
  • SpringWebFlux:异步非阻塞方式,基于SpringWebFlux+Reactor+Netty

5.4.7 SpringWebFlux基于函数式编程

package com.lyl.webfluxdemo1.handler;

import com.lyl.webfluxdemo1.entity.User;
import com.lyl.webfluxdemo1.service.UserService;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import static org.springframework.web.reactive.function.BodyInserters.fromObject;

/**
 * @ClassName UserHandler
 * @Description TODO
 * @Author liyulong
 * @Date 2021/11/24 19:47
 * @Version 1.0
 **/
public class UserHandler {

    private final UserService userService;

    public UserHandler(UserService userService) {
        this.userService = userService;
    }

    public Mono<ServerResponse> getUserById(ServerRequest request) {
        int id = Integer.valueOf(request.pathVariable("id"));
        Mono<ServerResponse> notFound = ServerResponse.notFound().build();
        Mono<User> userMono = this.userService.getUserById(id);
        return userMono.
                flatMap(person -> ServerResponse.ok().contentType(MediaType.APPLICATION_JSON)
                        .body(fromObject(person)))
                .switchIfEmpty(notFound);
    }

    public Mono<ServerResponse> getAllUser(ServerRequest request) {
        Flux<User> allUser = this.userService.getAllUser();
        return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(allUser, User.class);
    }

    public Mono<ServerResponse> saveUserInfo(ServerRequest request) {
        Mono<User> userMono = request.bodyToMono(User.class);
        return ServerResponse.ok().build(this.userService.saveUserInfo(userMono));
    }

}
package com.lyl.webfluxdemo1;

import com.lyl.webfluxdemo1.handler.UserHandler;
import com.lyl.webfluxdemo1.service.UserService;
import com.lyl.webfluxdemo1.service.impl.UserServiceImpl;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.netty.http.server.HttpServer;

import java.io.IOException;

import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.web.reactive.function.server.RequestPredicates.*;
import static org.springframework.web.reactive.function.server.RouterFunctions.toHttpHandler;

/**
 * @ClassName Server
 * @Description TODO
 * @Author liyulong
 * @Date 2021/11/24 20:06
 * @Version 1.0
 **/
public class Server {

    //创建Router路由
    public RouterFunction<ServerResponse> routingFunction() {
        //创建handler对象
        UserService userService = new UserServiceImpl();
        UserHandler userHandler = new UserHandler(userService);
        //设置路由
        return RouterFunctions.route(
                GET("/user/{id}").and(accept(APPLICATION_JSON)), userHandler::getUserById)
                .andRoute(GET("/users").and(accept(APPLICATION_JSON)), userHandler::getAllUser);
    }

    //创建服务器完成适配
    public void createReactorServer() {
        //路由和Handler适配
        RouterFunction<ServerResponse> routerFunction = routingFunction();
        HttpHandler httpHandler = toHttpHandler(routerFunction);
        ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);

        //创建服务器
        HttpServer httpServer = HttpServer.create();
        httpServer.handle(adapter).bindNow();

    }

    public static void main(String[] args) throws IOException {
        Server server = new Server();
        server.createReactorServer();
        System.out.println("enter to exit");
        System.in.read();
    }

}

5.4.8 使用WebClient实现调用

package com.lyl.webfluxdemo1;

import com.lyl.webfluxdemo1.entity.User;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;

/**
 * @ClassName Client
 * @Description TODO
 * @Author liyulong
 * @Date 2021/11/24 20:34
 * @Version 1.0
 **/
public class Client {

    public static void main(String[] args) {
        //调用服务器地址
        WebClient webClient = WebClient.create("http://localhost:64266");
        String id = "1";
        User user = webClient.get().uri("/user/{id}", id).accept(MediaType.APPLICATION_JSON).retrieve().bodyToMono(User.class).block();
        System.out.println(user);

        Flux<User> userFlux = webClient.get().uri("/users").accept(MediaType.APPLICATION_JSON).retrieve().bodyToFlux(User.class);
        userFlux.map(stu -> stu.getName()).buffer().doOnNext(System.out::println).blockFirst();
    }

}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值