初识spring

Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。

Spring是一个开源框架,它由[Rod Johnson](https://baike.baidu.com/item/Rod Johnson)创建。它是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。

快速构建一个spring项目

建议使用maven创建项目,在pom.xml下面导入依赖

<dependencies>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>

    </dependencies>
    
<!--防止打包忽略配置文件-->
 <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>

创建配置文件bean1.xml

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RewU5Oib-1650034961139)(初识spring.assets/1646806689953.png)]

<?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 name="user" class="com.wu.domain.User">
        <property name="id" value="123"/>
    </bean>

</beans>

创建实体类User

public class User {
    
        private Integer id;
        private String name;
    
        public User(){
    
        }
        public User(Integer id, String name) {
            this.id = id;
            this.name = name;
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }

编写测试类

public class BeanTest {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new 
                ClassPathXmlApplicationContext("bean1.xml");

        User user = (User) applicationContext.getBean("user");

        System.out.println(user.getId());
    }
}

什么是spring容器?

我们可以非常简单的理解成spring就是一个大澡堂,这个澡堂里有很多东西,服务

什么是IOC?

ioc(控制反转):字面很难理解,我们可以简单理解成。以前我们调用一个对象的时候是不是通过new关键字进行对象的创建,现在我们把把这个创建的权利交给了spring容器,我们只需要在容器中去getBean()获得对象即可调用。

(还可以简单理解成,以前去澡堂洗澡只能自己手动搓澡,政府强大了为了回报大家建造了一个澡堂(spring容器),可以为大家提供搓澡服务,这样一来我们就不用自己搓澡了)

(1)控制反转,把对象创建和对象之间的调用过程,交给 Spring 进行管理

(2)使用 IOC 目的:为了耦合度降低

(3)做入门案例就是 IOC 实现

ioc底层实现原理

xml 解析、工厂模式、反射

第一步spring会解析xml配置文件

第二步有一个工厂类会通过xml中的bean标签class属性获取类名然后获取他的.class文件通过反射,创建实例给与使用者

BeanFactory 接口

1,IOC 思想基于 IOC 容器完成,IOC 容器底层就是对象工厂

2,Spring 提供 IOC 容器实现两种方式:(两个接口)

(1)BeanFactory:IOC 容器基本实现,是 Spring 内部的使用接口,不提供开发人员进行使用

* 加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象

(2)ApplicationContext:BeanFactory 接口的子接口,提供更多更强大的功能,一般由开发人

员进行使用

* 加载配置文件时候就会把在配置文件对象进行创建

ioc管理bean的方式

为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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--p名称空间注入 p:name="wgy"-->
    <bean name="user" class="com.wu.domain.User">
        <!--set方法注入-->
<!--        <property name="id" value="123"/>-->
        <!--构造方法注入-->
<!--        <constructor-arg name="id" value="123"/>-->
<!--        <constructor-arg name="name" value="wgy"/>-->

        <!--将属性致于null-->
        <property name="id">
            <null/>
        </property>

        <!--属性值包含特殊符号
         1 把<>进行转义 < >
         2 把带特殊符号内容写到 CDATA
        -->
        <property name="name">
            <value><![CDATA[<<wgy>>]]></value>
        </property>
    </bean>

</beans>

属性是引用类型

<?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="userService" class="com.wu.service.UserService">
        <property name="userDao" ref="userDao"/>
    </bean>

    <bean id="userDao" class="com.wu.dao.UserDao"/>


</beans>

一对多赋值

<?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="emp" class="com.wu.domain.Emp">
        <property name="id" value="2"/>
        <property name="name" value="wgy"/>
        <property name="age" value="18"/>

        <!--对象属性赋值-->
<!--        <property name="dept">-->
<!--            <bean class="com.wu.domain.Dept">-->
<!--                <property name="id" value="1"/>-->
<!--                <property name="dname" value="开发"/>-->
<!--            </bean>-->
<!--        </property>-->

        <!--级联赋值-->
        <property name="dept" ref="dept"/>
    </bean>

    <bean id="dept" class="com.wu.domain.Dept">
        <property name="id" value="1"/>
        <property name="dname" value="开发"/>
    </bean>


</beans>

给集合赋值

//1 数组类型属性
    private String[] courses;
    //2 list 集合类型属性
    private List<String> list;
    //3 map 集合类型属性
    private Map<String,String> maps;
    //4 set 集合类型属性
    private Set<String> sets;
    private List<Course> listc;
<?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 https://www.springframework.org/schema/util/spring-util.xsd">

    <bean id="student" class="com.wu.domain.Student">
        <property name="courses">
            <array>
                <value>数学</value>
                <value>英语</value>
            </array>
        </property>

        <!--两种方法都可以-->
        <property name="list" ref="list">
<!--            <list>-->
<!--                <value>1</value>-->
<!--                <value>2</value>-->
<!--            </list>-->
        </property>

        <property name="maps">
            <map>
                <entry key="k1" value="wgy"/>
                <entry key="k2" value="why"/>
            </map>
        </property>

        <property name="sets">
            <set>
                <value>MySQL</value>
                <value>Redis</value>
            </set>
        </property>

        <property name="listc">
            <list>
                <ref bean="course1"/>
                <ref bean="course2"/>
            </list>
        </property>
    </bean>

    <bean class="com.wu.domain.Course" id="course1"/>
    <bean class="com.wu.domain.Course" id="course2"/>

    <!--提取list集合-->
    <util:list id="list">
        <value>1</value>
        <value>2</value>
    </util:list>
