2024年java面试准备--spring篇续集(二)

简介: 2024年java面试准备--spring篇续集(二)

2024年java面试准备--spring篇续集(一)https://developer.aliyun.com/article/1393093

面试问题:

1.如果一个接口有多个实现类,在springboot中如何调用不同实现类中的方法

public interface Animal {
    //动物的叫声
   public void call();
    //动物吃的东西
   public void eat();
}
实现类1
@Service("dogImpl")
public class Dog implements Animal {
  
    @Override
    public void call() {
        System.out.println("汪汪汪......");
    }
    @Override
    public void eat() {
        System.out.println("骨头");
    }
}
实现类2
@Service("catImpl")
public class Cat implements Animal {
  
    @Override
    public void call() {
        System.out.println("喵喵喵......");
    }
    @Override
    public void eat() {
        System.out.println("鱼");
    }
}

方法1 指明实现类的优先级

在写实现类的时候事先指明实现类的优先级,注入的时候就会使用优先级高的实现类。在调用的类中注入接口,默认使用的是Primary 标注的实现类的方法


@Service("dog")
@Primary
public class Dog implements Animal {
    .......
}

方法2 通过@Autowride和@Qualifier两个注解配合使用

在调用处使用这两个注解

@Autowired
@Qualifier("dog")
private Animal animal;    //正常启动

注:注解@Qualifier内的值是实现类的默认名

方法3 使用@Resource注解,默认类名区分

在调用处使用此注解

@Resource(name = "dog")
private Animal animal;     //正常启动

注:注解@Qualifier内的值是实现类中@Service指定的名字

2.拦截器的配置

  1. 实现HandlerInterceptor接口的拦截器
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {
        // 在请求处理之前进行拦截处理
        return true; // 返回true表示继续执行请求处理,返回false表示中断请求处理
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {
        // 在请求处理之后进行拦截处理
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,Exception ex) throws Exception {
        // 在请求处理完成之后进行拦截处理
    }
}
@Configuration
public class SpringMvcSupport extends webMvcConfigurationSupport {
    @Autowired
    private MyInterceptor myInterceptor;
    @verride
    protected void addInterceptors( InterceptorRegistry registry){          
        registry.addInterceptor(projectInterceptor).addPathPatterns("/路径");
    }
}
  1. 使用注解的拦截器
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
}
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {
        // 判断请求方法是否有MyAnnotation注解
        if (handler instanceof HandlerMethod) {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        if (method.isAnnotationPresent(MyAnnotation.class)) {
        // 在请求处理之前进行拦截处理
        return true; // 返回true表示继续执行请求处理,返回false表示中断请求处理
    }
}
    return true;
}
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {
        // 在请求处理之后进行拦截处理
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,Exception ex) throws Exception {
        // 在请求处理完成之后进行拦截处理
    }
}
@Controller
public class MyController {
    @RequestMapping("/test")
    @MyAnnotation
    public String test() {
        // 处理请求
        return "test";
    }
}


3.分页功能实现

@Test
void testGetPage(){
    IPage page = new Page( "current": 1,"size": 5);
    bookDao.selectPage(page, "queryWrapper": null);
    page.getCurrent();//获取当前页
    page.getSize();//获取每页数量
    page.getTotal();//获取总共数据条数
    page.getPages();//获取一共多少页
    page.getRecords();//获取的数据
}
//配置拦截器实现分页
@Configuration
public class MPConfig{
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor( ));
        return interceptor;
    }
}

4.如何定义一个全局异常处理类?

想要定义一个全局异常处理类的话,我们需要在这个类上添加@ContaollerAdvice注解,然后定义一些用于捕捉不同异常类型的方法,在这些方法上添加@ExceptionHandler(value = 异常类型.class)和@ResponseBody注解,方法参数是HttpServletRequest和异常类型,然后将异常消息进行处理。

如果我们需要自定义异常的话,就写一个自定义异常类,该类需要继承一个异常接口,类属性包括final类型的连续id、错误码、错误信息,再根据需求写构造方法;

5.说出Spring或者SpringMVC中常用的5个注解

@Component 基本注解,标识一个受Spring管理的组件 @Controller 标识为一个表现层的组件 @Service 标识为一个业务层的组件 @Repository 标识为一个持久层的组件 @Autowired 自动装配 @Qualifier("") 具体指定要装配的组件的id值 @RequestMapping() 完成请求映射 @PathVariable 映射请求URL中占位符到请求处理方法的形参

6.简述SpringMVC中如何返回JSON数据

Step1:在项目中加入json转换的依赖,例如jackson,fastjson,gson等

Step2:在请求处理方法中将返回值改为具体返回的数据的类型, 例如数据的集合类List等

Step3:在请求处理方法上使用@ResponseBody注解

7.Spring循环依赖问题

常见问法

请解释一下spring中的三级缓存

三级缓存分别是什么?三个Map有什么异同?

什么是循环依赖?请你谈谈?看过spring源码吗?

如何检测是否存在循环依赖?实际开发中见过循环依赖的异常吗?

多例的情况下,循环依赖问题为什么无法解决?

什么是循环依赖?

循环依赖就是在创建 A 实例的时候里面包含着 B 属性实例,所以这个时候就需要去创建 B 实例,而创 建 B 实例过程中也包含着 A 实例。 这样 A 实例还在创建的过程当中,所以就导致 A 和 B 实例都创建不出来。

