Java每日面试题(Spring)(day19)
目录
- Spring的优点
- 什么是Spring AOP?
- AOP有哪些实现方式?
- JDK动态代理和CGLIB动态代理的区别?
- Spring AOP相关术语
- Spring通知有哪些类型?
- 什么是Spring IOC?
- Spring中Bean的作用域有哪些?
- Spring中的Bean什么时候被实例化?
- Spring中Bean的生命周期
- 依赖注入的方式
- @Autowired和@Resource有什么区别?
- @Component和@Bean的区别
- Bean 是线程安全的吗?
- 什么是事务?
- spring 事务的实现方式
- Spring 事务隔离级别
- Spring 事务传播属性
- Spring 事务在什么情况下会失效?
- Spring怎么解决循环依赖的问题?
- 什么是MVC?
- Spring MVC工作原理
- Spring Boot的优势
- Spring Boot自动装配原理
- 了解Spring Boot中的日志组件吗?
Spring的优点
- 通过控制反转和依赖注入实现松耦合。
- 支持面向切面的编程,并且把应用业务逻辑和系统服务分开。
- 支持声明式事务。
- 方便集成各种优秀框架。
- 方便程序的测试。
什么是Spring AOP?
AOP(Aspect-Oriented Programming),即面向切面编程,用人话说就是把公共的逻辑抽出来,让开发者可以更专注于业务逻辑开发,可以减少系统的重复代码和降低模块之间的耦合度。
切面就是那些与业务无关,但所有业务模块都会调用的公共逻辑。
AOP有哪些实现方式?
AOP有两种实现方式:静态代理和动态代理。
-
静态代理:
代理类在编译阶段生成,在编译阶段将通知织入Java字节码中,也称编译时增强。AspectJ使用的是静态代理。
缺点:代理对象需要与目标对象实现一样的接口,并且实现接口的方法,会有冗余代码。同时,一旦接口增加方法,目标对象与代理对象都要维护。
-
动态代理:
代理类在程序运行时创建,AOP框架不会去修改字节码,而是在内存中临时生成一个代理对象,在运行期间对业务方法进行增强,不会生成新类。
JDK动态代理和CGLIB动态代理的区别?
Spring AOP中的动态代理主要有两种方式:JDK动态代理和CGLIB动态代理。
- JDK 动态代理 依赖于 反射机制来创建代理,适用于实现接口的情况。
- CGLib 动态代理 通过字节码生成技术创建子类来实现代理,适用于没有实现接口的类。
Spring AOP相关术语
术语 | 含义 |
---|---|
目标(Target) | 被通知的对象 |
代理(Proxy) | 向目标对象应用通知之后创建的代理对象 |
连接点(JoinPoint) | 目标对象的所属类中,定义的所有方法均为连接点 |
切入点(Pointcut) | 被切面拦截 / 增强的连接点 (切入点一定是连接点,连接点不一定是切入点) |
通知(Advice) | 增强的逻辑 / 代码,也即拦截到目标对象的连接点之后要做的事情 |
切面(Aspect) | 切入点(Pointcut)+通知(Advice) |
Weaving(织入) | 将通知应用到目标对象,进而生成代理对象的过程动作 |
Spring通知有哪些类型?
在AOP术语中,切面的工作被称为通知。通知实际上是程序运行时要通过Spring AOP框架来触发的代码段。
Spring切面可以应用5种类型的通知:
- 前置通知(Before):在目标方法被调用之前调用通知功能;
- 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么;
- 返回通知(After-returning ):在目标方法成功执行之后调用通知;
- 异常通知(After-throwing):在目标方法抛出异常后调用通知;
- 环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的逻辑
通知的执行顺序:
什么是Spring IOC?
IOC:控制反转,由Spring容器管理bean的整个生命周期。
通过反射实现对其他对象的控制,包括初始化、创建、销毁等,解放手动创建对象的过程,同时降低类之间的耦合度
- Spring IOC的实现机制:工厂模式+反射机制
Spring中Bean的作用域有哪些?
Bean的作用域:
singleton
:单例,Spring中的bean默认都是单例的。prototype
:原型,每次请求都会创建一个新的bean实例。- request:每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。
- session:每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP session内有效。
- application:全局session作用域。
Spring中的Bean什么时候被实例化?
- 单例作用域(Singleton):在 Spring 容器 启动 时,会立即实例化单例作用域的 Bean,将它们存储在容器的 Bean 工厂中,以便随时获取。
- 原型作用域(Prototype):在 请求 获取原型作用域的 Bean 时,Spring 容器才会实例化该 Bean,并返回给请求方。
- 其他作用域:如 Web 作用域和 Session 作用域等,它们的实例化时间依赖于具体的使用场景。
Spring中Bean的生命周期
Bean生命周期可以粗略的划分为五大步:
- 第一步:实例化Bean
- 第二步:Bean属性赋值
- 第三步:初始化Bean
- 第四步:使用Bean
- 第五步:销毁Bean
依赖注入的方式
在 Spring 中实现依赖注入的常见方式有以下 3 种:
- 属性注入(Field Injection)
- @Autowire实现属性注入
- @Resurce实现属性注入
- Set方法注入(Setter Injection)
- 构造方法注入(Constructor Injection)
@Autowired和@Resource有什么区别?
-
Autowired
是Spring提供的;Resource
是J2EE提供的 -
Resource
默认使用name装配,未指定name时,会按类型装配 -
AutoWired
按类型装配,如果要使用名称装配可以用@Qualifier结合使用
@Component和@Bean的区别
-
@Component 注解用在类上,表明一个类会作为组件类,并告知Spring要为这个类创建bean,每个类对应一个 Bean。
-
@Bean 注解用在方法上,表示这个方法会返回一个 Bean。
-
@Bean 注解更加灵活,相比 @Component 注解自定义性更强
Bean 是线程安全的吗?
Spring 框架中的 Bean 是否线程安全,取决于其作用域和状态。
-
prototype
作用域下,每次获取都会创建一个新的 bean 实例,不存在资源竞争问题,所以不存在线程安全问题。 -
singleton
作用域下,IoC 容器中只有唯一的 bean 实例,可能会存在资源竞争问题(取决于 Bean 是否有状态)。- 有状态Bean(包含可变的成员变量的对象),存在线程安全问题。
- 无状态Bean(没有定义可变的成员变量,比如dao和service),不能保存数据,是线程安全的。
什么是事务?
事务是一个操作序列,要么全部执行成功,要么全部执行失败。事务有四个重要特性,称为 ACID
特性:
- Atomicity(原子性):事务中的所有操作要么全部完成,要么全部不完成。
- Consistency(一致性):事务完成后,数据要处于一致的状态。
- Isolation(隔离性):一个事务的执行不能被其他事务干扰。
- Durability(持久性):事务完成后,数据应该永久保存
补充:
undo_log
表保证事务 原子性(A) 和 一致性(C )redo_log
表保证事务 持久性(D)- 隔离级别 保证事务 隔离性(I)
spring 事务的实现方式
Spring事务机制主要包括声明式事务和编程式事务。
- **编程式事务:通过编程的方式管理事务,手动去开启、提交、回滚事务、这种方式带来了很大的灵活性,但很难维护。
- 声明式事务:将事务管理代码从业务方法中分离出来,通过aop进行封装。Spring声明式事务使得我们无需要去处理获得连接、关闭连接、事务提交和回滚等这些操作。使用 @Transactional 注解开启声明式事务。
Spring 事务隔离级别
-
读未提交(read Uncommited)
在该隔离级别,所有的事务都可以读取到别的事务中未提交的数据,会产生脏读问题,在项目中基本不怎么用, 安全性太差;脏读:所谓的脏读,其实就是读到了别的事务回滚前的脏数据。比如事务B执行过程中修改了数据X,在未提交前,事务A读取了X,而事务B却回滚了,这样事务A就形成了脏读。
也就是说,当前事务读到的数据是别的事务想要修改成为的但是没有修改成功的数据。 -
读已提交(read commited)
处于READ COMMITTED
级别的事务可以看到其他事务对数据的修改。也就是说,在事务处理期间,如果其他事务修改了相应的数据,那么同一个事务的多个 SELECT 语句可能返回不同的结果。在一个事务内,能看到别的事务提交的数据。出现 不可重复读。不可重复读:事务A首先读取了一条数据,然后执行逻辑的时候,事务B将这条数据改变 了,然后事务A再次读取的时候,发现 数据不匹配,就是所谓的不可重复读了。
-
可重复读(Repeatable read)
这是 MySQL 的默认隔离级别,它确保了一个事务中多个实例在并发读取数据的时候会读取到一样的数据;不过理论上,这会导致另一个棘手的问题:幻读 。幻读:事务A首先根据条件索引得到N条数据,然后事务B改变了这N条数据之外的M条或者增添了M条符合事务A搜索条件的数据,导致事务A再次搜索发现有N+M条数据了,就产生了幻读,简单来说就是突然多了几行数据。
为了解决幻读问题,MySQL引入了两种不同的MVCC实现方式:基于快照的MVCC 和 基于原始行的MVCC。
- 基于快照的MVCC:该方式会为每个事务创建一个快照,事务开始时记录数据库的当前版本号,当事务再次访问该行数据时,会检查当前版本号是否与快照版本号一致,如果不一致则会进行回滚或重新读取数据。
- 基于原始行的MVCC:该方式会为每行数据创建一个版本链表,每次更新操作都会创建一个新的版本号,并将旧版本号链接到新版本号上。当事务需要读取数据时,会检查当前版本号是否在版本链表中,如果在则读取最新版本的数据,避免幻读问题。
-
可串行化
有效避免“脏读”、“不可重复读”、“幻读”,不过效率特别低。
不可重复读和幻读比较:
- 不可重复读 针对的是
update
或delete
,是由于数据发生改变导致的- 幻读 针对的
insert
,是由于行数发生改变导致的。
Spring 事务传播属性
记忆方法:
-
两个
REQUIRED
:一定有事务- 带NEW:总是自己建自己的事务。
- 不带NEW:有就加入,没有才建。
-
两个
SUPPORTS
- 带NOT:直接不用。
- 不带NOT:有就用,没有就拉到。
-
MANDATORY
:强制的意思,必须用,语气强烈,没有就异常。 -
NEVER
:从不,就不用,语气强烈,有就异常。 -
NESTED
:嵌套的意思,有,建嵌套事务。没有,新建普通事务。
Spring 事务在什么情况下会失效?
-
非
public
修饰的方法 -
自调用(Self-Invocation)
自调用指的是一个类的方法在调用同一个类的另一个方法,事务管理会失效。
-
数据库不支持事务
MySQL中,MyISAM引擎不支持事物,InnoDB 支持事物 -
异常类型不匹配
@Transactional 注解默认只管理运行时异常(如RuntimeException及其子类)和错误(如Error)。 -
传播属性设置不当导致不走事务
@Transactional 默认的事务传播机制是:REQUIRED
,若指定成了NOT_SUPPORTED
、NEVER
事务传播机制,则事物不生效 -
捕获异常未抛出
-
Bean没有纳入Spring IOC容器管理
-
事务方法内启动新线程进行异步操作
Spring怎么解决循环依赖的问题?
-
对于构造器注入的循环依赖,Spring处理不了,会直接抛出
BeanCurrentlylnCreationException
异常。 -
对于属性注入的循环依赖(单例模式下),是通过三级缓存处理来循环依赖的。
-
对于非单例对象的循环依赖,无法处理。
什么是MVC?
MVC是指Model-View-Controller
,是一种软件设计模式,它将应用程序分为三个部分:模型、视图和控制器
MVC模式的核心思想是将应用程序的表示(视图)和处理(控制器)分离开来,从而使得应用程序更加灵活、易于维护和扩展。这种模式可以提高代码的可读性和可维护性,同时也可以促进代码的复用和分工,使得多人协作开发变得更加容易
Spring MVC工作原理
Spring MVC 原理如下图所示:
- 流程说明(重要):
- 客户端(浏览器)发送请求, DispatcherServlet拦截请求。
- DispatcherServlet 根据请求信息调用 HandlerMapping 。 HandlerMapping 根据 URL 去匹配查找能处理的 Handler(也就是我们平常说的 Controller 控制器) ,并会将请求涉及到的拦截器和 Handler 一起封装。
- DispatcherServlet 调用 HandlerAdapter适配器执行 Handler 。
- Handler 完成对用户请求的处理后,会 返回一个 ModelAndView 对象给DispatcherServlet,ModelAndView 顾名思义,包含了数据模型以及相应的视图的信息。Model 是返回的数据对象,View 是个逻辑上的 View。
- ViewResolver 会根据逻辑 View 查找实际的 View。
- DispaterServlet 把返回的 Model 传给 View(视图渲染)。
- 把 View 返回给请求者(浏览器)
Spring Boot的优势
- 约定大于配置:大家默认的一些约定可直接使用,无需配置
- 开箱即用:无需配置,直接可使用
- 内置tomcat
Spring Boot自动装配原理
Spring Boot自动装配如下图所示:
Springboot项目的启动类需要由 @SpringBootApplication 注解修饰,该注解复合了如下三个注解。
-
@SpringBootConfiguration。表明Springboot启动类是一个配置类;
-
@ComponentScan。会将指定路径下的被特定注解修饰的类加载为Spring中的Bean,这些特定注解为@Component,@Controller,@Service,@Repository和@Configuration注解;
-
@EnableAutoConfiguration。用于开启Springboot的自动装配,该注解复合了如下两个核心注解。
- @AutoConfigurationPackage。用于将启动类所在的包里面的所有组件注册到spring容器。
- @Import(AutoConfigurationImportSelector.class)。通过
AutoConfigurationImportSelector
类加载配置文件中配置的bean。
-
自动装配流程说明(重要):
- @Import 将 AutoConfigurationImportSelector 注入到spring容器中
- AutoConfigurationImportSelector 通过 SpringFactoriesLoader 从类路径下去读取
META-INF/spring.factories
文件信息 - 此文件中有一个key为
org.springframework.boot.autoconfigure.EnableAutoConfiguration
,定义了一组需要自动配置的bean
了解Spring Boot中的日志组件吗?
在Spring Boot中,日志组件的设计遵循了门面模式的概念。
在日志处理方面,Spring Boot使用SLF4J作为门面。
SLF4J是一个抽象层,它为Java平台上的多种日志框架提供了一个统一的接口。
使用时只需要调用api即可,不需要关注是哪个组件进行实现的
spring 默认使用的 logback
日志组件。
相关文章:

Java每日面试题(Spring)(day19)
目录 Spring的优点什么是Spring AOP?AOP有哪些实现方式?JDK动态代理和CGLIB动态代理的区别?Spring AOP相关术语Spring通知有哪些类型?什么是Spring IOC?Spring中Bean的作用域有哪些?Spring中的Bean什么时候…...

【多线程】线程池(上)
文章目录 线程池基本概念线程池的优点线程池的特点 创建线程池自定义线程池线程池的工作原理线程池源码分析内置线程池newFixedThreadPoolSingleThreadExecutornewCachedThreadPoolScheduledThreadPool 线程池的核心线程是否会被回收?拒绝策略ThreadPoolExecutor.AbortPolicyT…...

ansible 语句+jinjia2+roles
文章目录 1、when语句1、判断表达式1、比较运算符2、逻辑运算符3、根据rc的返回值判断task任务是否执行成功5、通过条件判断路径是否存在6、in 2、when和其他关键字1、block关键字2、rescue关键字3、always关键字 3、ansible循环语句1、基于列表循环(whith_items)2、基于字典循…...

【Docker项目实战】使用Docker部署HumHub社交网络平台
【Docker项目实战】使用Docker部署HumHub社交网络平台 一、HumHub介绍1.1 HumHub简介1.2 HumHub特点1.3 主要使用场景二、本次实践规划2.1 本地环境规划2.2 本次实践介绍三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本四、下载HumHub镜…...