</beans>

IOC 操作 Bean **管理(**FactoryBean)

Spring 有两种类型 bean,一种普通** bean**,另外一种工厂** bean**(FactoryBean)**

1、普通** bean**:在配置文件中定义** bean 类型就是返回类型

2、工厂** bean**:在配置文件定义** bean 类型可以和返回类型不一样

第一步 创建类,让这个类作为工厂 bean,实现接口 FactoryBean

第二步 实现接口里面的方法,在实现的方法中定义返回的 bean 类型

创建一个工厂bean

首先创建一个对象实现接口

package FactoryBean.factory;

import FactoryBean.domain.User;
import org.springframework.beans.factory.FactoryBean;

/**
 * @Descirption:
 * @create 2022-03-09 16:08
 * @auther: wgy
 */
// 通过工厂将bean制造出来进一步解耦
public class MyBean implements FactoryBean<User> {

    @Override
    public User getObject() throws Exception {
        User user = new User();
        user.setName("wgy");
        return user;
    }

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

}

创建需要生成的对象

package FactoryBean.domain;

/**
 * @Descirption:
 * @create 2022-03-09 16:07
 * @auther: wgy
 */
public class User {

    private String name;

    public User(String name) {
        this.name = name;
    }

    public User(){
        System.out.println("hello");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

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

xml配置文件

<bean id="myBean" class="FactoryBean.factory.MyBean"></bean>

测试类

@Test
    public void TestBean1(){
        ApplicationContext applicationContext = new
                ClassPathXmlApplicationContext("bean5.xml");

        User user =applicationContext.getBean("myBean", User.class);

        System.out.println(user);
    }

Bean的实例化

1 . 静态工厂方式实例化

就是创建一个工厂类,在里面写上一个静态的方法,这个方法返回的是一个实例,这个实例是我们工厂实例化出来的.当我们需要用的时候,可以直接通过getBean(id的name)来得到他

1 .创建一个空的bean对象

package com.wu.staic_factory;

public class Bean2 {
}

2 . 创建一个工厂,里面定义一个静态的createBean方法,用来返回实例对象

package com.wu.staic_factory;


public class MyBean2Factory {

    public MyBean2Factory() {
        System.out.println("MyBean2Factory初始化工厂中");
    }

    //使用自己的工厂创建bean2实例
    public static Bean2 createBeanFactory(){
        return new Bean2();
    }
}

3 . 在xml文件中进行配置

<bean id="bean2" 
      class="com.wu.staic_factory.MyBean2Factory" factory-method="createBeanFactory"/>

4 . 编写测试类

package com.wu.staic_factory;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class InstanceTest2 {

    public static void main(String[] args) {
        //定义配置文件的路径
        String xmlPath="com/wu/staic_factory/bean2.xml";

        //applicationcontext加载配置文件。初始化bean
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);

        System.out.println(applicationContext.getBean("bean2"));
    }

}
2 . 实例化工厂实例化

跟静态工厂类似,不过工厂类中的创建bean方法不是静态的 , 配置文件修改.

1 . 创建一空bean对象

package com.wu.factory;

public class Bean3 {
}

2 . 创建一个工厂,里面定义一个createBean方法,用来返回实例对象

package com.wu.factory;


public class MyBean3Factory {

    public MyBean3Factory() {
        System.out.println("MyBean3Factory初始化工厂中");
    }

    //使用自己的工厂创建bean3实例
    public Bean3 createBeanFactory(){
        return new Bean3(;
    }
}

3 . 配置文件如下

<!-- 配置工厂-->
    <bean id="myBean3Factory" class="com.wu.factory.MyBean3Factory"/>

    <!-- 使用factory-bean指定配置的实例工厂   -->
    <!-- 使用factory-method指定配置的实例工厂的拿个方法   -->
    <bean id="bean3" factory-bean="myBean3Factory" factory-method="createBeanFactory"/>

4 . 测试类

package com.wu.factory;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class InstanceTest3 {

    public static void main(String[] args) {
        //定义配置文件的路径
        String xmlPath="com/wu/factory/bean3.xml";

        //applicationcontext加载配置文件。初始化bean
        ApplicationContext applicationContext = new 	      ClassPathXmlApplicationContext(xmlPath);

        System.out.println(applicationContext.getBean("bean3"));
    }

}

有人说静态工厂和实例化工厂不就是,方法多个static,为啥要多加配置文件.我的理解是static修饰的东西他是最先加载的,比类还要先加载,所以我们在静态工厂实例化中可以用factory-method="createBeanFactory"指定静态方法.但是实例化工厂则不可以,因为他的方法是非静态的 , 所以加载顺序必须等类实例化出来才可以加载方法所以实例化工厂 , 我们需要先把bean工厂给实例化出来然后再去指定他的实例化方法. 故多了一些配置

Bean的作用域

1 . singleton单例模式,每次创建的bean实例都是同一个.

2 . prototype原型模式,每次创建的bean实例都是一个新的

只需要在bean属性中加上scope属性即可使用

spring默认使用singleton

区别

singleton 会在加载配置文件的时候 将bean全部实例化出来

prototype 会在你需要的时候实例化bean不会在加载的时候实例化

Bean生命周期

(1)通过构造器创建 bean 实例(无参数构造)

(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)

(3)调用 bean 的初始化的方法(需要进行配置初始化的方法)

(4)bean 可以使用了(对象获取到了)

(5)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)

package life.domain;

/**
 * @Descirption:
 * @create 2022-03-09 17:05
 * @auther: wgy
 */
public class User {

