【Java面试】六、Spring框架相关

文章目录

  • 1、单例Bean不是线程安全的
  • 2、AOP
  • 3、Spring中事务的实现
  • 4、Spring事务失效的场景
    • 4.1 情况一:异常被捕获
    • 4.2 情况二:抛出检查异常
    • 4.3 注解加在非public方法上
  • 5、Bean的生命周期
  • 6、Bean的循环引用
  • 7、Bean循环引用的解决:Spring三级缓存
  • 8、构造方法出现循环依赖
  • 9、面试

1、单例Bean不是线程安全的

@Scope注解下,singleton表示Bean在IOC容器中只有一个实例,prototype则表示一个Bean可以有多个实例

在这里插入图片描述

但单例Bean不是线程安全的,Demo代码如下:线程1进来count被改成1,线程2进来,count被改成10,线程交替执行,就乱套了,单例Bean UserController就不线程安全

在这里插入图片描述
多个用户同时请求一个微服务,每个请求对应一个线程,如果并发的这段代码中,对单例的成员属性修改了,则存在线程安全问题。上面例子中,UserController这个Bean的成员属性count在被并发修改(存在可修改的成员变量),此时,单例的Bean不是线程安全的。相反,UserService的这个Bean,是不可变状态(不涉及其成员属性的修改),因此,UserService的这个单例Bean是线程安全的。

最后,补充一句,/getById/{id},id属于局部变量,更无线程安全问题了。

2、AOP

项目相关:做链路追踪埋点,采集所有接口的数据库层、Redis执行时间等信息,采用了AOP实现。

AOP,面向切面编程,将那些公共的逻辑代码,抽取封装,匹配要切入的点,实现统一加功能的操作。减少了系统的重复代码,提高了可维护性。其使用场景如自己做公共日志采集上报、Spring用来实现事务

在这里插入图片描述

3、Spring中事务的实现

Spring中,事务的实现可以编程式,也可以声明式。前者使用TransactionTemplate实现,对业务代码有侵入性。后者使用@Transactional注解。加注解实现事务,底层用的是AOP:

在这里插入图片描述
实现如上:切点表达式匹配@Transactional注解,使用环绕通知,执行前,加开启事务的代码,执行后,加提交事务的代码,出现异常,回滚事务。

4、Spring事务失效的场景

4.1 情况一:异常被捕获

如下:不加try-catch,发生异常后,事务回滚。加了try-catch,发生异常后,被catch捕获处理了。@Transactional对应的AOP没有收到异常,就会去提交事务。导致了异常后面的业务代码没执行,就会出现转账账户扣钱了,但被转账的用户余额不变的情况。

在这里插入图片描述

4.2 情况二:抛出检查异常

以下,读取的文件不存在,抛出了FileNotFound异常,但事务并不会回滚

在这里插入图片描述

因为Spring默认只会回滚非检查异常(RunTimeException),解决办法是,添加属性,指明事务回滚的异常种类,以下写法即只要发生异常就回滚:

@Transactional(rollbackFor=Exception.class)

4.3 注解加在非public方法上

在这里插入图片描述
Spring为方法创建代理,AOP添加事务通知的前提是:方法是public的,此时需要改为public方法

5、Bean的生命周期

首先,Spring容器将xml中的<bean>信息封装成一个个BeanDefinition对象(该接口的相关方法如下,可获取全类名、初始化方法、作用域,其中后面步骤的初始化,也是从这儿BeanDefition拿的方法名)

在这里插入图片描述
接下来:⇒

STEP1:实例化

  • 由BeanDefinition拿到构造方法,通过反射去拿到构造函数来(new Instance)实例化,拿到空对象,即纯净态的Bean
  • 当然实例化也可能是实例工厂、静态工厂等

STEP2:属性赋值

  • 解析自动装配(DI的体现),可byName、byType、constractor
  • 这里当然还有循环依赖的情况

STEP3:初始化

  • 调用那些XXXAware的回调方法
  • 调用初始化生命周期的回调方法(init-method)
  • 如果Bean涉及了AOP,还要为这个Bean创建动态代理

STEP4:销毁

  • 在Spring容器关闭的时候调用
  • 调用销毁生命周期的回调方法(destroy-method)