“医者仁术”再进化,AI让乳腺癌筛查迎难而上
世卫组织最新数据显示,我国肿瘤疾病仍然呈上升趋势,肿瘤防控形势依然比较严峻。尤其是像乳腺癌等发病率较高的疾病,早诊断和早治疗意义重大,能够有效降低病死率。 另一方面,中国地域广阔且发展不平衡,各地…...

安卓流式布局实现记录
效果图: 1、导入第三方控件 implementation com.google.android:flexbox:1.1.0 2、布局中使用 <com.google.android.flexbox.FlexboxLayoutandroid:id"id/baggageFl"android:layout_width"match_parent"android:layout_height"wrap_co…...

-bash gcc command not found解决方案(CentOS操作系统)
以 CentOS7 为例,执行以下语句 : yum install gcc如果下载不成功,并且网络没有问题。 执行以下语句 : cp -r /etc/yum.repos.d /etc/yum.repos.d.bakrm -f /etc/yum.repos.d/*.repocurl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.…...

(二)Python输入输出函数
一、输入函数 input函数:用户输入的数据,以字符串形式返回;若需数值类型,则进行类型转换。 xinput("请入你喜欢的蔬菜:") print(x) 二、输出函数 print函数 输出单一数值 x666 print(x) 输出混合类型…...

从调用NCCL到深入NCCL源码
本小白目前研究GPU多卡互连的方案,主要参考NCCL和RCCL进行学习,如有错误,请及时指正! 内容还在整理中,近期不断更新!! 背景介绍 在大模型高性能计算时会需要用到多卡(GPU…...

深入理解Transformer的笔记记录(精简版本)NNLM → Word2Vec
文章的整体介绍顺序为: NNLM → Word2Vec → Seq2Seq → Seq2Seq with Attention → Transformer → Elmo → GPT → BERT 自然语言处理相关任务中要将自然语言交给机器学习中的算法来处理,通常需要将语言数学化,因为计算机机器只认数学符号…...

优选算法第一讲:双指针模块
优选算法第一讲:双指针模块 1.移动零2.复写零3.快乐数4.盛最多水的容器5.有效三角形的个数6.查找总价格为目标值的两个商品7.三数之和8.四数之和 1.移动零 链接: 移动零 下面是一个画图,其中,绿色部分标出的是重点: 代码实现&am…...

智能优化算法-水循环优化算法(WCA)(附源码)
目录 1.内容介绍 2.部分代码 3.实验结果 4.内容获取 1.内容介绍 水循环优化算法 (Water Cycle Algorithm, WCA) 是一种基于自然界水循环过程的元启发式优化算法,由Shah-Hosseini于2012年提出。WCA通过模拟水滴在河流、湖泊和海洋中的流动过程,以及蒸发…...

基于SpringBoot的个性化健康建议平台
1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及,互联网成为人们查找信息的重要场所,二十一世纪是信息的时代,所以信息的管理显得特别重要。因此,使用计算机来管理基于智能推荐的卫生健康系统的相关信息成为…...

Mapsui绘制WKT的示例
步骤 创建.NET Framework4.8的WPF应用在NuGet中安装Mapsui.Wpf 4.1.7添加命名空间和组件 <Window x:Class"TestMapsui.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winf…...

Modbus TCP 西门子PLC指令以太口地址配置以及 Poll Slave调试软件地址配置
1前言 本篇文章讲了 Modbus TCP通讯中的一些以太网端口配置和遇到的一些问题, 都是肝货自己测试的QAQ。 2西门子 SERVER 指令 该指令是让外界设备主动连接此PLC被动连接, 所以这里应该填 外界设备的IP地址。 这边 我因为是电脑的Modbus Poll 主机来…...

MySQL表的基本查询上
1,创建表 前面基础的文章已经讲了很多啦,直接上操作: 非常简单!下一个! 2,插入数据 1,全列插入 前面也说很多了,直接上操作: 以上插入和全列插入类似,全列…...

MySQL中什么情况下类型转换会导致索引失效
文章目录 1. 问题引入2. 准备工作3. 案例分析3.1 正常情况3.2 发生了隐式类型转换的情况 4. MySQL隐式类型转换的规则4.1 案例引入4.2 MySQL 中隐式类型转换的规则4.3 验证 MySQL 隐式类型转换的规则 5. 总结 如果对 MySQL 索引不了解,可以看一下我的另一篇博文&…...

数据治理的意义
数据治理是一套管理数据资产的流程、策略、规则和控制措施,旨在确保数据的质量、安全性、可用性和合规性。数据治理的目标通常包括但不限于以下几点: 1. **提高数据质量**:确保数据的准确性、一致性、完整性和可靠性。 2. **确保数据安全**…...

快手游戏服务端C++开发一面-面经总结
1、tcp的重传机制有哪几种?具体描述一下 最基本的超时重传 超过时间就会重传 三个重复ACK 快速重传 减少等待超时、 接收方可以发送选择性确认 不用重传整段 乱序到达 可以通知哪些丢失 重复数据重传 2、override和final? override可写可不写 写出来就…...

git的学习使用(认识工作区,暂存区,版本区。添加文件的方法)
学习目标: 学习使用git,并且熟悉git的使用 学习内容: 必备环境:xshell,Ubuntu云服务器 如下: 搭建 git 环境认识工作区、暂存区、版本区git基本操作之添加文件(1):gi…...

Series数据去重
目录 准备数据 Series数据去重 DataFrame数据和Series数据去重对比 在pandas中,Series.drop_duplicates(keep, inplace)方法用于删除Series对象中的重复值。 keep: 决定保留哪些重复值。可以取以下三个值之一: first(默认值&…...

Python语言核心12个必知语法细节
1. 变量和数据类型 Python是动态类型的,变量不需要声明类型。 python复制代码 a 10 # 整数 b 3.14 # 浮点数 c "Hello" # 字符串 d [1, 2, 3] # 列表 2. 条件语句 使用if, elif, else进行条件判断。 python复制代码 x 10 if x > 5: print(&q…...

解决ImageIO无法读取部分JPEG格式图片问题
解决ImageIO无法读取部分JPEG格式图片问题 问题描述 我最近对在线聊天功能进行了一些内存优化,结果在回归测试时,突然发现有张图片总是发送失败。测试同事把问题转到我这儿来看,我仔细检查了一下,发现是上传文件的接口报错&#…...

使用three.js 实现蜡烛效果
使用three.js 实现蜡烛效果 import * as THREE from "three" import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"var scene new THREE.Scene(); var camera new THREE.PerspectiveCamera(60, window.innerWidth / window.in…...

手动在Linux服务器上部署并运行SpringBoot项目(新手向)
背景 当我们在本地开发完应用并且测试通过后,接着就要部署在服务器上启动。 步骤 1.先用maven将SpringBoot应用当成jar包 2.生成jar文件并复制此文件 3.xshell远程连接linux服务器,在xftp将文件粘贴到linux服务器,这里我放在/usr/local…...

自媒体短视频如何制作?
从0到1打造爆款短视频!300条视频创作经验分享,助你玩转自媒体! 想用短视频玩转自媒体却不知道从何下手?别担心!从21年开始接触短视频的我,断断续续创作了300多条视频,踩过不少坑,也收获了一些心得,核心秘诀就是:账号内容垂直化 + 明确受众群体! 我将从主题确定、脚本…...

2024年河南省职业技能竞赛(网络建设与运维赛项)
模块二:网络建设与调试 说明: 1.所网络设备在创建之后都可以直接通过 SecureCRT 软件 telnet 远程连接操作。 2.要求在全员化竞赛平台中保留竞赛生成的所有虚拟主机。 3.题目中所有所有的密码均为 Pass-1234,若未按照要求设置,涉 …...

git--git reset
HEAD 单独一个HEAD eg:git diff HEAD 表示当前结点。 HEAD~ HEAD~只处理当前分支。 注意:master分支的上一个结点是tmp分支的所在的结点fc11b74, 79f109e才是master的第二个父节点。 HEAD~ 当前结点的父节点。 HEAD~1 当前结点的父节点。 HEAD~n 当前结点索…...

Spring Boot的实用内置功能详解
Spring Boot作为一款备受欢迎的Java框架,以其简洁、高效和易用的特点,赢得了广大开发者的青睐。其内置的多种功能更是为开发者提供了极大的便利,本文将详细介绍Spring Boot中记录请求数据、请求/响应包装器、特殊的过滤器Filter以及Controlle…...

撸猫变梳毛?怎么解决猫咪掉毛问题?好用的宠物空气净化器推荐
秋风一吹,新一轮的猫咪换毛季又到了,这也意味着我失去了撸猫自由。我每天的治愈方式就是下班撸猫,抚摸着柔软的毛发,好像一天的烦恼都消除了。可是一到换毛季,猫还没撸两下,先从猫咪身上带下一手毛…...