    private String name;

    public User(){
        System.out.println("第一步,构造方法开始执行了");
    }

    public User(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        System.out.println("第二步,set方法开始执行");
    }

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

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

    public void destroy(){
        System.out.println("最后一步,销毁方法执行");
    }
}
<bean id="user" class="life.domain.User" init-method="initialize" destroy-method="destroy">
        <property name="name" value="123"/>
    </bean>

但是当我们添加了后置处理器之后MyPostProcessor,就会添加两个步骤

package life.postprocessor;

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

/**
 * @Descirption:
 * @create 2022-03-09 17:06
 * @auther: wgy
 */
// 后置处理器,实现此接口后,spring所有的bean都会经过他
public class MyPostProcessor 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配置文件注册后置处理器,注册之后会对每一个bean进行处理

<!--配置后置处理器-->
    <bean id="MyPostProcessor" class="life.postprocessor.MyPostProcessor"/>

所以最后的步骤是7步

(1)通过构造器创建 bean 实例(无参数构造)

(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)

(3)调用 bean 的初始化的方法(需要进行配置初始化的方法)

(4)后置处理器 postProcessBeforeInitialization方法

(5)bean 可以使用了(对象获取到了)

(6)后置处理器postProcessAfterInitialization方法

(7)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)

bean自动装配

<!--实现自动装配
     bean 标签属性 autowire,配置自动装配
     autowire 属性常用两个值:
         byName 根据属性名称注入 ,注入值 bean 的 id 值和类属性名称一样
         byType 根据属性类型注入
    -->
    <bean id="emp" class="autowire.domain.Emp" autowire="byName"></bean>

    <bean id="dep" class="autowire.domain.Dep"/>

读取外部文件

导入Druid依赖和mysql依赖

<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.8</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>

bean.xml配置

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

    <!-- 配置连接池 -->
    <!-- DruidDataSource dataSource = new DruidDataSource(); -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <!-- dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            set方法注入
        -->
        <!-- 获取properties文件内容,根据key获取,使用spring表达式获取 -->
        <property name="driverClassName" value="${jdbc.driverclass}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>

什么是DI ?

di(依赖注入):简单理解成,将我们需要的类添加到spring容器里面,给调用者去调用。

(可以理解成新建的澡堂,只有水池啥也没有,然后政府批钱下来了,负责人开始发布招聘信息。一些有才能的人按摩,搓澡,采耳的人都来到了澡堂应聘。这样一来来搓澡的人就可以自由选择自己需要的服务了)

注入的条件?

必须满足:

1.属性有set方法 : spring容器通过调用无参构造器或者静态工厂方法实例化bean后,会调用set属性将实例化的bean注入

2.构造方法注入 : spring容器通过构造方法注入被依赖的实例, 基于构造方法注入通过调用有参构造方法实现,每个参数代表一个依赖

1 . 定义一个接口,里面添加一个say()方法

package com.wu.ioc;

public interface UserService {

    void say();
}

2 . 实现一个接口实现类,实现say方法

package com.wu.ioc;

public class UserServiceImpl implements UserService {

    //声明一个对象
    private UserDao userDao;

    //提供给spring的注入方法
    public void setUserDao(UserDao userDao){
        this.userDao=userDao;
    }

    //实现接口的方法
    @Override
    public void say() {
        userDao.say();
        System.out.println("userserviceimpl hello world");
    }
}

3 . 配置文件如下

<bean id="userService" class="com.wu.ioc.UserServiceImpl">
        <property name="userDao" ref="userDao"/>
 </bean>

4 . 测试类

package com.wu.ioc;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestDI {

    public static void main(String[] args) {
        //初始化spring容器,加载配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //通过容器获得工厂的实例对象
        UserService userService= (UserService) context.getBean("userService");
        //调用实例中的方法
        userService.say();
    }
}

5 . 完成

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pJ6kMVHB-1650034961141)(初识spring.assets/1617765936987.png)]

全注解配置bean

(1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值…)

(2)使用注解,注解作用在类上面,方法上面,属性上面

(3)使用注解目的:简化 xml 配置

Spring 针对 Bean 管理中创建对象提供注解

(1)@Component

(2)@Service

(3)@Controller

(4)@Repository

* 上面四个注解功能是一样的,都可以用来创建 bean 实例

<!-- 扫描所有该文件下下的注解 -->
<context:component-scan base-package="com.wu"/>

 <!--只扫描带有controller注解的类
            use-default-filters 是否使用默认过滤 true全部扫描 false自定义扫描
        -->
 <context:component-scan base-package="com.wu" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

 <!--不扫描带有controller注解的类-->
<context:component-scan base-package="com.wu" >
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

Autowired:根据属性类型进行自动装配

Qualifier: 根据名字匹配 可以和Autowired搭配使用

Resource:可以根据类型注入,可以根据名称注入

Value:注入普通类型属性

