初识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