在这里插入图片描述

注意Bean前置处理器和Bean后置处理器的执行时机,是在Bean的init方法执行前后。一般来说,框架中,Bean创建动态代理,常用后置处理器,即实现BeanPostProcessor。代码验证下:

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Component
public class User implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean {

    public User() {
        System.out.println("User的构造方法执行了.........");
    }

    private String name ;

    @Value("张三")		//依赖注入
    public void setName(String name) {
        System.out.println("setName方法执行了.........");
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("setBeanName方法执行了.........");
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("setBeanFactory方法执行了.........");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("setApplicationContext方法执行了........");
    }

    @PostConstruct
    public void init() {
        System.out.println("init方法执行了.................");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet方法执行了........");
    }

    @PreDestroy
    public void destory() {
        System.out.println("destory方法执行了...............");
    }

}

关于前置处理器和后置处理器接口的实现:指定如果是user的Bean,就打印一句话。前面提到,框架中,Bean创建动态代理,常用后置处理器。下面就体现了模拟框架动态代理,给user这个Bean做cglib动态代理的效果:

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.InvocationHandler;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("user")) {
            System.out.println("postProcessBeforeInitialization方法执行了->user对象初始化方法前开始增强....");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("user")) {
            System.out.println("postProcessAfterInitialization->user对象初始化方法后开始增强....");
            //cglib代理对象
            Enhancer enhancer = new Enhancer();
            //设置需要增强的类
            enhancer.setSuperclass(bean.getClass());
            //执行回调方法,增强方法
            enhancer.setCallback(new InvocationHandler() {
                @Override
                public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                    //执行目标方法
                    return method.invoke(method,objects);
                }
            });
            //创建代理对象
            return enhancer.create();
        }
        return bean;
    }

}

效果:

在这里插入图片描述

6、Bean的循环引用

如下,A这个Bean创建时,依赖B这个Bean。而B这个Bean的创建,又依赖A这个Bean,即循环引用。有点死锁的感觉。

在这里插入图片描述
由Bean的生命周期可知,刚开始,从Beanfinition获取构造方法,反射拿到半成品的A这个Bean,即纯净态的Bean,此时,没有依赖注入,即b属性为null。

接下来,对A这个Bean进行初始化,需要依赖注入,设置b的属性,此时就需要从IoC容器中拿到B这个Bean。很明显,容器中没有,因此,去创建B这个Bean。

同A,纯净态的B,在实例化时,依赖注入,设置a的属性,发现需要A这个Bean。于是又走到了实例化A这条线路。到此,闭环了,走不出来了。

在这里插入图片描述

7、Bean循环引用的解决:Spring三级缓存

Spring框架已经帮开发者解决了大部分的循环引用 ⇒ 三级缓存(三个Map )

在这里插入图片描述

三个Map中存的分别是:单例已经走完全部流程的成熟态Bean、存半成品的Bean、对象工厂

在这里插入图片描述

一级缓存作用是:限制 bean 在 beanFactory 中只存一份,即实现 singleton scope。 仅靠它解决不了循环引用,还是会从1-6步一直循环:

在这里插入图片描述

引入二级缓存后,将原始对象A放入二级缓存,再去找B这个Bean。同理,B的原始对象也会先放入二级缓存。接下来B需要依赖注入A这个Bean时,会去从二级缓存中获取,然后B这个Bean创建成功,存储到一级缓存的单例池中,同时,将B在二级缓存中的半成品删掉。再回到造A的路上,将B从容器中注入到A,A也创建成功,将A在二级缓存中的半成品也删掉。

在这里插入图片描述

到此,一般对象之间的循环引用到二级缓存就解决了。但还有个场景,如果主要注入的A对象是个代理对象,则需要三级缓存:

在这里插入图片描述

8、构造方法出现循环依赖

Spring三级缓存解决了大部分的循环依赖(set注入时的循环依赖),但如果是构造方法的循环依赖,则需自己处理。如下写法,报错:Is there an unresolvable circular reference?