@Controller
public class UserController {

    @Autowired //根据类型自动匹配
    @Qualifier(value = "userService") //根据名称进行注入
    private UserService userService;

    @Value("123")
    public String key;

    public void add(){
        userService.add();
    }
}


@Service   //默认按照类名首字母小写注入
public class UserService {

    //@Resource //根据类型进行注入
    @Resource(name = "userDao") //根据名称进行注入
    private UserDao userDao;

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

配置类代替配置文件

@Configuration  //声明这是一个配置类
@ComponentScan(basePackages = {"com.wu"}) //配置扫描包
public class SpringConfig {
}

测试方法
     @Test
    public void TestBean3(){
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);

        UserController userController = (UserController) applicationContext.getBean("userController");
        userController.add();
        System.out.println(userController.key);
    }

什么是aop?

(1)面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得

业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

(2)通俗描述:不通过修改源代码方式,在主干功能里面添加新功能

举个例子 现在我写了一个登录的业务但是,这个系统给每一个登录的用户都设有权限.怎么样才能在访问指定资源的时候进行权限的认证.这个时候我们就可以采用aop来实现权限认证.这样不会对原来的业务进行改变.同时完成需求

aop底层原理

1,有接口的情况下,使用jdk动态代理(创建接口的实现类代理对象)

2,没有接口的情况下,使用cglib动态代理(创建当前类的子类代理对象)

使用 JDK 动态代理,使用 Proxy 类里面的方法创建代理对象

调用newProxyInstance方法

方法有三个参数:

第一参数,类加载器

第二参数,增强方法所在的类,这个类实现的接口,支持多个接口

第三参数,实现这个接口 InvocationHandler,创建代理对象,写增强的部分

aopjdk事例

public interface UserDao {

    int add(int a,int b);

    String update(String id);
}

public class UserDaoImpl implements UserDao{
    @Override
    public int add(int a, int b) {
        return a+b;
    }

    @Override
    public String update(String id) {
        return "update方法"+id;
    }
}

public class UserDaoProxy implements InvocationHandler {

    //1 把创建的是谁的代理对象,把谁传递过来
    //有参数构造传递
    private Object obj;

    public UserDaoProxy(Object obj) {
        this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //方法之前
        System.out.println("方法之前执行...." + method.getName() + " :传递的参..." + Arrays.toString(args));
        //被增强的方法执行
        Object res = method.invoke(obj, args);
        //方法之后
        System.out.println("方法之后执行...." + obj);
        return res;
    }
}

public class JDKProxy {

    public static void main(String[] args) {
        // 获取所有需要代理的对象
        Class[] interfaces = {UserDao.class};

        UserDaoImpl userDao = new UserDaoImpl();

        UserDao userDao1 = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));

        userDao1.add(1,2);
        userDao1.update("1");
    }
}

aop术语

1,连接点

类里面的那些方法可以被增强,这些方法就叫做连接点

2,切入点

实际被增强的方法

3,通知

1,增强的逻辑部分被称为通知

2,通知的种类

前置通知,后置通知,环绕通知,异常通知,最终通知

4,切面

把通知应用到切点的动作

AspectJ实现aop

AspectJ 不是 Spring 组成部分,独立 AOP 框架,一般把 AspectJ 和 Spirng 框架一起使

用,进行 AOP 操作