image.png

spring通过三级缓存来解决循环依赖:

一级缓存:缓存经过完整的生命周期的Bean

二级缓存 :缓存未经过完整的生命周期的Bean

三级缓存:缓存的是ObjectFactory,其中存储了一个生成代理类的拉姆达表达式

我们在创建 A 的过程中,先将 A 放入三级缓存 ,这时要创建B,B要创建A就直接去三级缓存中查找,并且判断需不需要进行 AOP 处理,如果需要就执行拉姆达表达式得到代理对象,不需要就取出原始对象。然后将取出的对象放入二级缓存中,因为这个时候 A 还未经 过完整的生命周期所以不能放入一级缓存。这个时候其他需要依赖 A 对象的直接从二级缓存中去获取即可。当B创建完成,A 继续执行生命周期,当A完成了属性的注入后,就可以放入一级缓存了

问题1:为什么构造器注入属性无法解决循环依赖问题?

由于spring中的bean的创建过程为先实例化 再初始化(在进行对象实例化的过程中不必赋值)将实例化好的对象暴露出去,供其他对象调用,然而使用构造器注入,必须要使用构造器完成对象的初始化的操作,就会陷入死循环的状态

问题2:一级缓存能不能解决循环依赖问题? 不能

在三个级别的缓存中存储的对象是有区别的 一级缓存为完全实例化且初始化的对象 二级缓存实例化但未初始化对象 如果只有一级缓存,如果是并发操作下,就有可能取到实例化但未初始化的对象,就会出现问题

问题3:二级缓存能不能解决循环依赖问题?

理论上二级缓存可以解决循环依赖问题,但是需要注意,为什么需要在三级缓存中存储匿名内部类(ObjectFactory),原因在于 需要创建代理对象 eg:现有A类,需要生成代理对象 A是否需要进行实例化(需要) 在三级缓存中存放的是生成具体对象的一个匿名内部类,该类可能是代理类也可能是普通的对象,而使用三级缓存可以保证无论是否需要是代理对象,都可以保证使用的是同一个对象,而不会出现,一会儿使用普通bean 一会儿使用代理类

相关文章
|
1天前
|
存储 Java
面试官:素有Java锁王称号的‘StampedLock’你知道吗?我:这什么鬼?
面试官:素有Java锁王称号的‘StampedLock’你知道吗?我:这什么鬼?
43 23
|
1天前
|
监控 Java 应用服务中间件
Spring Boot 源码面试知识点
【5月更文挑战第12天】Spring Boot 是一个强大且广泛使用的框架,旨在简化 Spring 应用程序的开发过程。深入了解 Spring Boot 的源码,有助于开发者更好地使用和定制这个框架。以下是一些关键的知识点:
20 6
|
1天前
|
Java 数据安全/隐私保护 Spring
Java 中 Spring Boot 框架下的 Email 开发
Java 中 Spring Boot 框架下的 Email 开发
18 2
|
1天前
|
前端开发 Java 测试技术
Java一分钟之Spring MVC:构建Web应用
【5月更文挑战第15天】Spring MVC是Spring框架的Web应用模块,基于MVC模式实现业务、数据和UI解耦。常见问题包括:配置DispatcherServlet、Controller映射错误、视图解析未设置、Model数据传递遗漏、异常处理未配置、依赖注入缺失和忽视单元测试。解决这些问题可提升代码质量和应用性能。注意配置`web.xml`、`@RequestMapping`、`ViewResolver`、`Model`、`@ExceptionHandler`、`@Autowired`,并编写测试用例。
47 3
|
1天前
|
Java 关系型数据库 MySQL
【Java Spring开源项目】新蜂(NeeBee)商城项目运行、分析、总结
【Java Spring开源项目】新蜂(NeeBee)商城项目运行、分析、总结
12 4
|
1天前
|
消息中间件 安全 前端开发
字节面试:说说Java中的锁机制?
Java 中的锁(Locking)机制主要是为了解决多线程环境下,对共享资源并发访问时的同步和互斥控制,以确保共享资源的安全访问。 锁的作用主要体现在以下几个方面: 1. **互斥访问**:确保在任何时刻,只有一个线程能够访问特定的资源或执行特定的代码段。这防止了多个线程同时修改同一资源导致的数据不一致问题。 2. **内存可见性**:通过锁的获取和释放,可以确保在锁保护的代码块中对共享变量的修改对其他线程可见。这是因为 Java 内存模型(JMM)规定,对锁的释放会把修改过的共享变量从线程的工作内存刷新到主内存中,而获取锁时会从主内存中读取最新的共享变量值。 3. **保证原子性**:锁
16 1
|
1天前
|
移动开发 前端开发 NoSQL
ruoyi-nbcio从spring2.7.18升级springboot到3.1.7,java从java8升级到17(二)
ruoyi-nbcio从spring2.7.18升级springboot到3.1.7,java从java8升级到17(二)
48 0
|
1天前
|
JSON 前端开发 Java
【JAVA进阶篇教学】第七篇:Spring中常用注解
【JAVA进阶篇教学】第七篇:Spring中常用注解
|
1天前
|
XML Java 数据库连接
【JAVA基础篇教学】第十五篇:Java中Spring详解说明
【JAVA基础篇教学】第十五篇:Java中Spring详解说明
|
SQL 缓存 安全
Java高频面试题目
面试时面试官最常问的问题总结归纳!
102 0