在这里插入图片描述
Bean的生命周期第一步,是通过BeanDefinition获取方法名,反射去拿到构造函数来(new Instance)实例化一个纯净态的Bean,还没到set依赖注入这一步(依赖注入的方式不是set方法,而是构造函数),就发现需要一个B这个Bean,同理B一开始执行构造方法就需要A这个Bean。此时Spring框架的三级缓存不能解决。需要加 @Lazy

在这里插入图片描述

9、面试

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/663943.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JS-51-Node.js10-yarn

一、yarn的简介 Yarn 是一款 JavaScript 的包管理工具&#xff08;npm的代替方案&#xff09;&#xff0c;是 Facebook, Google, Exponent 和 Tilde 开发的一款新的 JavaScript 包管理工具。 正如 Yarn 官网的介绍&#xff0c;Yarn 的具有速度快 、安全 、可靠 的优点&#x…

【机器学习】Transformer模型大小与性能探究

Transformer模型大小与性能&#xff1a;不仅仅是尺寸的问题 一、Transformer模型的挑战二、经验标度定律的局限性三、记忆过程与性能动态五、结论与展望 在人工智能和机器学习的领域里&#xff0c;模型的大小与性能之间的关系一直是研究人员关注的焦点。然而&#xff0c;最近的…

比较好的Python课程

最近在学习夜曲编程的Python进阶课程——办公效率化&#xff1b;夜曲编程之前有推出一款学习Python的入门课程&#xff0c;在手机端和电脑端都可以学习的&#xff0c;如果没有时间在手机端学习都很好的。每节课程学习下来&#xff0c;可以收集到Python入门的知识卡片&#xff0…

VNC server ubuntu20 配置

介绍 最近想使用实验室的4卡服务器跑一些深度学习实验&#xff0c;因为跑的是三维建图实验&#xff0c;需要配上可视化界面&#xff0c;本来自带的IPMI可以可视化&#xff0c;但分辨率固定在640*480&#xff0c;看起来很别扭&#xff0c;就捣鼓服务器远程可视化访问了两天&…

Python | Leetcode Python题解之第120题三角形最小路径和

题目&#xff1a; 题解&#xff1a; class Solution:def minimumTotal(self, triangle: List[List[int]]) -> int:n len(triangle)f [0] * nf[0] triangle[0][0]for i in range(1, n):f[i] f[i - 1] triangle[i][i]for j in range(i - 1, 0, -1):f[j] min(f[j - 1], …

Javaweb基础之Cookie会话技术

大家好&#xff0c;这里是教授.F 引入&#xff1a; 我们想在登录一个网站时&#xff0c;能够显示我们上一次的登录时间啊&#xff0c;或者我们在该网站的浏览痕迹。哪这些要怎么做到&#xff1f;我们想&#xff0c;这些数据不可能从服务端给你返回来&#xff0c;因为一旦用户…

react 怎样配置ant design Pro 路由?

Ant Design Pro 是基于 umi 和 dva 的框架&#xff0c;umi 已经预置了路由功能&#xff0c;只需要在 config/router.config.js 中添加路由信息即可。 例如&#xff0c;假设你需要为 HelloWorld 组件创建一个路由&#xff0c;你可以将以下代码添加到 config/router.config.js 中…

ArcGIS教程(04):查找最近的消防站

本节目标 创建、设置和求解最近设施点分析。在本练习中&#xff0c;将查找可对给定地址处发生的火灾做出最快响应的四个消防站。还将生成消防队员的行进路线和驾车方向。 准备视图 双击打开【Exercise04.mxd】启用 【ArcGIS Network Analyst 扩展模块】单击【自定义 > 工…

游戏安全 | 一款「安全」的SLG游戏应该是什么样的?

谈到SLG游戏&#xff0c;也许会想到《万国觉醒》&#xff0c;海外上线5个月后&#xff0c;以5400万美元的月流水创造了新的SLG手游海外收入纪录。 谈到SLG游戏&#xff0c;也许会想到《王国纪元》&#xff0c;通过两军对战的方式&#xff0c;以大面积消灭敌人的攻势&#xff0c…

台灯怎么选对眼睛好?今天来讲护眼台灯真的有用吗

现在我们很多家长对自己孩子的视力十分关心&#xff0c;生怕自己的孩子是近视、远视、弱视等等。对于父母而言&#xff0c;在孩子读书压力大课业重的关键时期&#xff0c;为孩子选择合适的桌椅&#xff0c;护眼灯从而保护孩子的眼睛是非常重要的事情!那么买给孩子读书做功课的台…