(1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强

(2)语法结构: execution([权限修饰符] [返回类型] [类全路径] 方法名称 )

举例 1:对 com.atguigu.dao.BookDao 类里面的 add 进行增强

execution(* com.atguigu.dao.BookDao.add(…))

举例 2:对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强

execution(* com.atguigu.dao.BookDao.* (…))

举例 3:对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强

execution(* com.atguigu.dao.. (…))

注解实现aop

@Component
public class User {

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

@Component
@Aspect
@Order(1) // 数字越小优先级越高
public class UserProxy {

    // 提取一个公共切点
    @Pointcut(value = "execution(* aopanno.User.add(..))")
    public void pointdemo() {
    }

    //@Before 注解表示作为前置通知
    @Before(value = "pointdemo()")
    public void before() {
        System.out.println("before.........");
    }
    //后置通知(返回通知)
    @AfterReturning(value = "execution(* aopanno.User.add(..))")
    public void afterReturning() {
        System.out.println("afterReturning.........");
    }
    //最终通知
    @After(value = "execution(* aopanno.User.add(..))")
    public void after() {
        System.out.println("after.........");
    }
    //异常通知
    @AfterThrowing(value = "execution(* aopanno.User.add(..))")
    public void afterThrowing() {
        System.out.println("afterThrowing.........");
    }
    //环绕通知
    @Around(value = "execution(* aopanno.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws
            Throwable {
        System.out.println("环绕之前.........");
        //被增强的方法执行
        proceedingJoinPoint.proceed();
        System.out.println("环绕之后.........");
    }
}


@Configuration
@ComponentScan(basePackages = {"aopanno"})
@EnableAspectJAutoProxy(proxyTargetClass = true) // 开启aop支持
public class AopConfig {
}
<?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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    <context:component-scan base-package="aopanno"/>

    <!-- 开启 Aspect 生成代理对象-->
    <aop:aspectj-autoproxy/>
</beans>

xml实现aop

@Component
public class Book {

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

public class BookProxy {

    @Before(value = "execution(* aopxml.Book.add(..))")
    public void before() {
        System.out.println("before.........");
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns: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/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="book" class="aopxml.Book"/>
    <bean id="bookProxy" class="aopxml.BookProxy"/>

    <!--配置aop-->
    <aop:config>
        <!--切入点(需要增强的类方法)-->
        <aop:pointcut id="p" expression="execution(* aopxml.Book.add(..))"/>
        <!--配置切面(增强的类)-->
        <aop:aspect ref="bookProxy">
            <aop:before method="before" pointcut-ref="p"/>
        </aop:aspect>
    </aop:config>
</beans>

spring整合jdbc

导入依赖

<dependencies>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.8</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
    </dependencies>

创建实体类

package com.wu.domain;

import lombok.*;

import java.io.Serializable;

/**
 * @Descirption:
 * @create 2022-03-28 15:58
 * @auther: wgy
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@EqualsAndHashCode
public class User implements Serializable {

    private Integer id;
    private String name;
    private String password;
    private String address;
    private String phone;

}

创建配置文件

<?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.wu"/>

    <!-- 数据库连接池 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
          destroy-method="close">
        <property name="url" value="jdbc:mysql://localhost:3306/jdbc"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    </bean>

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




</beans>

dao层

package com.wu.dao;

import com.wu.domain.User;
import lombok.AllArgsConstructor;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * @Descirption:
 * @create 2022-03-28 16:03
 * @auther: wgy
 */
@Repository
@AllArgsConstructor
public class UserDao {

    // 添加配置好的jdbctemplate
    private final JdbcTemplate jdbcTemplate;

    // 添加
    public boolean addUser(User user) {
        Object[] args = {user.getName(), user.getPassword(), user.getAddress(), user.getPhone()};
        int update = jdbcTemplate.update("insert into user values(null,?,?,?,?)", args);
        return update > 0;
    }

    // 删除
    public boolean deleteUser(Integer id) {
        int update = jdbcTemplate.update("delete from user where id=?", id);
        return update > 0;
    }

    // 修改
    public boolean updateUser(User user) {
        Object[] args = {user.getName(), user.getPassword(), user.getAddress(), user.getPhone(), user.getId()};
        int update = jdbcTemplate.update("update user set name=?,password=?,address=?,phone=? where id=?", args);
        return update > 0;
    }

    // 查询多少条数据
    public int selectUserClount() {
        Integer count = jdbcTemplate.queryForObject("select count(*) from user", Integer.class);
        return count;
    }

    // 查询一条对象
    public User selectUserById(Integer id) {
        User user = jdbcTemplate.queryForObject("select * from user where id=?", new BeanPropertyRowMapper<User>(User.class), id);
        return user;
    }

    // 查询多条
    public List<User> selectUsers() {
        List<User> userList = jdbcTemplate.query("select * from user", new BeanPropertyRowMapper<User>(User.class));
        return userList;
    }

    // 批量修改
    public boolean batchUpdate(List<Object[]> args) {
        int[] ints = jdbcTemplate.batchUpdate("update user set name=?,password=?,address=?,phone=? where id=?", args);
        for (int anInt : ints) {
            if (anInt <= 0) return false;
        }
        return true;
    }

    // 批量删除
    public boolean batchDelete(List<Object[]> args) {
        int[] ints = jdbcTemplate.batchUpdate("delete from user where id=?", args);
        for (int anInt : ints) {
            if (anInt <= 0) return false;
        }
        return true;
    }

    // 批量添加
    public boolean batchAdd(List<Object[]> args) {
        int[] ints = jdbcTemplate.batchUpdate("insert into user values(null,?,?,?,?)", args);
        for (int anInt : ints) {
            if (anInt <= 0) return false;
        }
        return true;
    }
}

service层

package com.wu.service;

import com.wu.dao.UserDao;
import com.wu.domain.User;
import lombok.AllArgsConstructor;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @Descirption:
 * @create 2022-03-28 16:02
 * @auther: wgy
 */
@Service
@AllArgsConstructor
public class UserService {

    private final UserDao userDao;

    public Boolean addUser(User user) {
        return userDao.addUser(user);
    }

    public boolean deleteUser(Integer id) {
        return userDao.deleteUser(id);
    }

    public boolean updateUser(User user) {
        return userDao.updateUser(user);
    }

    public int selectUserCount(){
        return userDao.selectUserClount();
    }

    public User selectUserById(Integer id){
        return userDao.selectUserById(id);
    }

    public List<User> selectUsers(){
        return userDao.selectUsers();
    }

    public boolean batchUpdate(List<Object[]> args){
        return userDao.batchUpdate(args);
    }

    public boolean batchDelete(List<Object[]> args){
        return userDao.batchDelete(args);
    }

    public boolean batchAdd(List<Object[]> args) {
        return userDao.batchAdd(args);
    }
}

测试类

package com.wu.test;

import com.wu.domain.User;
import com.wu.service.UserService;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.ArrayList;
import java.util.List;

/**
 * @Descirption:
 * @create 2022-03-28 16:12
 * @auther: wgy
 */
public class JdbcTest {


    @Test
    public void test1() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");

        UserService userService = context.getBean("userService", UserService.class);

        User user = new User(null, "wgy", "123", "武汉", "123456789");

        System.out.println(userService.addUser(user));
    }

    @Test
    public void test2() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");

        UserService userService = context.getBean("userService", UserService.class);


        System.out.println(userService.deleteUser(6));
    }

    @Test
    public void test3() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");

        UserService userService = context.getBean("userService", UserService.class);

        User user = new User(7, "wgy", "456", "武汉", "123456789");

        System.out.println(userService.updateUser(user));
    }


    @Test
    public void test4() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");

        UserService userService = context.getBean("userService", UserService.class);


        System.out.println(userService.selectUserCount());
    }

    @Test
    public void test5() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");

        UserService userService = context.getBean("userService", UserService.class);


        System.out.println(userService.selectUserById(7));
    }

    @Test
    public void test6() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");

        UserService userService = context.getBean("userService", UserService.class);


        List<User> userList = userService.selectUsers();

        userList.forEach(System.out::println);
    }


    @Test
    public void test7() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");

        UserService userService = context.getBean("userService", UserService.class);


        Object[] obj1 = {"json", "123456", "usa", "123456", "4"};
        Object[] obj2 = {"wgy", "123456", "wl", "123456", "5"};
        List<Object[]> objects = new ArrayList<>();
        objects.add(obj1);
        objects.add(obj2);

        System.out.println(userService.batchUpdate(objects));
    }

    @Test
    public void test8() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");

        UserService userService = context.getBean("userService", UserService.class);


        Object[] obj1 = {"4"};
        Object[] obj2 = {"5"};
        List<Object[]> objects = new ArrayList<>();
        objects.add(obj1);
        objects.add(obj2);

        System.out.println(userService.batchDelete(objects));
    }

    @Test
    public void test9() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");

        UserService userService = context.getBean("userService", UserService.class);


        Object[] obj1 = {"json", "123456", "usa", "123456"};
        Object[] obj2 = {"wgy", "123456", "wl", "123456"};
        List<Object[]> objects = new ArrayList<>();
        objects.add(obj1);
        objects.add(obj2);

        System.out.println(userService.batchAdd(objects));
    }
}

spring整合事务

1、什么事务

(1)事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败所有操

作都失败

(2)典型场景:银行转账

* lucy 转账 100 元 给 mary

* lucy 少 100,mary 多 100

2、事务四个特性(ACID)

(1)原子性

(2)一致性

(3)隔离性

(4)持久性

操作事务

1,事务添加到 JavaEE 三层结构里面 Service 层(业务逻辑层)

2, Spring 进行事务管理操作

(1)有两种方式:编程式事务管理和声明式事务管理(使用)

3,声明式事务管理

**(**1)基于注解方式(使用)

(2)基于 xml 配置文件方式

4, 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


@Transactional注解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XE76NEiO-1650034961143)(初识spring.assets/1649084389017.png)]

propagation:事务传播行为

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fAkzzIUY-1650034961144)(初识spring.assets/1649084427922.png)]

ioslation:事务隔离级别

(1)事务有特性成为隔离性,多事务操作之间不会产生影响。不考虑隔离性产生很多问题

(2)有三个读问题:脏读、不可重复读、虚(幻)读

(3)脏读:一个未提交事务读取到另一个未提交事务的数据

(4)不可重复读:一个未提交事务读取到另一提交事务修改数据

(5)幻读:一个未提交事务读取到另一提交事务添加数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KUOtZcRL-1650034961146)(初识spring.assets/1649084634451.png)]

timeout:超时时间

(1)事务需要在一定时间内进行提交,如果不提交进行回滚

(2)默认值是 -1 ,设置时间以秒单位进行计算

readOnly:是否只读

(1)读:查询操作,写:添加修改删除操作

(2)readOnly 默认值 false,表示可以查询,可以添加修改删除操作

(3)设置 readOnly 值是 true,设置成 true 之后,只能查询

rollbackFor:回滚

(1)设置出现哪些异常进行事务回滚

noRollbackFor:不回滚

(1)设置出现哪些异常不进行事务回滚

开启事务-xml版(前提导入数据源)

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

    <!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--2 配置通知-->
    <tx:advice id="txadvice">
        <!--配置事务参数-->
        <tx:attributes>
            <!--指定哪种规则的方法上面添加事务-->
            <tx:method name="accountMoney" propagation="REQUIRED"/>
            <!--<tx:method name="account*"/>-->
        </tx:attributes>
    </tx:advice>

    <!--3 配置切入点和切面-->
    <aop:config>
        <!--配置切入点-->
        <aop:pointcut id="pt" expression="execution(* com.wu.service.UserService.*(..))"/>
        <!--配置切面-->
        <aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
    </aop:config>

spring5新特性

1,log4j

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后面的status用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,可以看到log4j2内部各种详细输出-->
<configuration status="INFO">
    <!--先定义所有的appender-->
    <appenders>
        <!--输出日志信息到控制台-->
        <console name="Console" target="SYSTEM_OUT">
            <!--控制日志输出的格式-->
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </console>
    </appenders>
    <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
    <!--root:用于指定项目的根日志,如果没有单独指定Logger,则会使用root作为默认的日志输出-->
    <loggers>
        <root level="info">
            <appender-ref ref="Console"/>
        </root>
    </loggers>
</configuration>

pox.xml

<dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.25</version>
        </dependency>

测试用例

package log;

import org.apache.log4j.Logger;