2024.5.29晚训参考代码

因为本套题没有BFS例题&#xff0c;所以我先把BFS模板放着 #include<bits/stdc.h> using namespace std; int n,m;//n*m的棋盘 int dis[402][402]; bool vis[402][402]; int X[]{-2,-2,-1,-1,1,1,2,2};//偏移量的表 int Y[]{-1,1,-2,2,-2,2,-1,1};//定义一个数组&…

我给线程池管理框架hippo4j找bug

1 虚拟机参数不生效 hippo4j的docker启动脚本位于 docker/docker-startup.sh 。从下图可以看到 JAVA_OPT放在了jar包名 hippo4j-server.jar之后&#xff0c;而只有项目参数才放在jar包名之后。 实际上这里JAVA_OPT中包含虚拟机参数&#xff0c;而虚拟机参数要放在jar包名之前…

【SpringMVC】_简单示例计算器

目录 1. 需求分析 2. 接口定义 3. 请求参数 4. 响应数据 5. 服务器代码 6. 前端页面代码 7. 运行测试 为阶段性总结与应用&#xff0c;现将以Spring MVC项目创建一个可以实现加法的计算器为例 1. 需求分析 加法计算器功能&#xff0c;对两个整数进行相加&#xff0c;需…

微软Edge浏览器深度解析:功能、同步、隐私与安全

微软Edge浏览器是微软公司开发的一款网页浏览器,它基于Chromium内核,提供了快速、安全和兼容性良好的网页浏览体验。以下是关于微软Edge浏览器的详细信息和使用指南: 微软Edge浏览器的主要特点: 1. 基于Chromium内核: 渲染引擎:Chromium内核是基于开源项目Blink的,它…

Android Notes

maven 版本发布 1、小于 AGP7 使用 maven 插件 apply plugin: maven uploadArchives {repositories {mavenDeployer {pom.groupId GROUP_IDpom.artifactId ARTIFACT_IDpom.version VERSION//正式版本repository(url: RELEASE_URL) {authentication(userName: userName, p…

【学习】自动化测试与单元测试框架的差异化解析

在软件开发的世界中&#xff0c;质量保证是构建可靠、健壮应用程序的关键一环。在这个过程中&#xff0c;自动化测试和单元测试框架是确保代码质量的两种重要工具。尽管它们在目标上有着共同点——提高软件测试的效率和有效性&#xff0c;但它们在应用场景、功能特点以及实现方…

【康耐视国产案例】智能AI相机机器视觉精准快速实现包裹标签的智能粘贴

康耐视推出的3D-A1000是专业的、匹配物流行业各类分拣机及包裹检测应用的全功能视觉检测系统&#xff0c;其能够准确检测分拣机上是否有包裹、包裹是否超出边界、空车检测、是否有遗留物品等。由于搭载了专利的三维结构光技术&#xff0c;产品具有更强大的创新性以满足持续更新…

2024ciscn初赛——easycms

什么是CMS&#xff1f; CMS是“Content Management System”的缩写&#xff0c;意为“内容管理系统”。网站的开发者为了方便&#xff0c;制作了不同种类的CMS&#xff0c;可以加快网站开发的速度和减少开发的成本。 常见的CMS&#xff1a; php类cms系统&#xff1a;dedecms、…

2024年人文发展与社会科学国际会议(ICHDSS 2024)

2024年人文发展与社会科学国际会议 2024 International Conference on Humanities Development and Social Sciences 【1】会议简介 2024年人文发展与社会科学国际会议是一个汇集全球人文科学和社会科学领域专家学者的盛会。本次会议旨在深入探讨人文发展的多元性、复杂性以及社…

做外贸,怎么选国外服务器?

不管是新手还是外贸老司机&#xff0c;大家都知道要用海外服务器来做外贸网站&#xff0c;无论外贸独立站的客户是欧美、东南亚、还是非洲&#xff0c;都不能选择国内机房的服务器&#xff0c;必须选择海外服务器&#xff0c;这是共识。 但是今天&#xff0c;我要告诉大家一个…