/**
 * @Descirption:
 * @create 2022-04-15 11:20
 * @auther: wgy
 */
public class TestLog {

    // 日志
    private static Logger logger = Logger.getLogger(TestLog.class);

    public static void main(String[] args) {
        logger.info("info");
        logger.debug("debug");
        logger.error("error");
    }
}

2,@Nullable

public class TestNullAble {

    // 属性可以为null
    @Nullable
    private String name;

    // 返回值可以为null
    @Nullable
    public String get(){
        return "123";
    }

    // 方法参数可以为null
    public String getHello(@Nullable String name){
        return "123";
    }
}

3,函数声明注册bean

// 函数式注册bean进入spring容器
    @Test
    public void testBean(){
        //1 创建 GenericApplicationContext 对象
        GenericApplicationContext context = new GenericApplicationContext();
        //2 调用 context 的方法对象注册
        context.refresh();
        context.registerBean("user1",User.class,() -> new User());
        //3 获取在 spring 注册的对象
        // User user = (User)context.getBean("com.atguigu.spring5.test.User");
        User user = (User)context.getBean("user1");
        System.out.println(user);
    }

4,junt4整合

pom.xml

<dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
@RunWith(SpringJUnit4ClassRunner.class) //单元测试框架
@ContextConfiguration("classpath:bean1.xml") //加载配置文件
public class TestJuint4 {

    // 可以在内部对象注入等
}

4,junt5整合

pox.xml

<dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.7.0</version>
        </dependency>
@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath:bean1.xml")

// 复合注解
//@SpringJUnitConfig(locations = "classpath:bean1.xml")
public class TestJunt5 {
}

spring-webflux

1,是 Spring5 添加新的模块,用于 web 开发的,功能和 SpringMVC 类似的,Webflux 使用

当前一种比较流程响应式编程出现的框架。**

2,使用传统 web 框架,比如 SpringMVC,这些基于 Servlet 容器,Webflux 是一种异步非阻

塞的框架,异步非阻塞的框架在 Servlet3.1 以后才支持,核心是基于 Reactor 的相关 API 实现

3,解释什么是异步非阻塞

* 异步和同步

* 非阻塞和阻塞

**** 上面都是针对对象不一样**

** 异步和同步针对调用者,调用者发送请求,如果等着对方回应之后才去做其他事情就是同

步,如果发送请求之后不等着对方回应就去做其他事情就是异步

**** 阻塞和非阻塞针对被调用者,被调用者受到请求之后,做完请求任务之后才给出反馈就是阻**

塞,受到请求之后马上给出反馈然后再去做事情就是非阻塞

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

第二 函数式编程:Spring5 框架基于 java8,Webflux 使用 Java8 函数式编程方式实现路由请求

响应式编程

响应式编程(Reactor实现)

(1)响应式编程操作中,Reactor 是满足 Reactive 规范框架

(2)Reacto有两个核心类,Mono 和 Flux,这两个类实现接口Publisher,提供丰富操作

符。Flux 对象实现发布者,返回 N 个元素;Mono实现发布者,返回 0 或者 1 个元素

(3)Flux 和 Mono 都是数据流的发布者,使用 Flux 和 Mono 都可以发出三种数据信号:

元素值,错误信号,完成信号,错误信号和完成信号都代表终止信号,终止信号用于告诉

订阅者数据流结束了,错误信号终止数据流同时把错误信息传递给订阅者

三种信号特点

* 错误信号和完成信号都是终止信号,不能共存的

* 如果没有发送任何元素值,而是直接发送错误或者完成信号,表示是空数据流

* 如果没有错误信号,没有完成信号,表示是无限数据流

调用 just 或者其他方法只是声明数据流,数据流并没有发出,只有进行订阅之后才会触

发数据流,不订阅什么都不会发生的

操作符

对数据流进行一道道操作,成为操作符,比如工厂流水线

SpringWebflux 基于 Reactor,默认使用容器是 Netty,Netty 是高性能的 NIO 框架,异步非阻

塞的框架

SpringWebflux 执行过程和 SpringMVC 相似的

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

* 接口 WebHandler 有一个方法

SpringWebflux 里面 DispatcherHandler,负责请求的处理

* HandlerMapping:请求查询到处理的方法

* HandlerAdapter:真正负责请求处理

* HandlerResultHandler:响应结果处理

SpringWebflux 实现函数式编程,两个接口:RouterFunction(路由处理)

和 HandlerFunction(处理函数)

SpringMVC 方式实现,同步阻塞的方式,基于 SpringMVC+Servlet+Tomcat

SpringWebflux 方式实现,异步非阻塞 方式,基于 SpringWebflux+Reactor+Netty

注解实现

SpringWebflux 实现方式有两种:注解编程模型和函数式编程模型

使用注解编程模型方式,和之前 SpringMVC 使用相似的,只需要把相关依赖配置到项目中,

SpringBoot 自动配置相关运行容器,默认情况下使用 Netty 服务器

pom.xml依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wu</groupId>
    <artifactId>spring5-webflux</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring5-webflux</name>
    <description>spring5-webflux</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <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>io.projectreactor</groupId>
            <artifactId>reactor-core</artifactId>
            <version>3.4.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

controller

@RestController
public class UserController {

    //SpringMVC 方式实现,同步阻塞的方式,基于 SpringMVC+Servlet+Tomcat
    //SpringWebflux 方式实现,异步非阻塞 方式,基于 SpringWebflux+Reactor+Netty

    //注入 service
    @Autowired
    private UserService userService;

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

    //查询所有
    @GetMapping("/user")
    public Flux<User> getUsers() {
        return userService.getAllUser();
    }

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

service

public interface UserService {

    // 通过id查找用户
    Mono<User> getUserById(Integer id);

    // 查询所有用户
    Flux<User> getAllUser();

    // 添加用户
    Mono<Void> saveUserInfo(Mono<User> user);
}

@Service
public class UserServiceImpl implements UserService {

    //创建 map 集合存储数据
    private final List<User> users = new ArrayList<>();

    public UserServiceImpl() {
        this.users.add(new User(1, "nan", 20));
        this.users.add(new User(2, "nv", 30));
        this.users.add(new User(3, "nv", 50));
    }

    @Override
    public Mono<User> getUserById(Integer id) {
        return Mono.justOrEmpty(this.users.stream().filter(user -> user.getId().equals(id)).findFirst().orElse(null));
    }

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

    @Override
    public Mono<Void> saveUserInfo(Mono<User> user) {
        //向 map 集合里面放值
        return user.doOnNext(this.users::add).thenEmpty(Mono.empty());
    }
}

domain

private Integer id;
    private String name;
    private Integer age;

函数式实现

(1)在使用函数式编程模型操作时候,需要自己初始化服务器

(2)基于函数式编程模型时候,有两个核心接口:RouterFunction(实现路由功能,请求转发

给对应的 handler)和 HandlerFunction(处理请求生成响应的函数)。核心任务定义两个函数

式接口的实现并且启动需要的服务器。

( 3 ) SpringWebflux 请 求 和 响 应 不 再 是 ServletRequest 和 ServletResponse ,而是

ServerRequest 和 ServerResponse

pom.xml同上不变

创建handler

package com.wu.spring5webflux2.handler;


import com.wu.spring5webflux2.domain.User;
import com.wu.spring5webflux2.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;

/**
 * @Descirption:
 * @create 2022-04-15 22:01
 * @auther: wgy
 */
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.parseInt(request.pathVariable("id"));
        //空值处理
        Mono<ServerResponse> notFound = ServerResponse.notFound().build();
        //调用 service 方法得到数据
        Mono<User> userMono = this.userService.getUserById(userId);
        //把 userMono 进行转换返回
        //使用 Reactor 操作符 flatMap
        return userMono.flatMap(person ->
                        ServerResponse.ok().contentType(MediaType.APPLICATION_JSON)
                                .body(fromObject(person)))
                .switchIfEmpty(notFound);
    }

    //查询所有
    public Mono<ServerResponse> getAllUsers(ServerRequest request) {
        //调用 service 得到结果
        Flux<User> users = this.userService.getAllUser();
        return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(users, User.class);
    }

    //添加
    public Mono<ServerResponse> saveUser(ServerRequest request) {
        //得到 user 对象
        Mono<User> userMono = request.bodyToMono(User.class);
        return ServerResponse.ok().build(this.userService.saveUserInfo(userMono));
    }

}

service和domain直接复制不变

创建server

package com.wu.spring5webflux2;

import com.wu.spring5webflux2.handler.UserHandler;
import com.wu.spring5webflux2.service.UserService;
import com.wu.spring5webflux2.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.GET;
import static org.springframework.web.reactive.function.server.RequestPredicates.accept;
import static org.springframework.web.reactive.function.server.RouterFunctions.toHttpHandler;

/**
 * @Descirption:
 * @create 2022-04-15 22:29
 * @auther: wgy
 */
public class Server {

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


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


    //2 创建服务器完成适配
    public void createReactorServer() {
        //路由和 handler 适配
        RouterFunction<ServerResponse> route = routingFunction();
        HttpHandler httpHandler = toHttpHandler(route);
        ReactorHttpHandlerAdapter adapter = new
                ReactorHttpHandlerAdapter(httpHandler);
        //创建服务器
        HttpServer httpServer = HttpServer.create();
        httpServer.handle(adapter).bindNow();
    }
}

().build(this.userService.saveUserInfo(userMono));
}

}

service和domain直接复制不变



创建server

```java
package com.wu.spring5webflux2;

import com.wu.spring5webflux2.handler.UserHandler;
import com.wu.spring5webflux2.service.UserService;
import com.wu.spring5webflux2.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.GET;
import static org.springframework.web.reactive.function.server.RequestPredicates.accept;
import static org.springframework.web.reactive.function.server.RouterFunctions.toHttpHandler;

/**
 * @Descirption:
 * @create 2022-04-15 22:29
 * @auther: wgy
 */
public class Server {

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


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


    //2 创建服务器完成适配
    public void createReactorServer() {
        //路由和 handler 适配
        RouterFunction<ServerResponse> route = routingFunction();
        HttpHandler httpHandler = toHttpHandler(route);
        ReactorHttpHandlerAdapter adapter = new
                ReactorHttpHandlerAdapter(httpHandler);
        //创建服务器
        HttpServer httpServer = HttpServer.create();
        httpServer.handle(adapter).bindNow();
    }
}

``跟着尚硅谷学习写的笔记,啥也不说了尚硅谷yyds