面试 Java 框架八股文十问十答第一期

面试 Java 框架八股文十问十答第一期

作者:程序员小白条,个人博客

相信看了本文后,对你的面试是有一定帮助的!

⭐点赞⭐收藏⭐不迷路!⭐

1.Spring的IOC和AOP

  • SpringIOC的意思是控制反转,将创建对象和对象管理的过程交给Spring,而减少业务逻辑代码和对象创建和管理之间的耦合度
  • IOC底层原理是:xml解析+工厂模式+反射
  • SpringAOP的意思是面向切面,利用AOP可以对业务逻辑的各个部分进行隔离,减少业务逻辑各部分之间的耦合度,提高程序可重用性。
  • AOP底层有两种动态代理方式(JDK动态代理+CGLIB动态代理)
  • 当有接口情况,使用JDK动态代理,创建接口的实现类的代理对象
  • 没有接口的情况,使用CGLIB动态代理,创建子类的代理对象
  • JDK动态代理使用Proxy类里面的newProxyInstance方法,传入ClassLoader类加载器,要增加的接口数组,实现InvocationHandler,创建代理对象,可以用匿名内部类,或者创建一个新类
  • AOP术语
  • 连接点:可以被增强的方法,切入点: 真正被增强的方法,增强: 真正增强的逻辑部分,切面:把通知应用到切入点的过程
  • AOP一般基于AspectJ实现AOP操作
  • SpringBoot开启AspectJ(@EnableAspectJAutoProxy)

2.SpringMVC和SpringBoot的区别和联系

  • SpringMVC是为了优化Web开发而基于Spring衍生的一个框架,基于ServletAPI的模型视图控制器,SpringMVC的主要作用是将请求和相应进行解耦,将请求和相应与业务逻辑分开来,控制层用于接受请求,返回请求,业务层Service用于写具体业务实现的代码,SpringMVC可以使用拦截器、过滤器对请求进行处理,像登录拦截器,请求日志拦截器等等。
  • SpringBoot是Spring框架中的一个快速开发的框架,可以快速开发生产级别的Spring应用程序,SpringBoot可以自动配置大部分的应用程序,减少繁琐的配置工作,像SpringMVC中写中文乱码,视图解析器都做了自动配置,通过Starter来一键配置Web开发所需要的基本依赖,然后可以用@Bean进行组件注入和覆盖,或者在yml格式中进行修改配置,SpringBoot中很多注解可以配置应用程序的各种组件,比如事务管理器,开启AspecJ,指定扫描包路径。
  • 可以在用SpringBoot快速搭建应用程序的基础上,快速开发SpringMVC的应用程序,提供了很多自动配置和插件,二者结合使用,效率更高。

3.SpringBoot的自动装配原理

推荐文章:https://zhuanlan.zhihu.com/p/626603268

@EnableAutoConfiguration
点击注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class[] exclude() default {};

    String[] excludeName() default {};
}
@AutoConfigurationPackage点击这个注解

@Import({AutoConfigurationPackages.Registrar.class})

 public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            AutoConfigurationPackages.register(registry, (String[])(new PackageImports(metadata)).getPackageNames().toArray(new String[0]));
        }
new AutoConfigurationPackage.PackageImports.getPackageNames() 发现是主程序所在的包以及下面的子包
@Import({AutoConfigurationImportSelector.class})
getAutoConfigurationEntry->getCandidateConfigurations->SpringFactoriesLoader.loadFactoryNames
点开这个类,发现FACTORIES_RESOURCE_LOCATION静态变量=META-INF/spring.factories就是需要加载的类

4.Token可以存哪些地方,分别有哪些优缺点?

1.客户端(前端):Token 可以直接存储在客户端(如 Web 浏览器、移动 App 等)中,通常以 Cookie、LocalStorage、SessionStorage 等形式存储。客户端在发送请求时,将 Token 附加到请求头、请求参数或请求体中,用于向服务器进行身份验证和授权。

  • 优点:客户端存储 Token 简单,无需服务器端维护 Token 的状态信息,适合单页应用、移动 App 等场景。
  • 缺点:客户端存储的 Token 可能面临安全风险,如 XSS 攻击、CSRF 攻击等。如果 Token 泄漏,攻击者可能获取到用户的身份信息,并进行恶意操作。

2.服务器端(后端):Token 可以由服务器生成和管理,通常存储在服务器端的内存、数据库或分布式缓存(如 Redis)中。服务器在生成 Token 时,会将 Token 发送给客户端,并在后续请求中验证 Token 的有效性。

  • 优点:服务器端存储 Token 更加安全,减少了 Token 泄漏的风险。服务器可以灵活管理 Token,如设置过期时间、撤销 Token 等。
  • 缺点:服务器端存储 Token 需要维护 Token 的状态信息,增加了服务器的存储和管理成本。在分布式系统中,Token 的管理和验证可能需要跨多个服务器进行协调。

3.第三方服务(如 OAuth2、OpenID Connect 等):Token 可以由第三方服务(如授权服务器、认证服务器等)生成和管理,用于对多个客户端进行身份验证和授权。

  • 优点:第三方服务提供了标准化和安全的身份验证/授权方案,减少了开发和维护的工作量,适用于多个应用场景和多个客户端。
  • 缺点:依赖第三方服务,可能面临单点故障、性能瓶颈等问题。需要与第三方服务进行集成和配置,增加了系统的复杂性和维护成本。

需要根据具体的应用场景和安全要求来选择合适的 Token 后端方案,并采取相应的安全措施,以保护用户身份信息的安全性。

5.关于JWT有哪些了解?

JWT(JSON Web Token)是一种用于在网络应用中传输信息的开放标准,它定义了一种紧凑且自包含的方式,用于在各方之间安全地传输信息。

JWT 主要由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。

  • 头部(Header):通常由两部分组成,令牌的类型(即 JWT)和签名算法(如 HMAC SHA256 或 RSA 等)。
  • 载荷(Payload):用于携带实际的信息,如用户身份、权限等。载荷可以包含自定义的声明(Claim),也可以包含一些预定义的声明,如过期时间(exp)、发布时间(iat)、签发人(iss)等。
  • 签名(Signature):由头部、载荷和预先定义的密钥(或公钥)进行签名而生成的,用于验证消息的完整性和来源。

JWT 的作用主要包括身份认证和授权。在身份认证方面,JWT 可以通过在请求中携带 Token,用于验证用户的身份信息,并允许用户在不需要重新登录的情况下访问受保护的资源。在授权方面,JWT 可以在载荷中包含用户的权限信息,用于进行细粒度的访问控制。

JWT 的优点包括:

  1. 简洁性和自包含性:JWT 是一种紧凑的编码格式,可以轻松传输和存储。由于 JWT 是自包含的,包含了全部的信息,因此不需要额外的服务器状态存储。
  2. 可扩展性和灵活性:JWT 的载荷部分可以包含自定义的声明,从而支持灵活的定制化需求。
  3. 基于标准和开放性:JWT 是一种开放标准,得到了广泛的支持和应用,可以与多种编程语言和框架进行集成。

JWT 的缺点包括:

  1. 安全性依赖密钥管理:JWT 的签名依赖于密钥的保护,如果密钥泄漏,可能导致令牌被篡改。因此,密钥的安全管理非常重要。
  2. 令牌无法撤销:一旦 JWT 被签发,就无法撤销,除非等待 JWT 过期。这意味着在某些情况下,无法即时地取消或撤销用户的访问权限。
  3. 令牌大小可能较大:由于 JWT 包含了完整的信息和签名,因此 JWT 的大小可能较大,尤其当包含大量自定义声明时,可能会增加网络传输和存储的成本。

JWT 可以在许多场景使用,包括但不限于以下情况:

  1. 身份认证:JWT 可以用于验证用户身份,确保用户在访问受保护的资源时是合法的,从而实现身份认证的功能。例如,在 Web 应用中,用户登录成功后可以通过 JWT 获取一个令牌,然后将该令牌包含在后续的请求中,用于验证用户的身份。
  2. 授权控制:JWT 的载荷部分可以包含用户的权限信息,从而实现细粒度的授权控制。例如,在一个多用户的应用中,可以在 JWT 的载荷中包含用户的角色或权限信息,用于限制用户访问不同的资源或执行不同的操作。
  3. 单点登录(SSO):JWT 可以用于实现单点登录,即用户在一次登录后可以在多个不同的应用中共享登录状态,从而避免重复登录的问题。
  4. 移动应用认证:JWT 可以作为移动应用与后端服务器之间的认证机制,用于验证移动应用的合法性和用户身份。
  5. 微服务架构中的认证和授权:在微服务架构中,各个微服务之间可能需要进行认证和授权,JWT 可以作为一种轻量级的认证和授权机制,用于实现微服务之间的安全通信。

在 Java 中,可以使用许多现有的 JWT 库来实现 JWT 的生成、验证和解析。例如,常用的 Java JWT 库包括 “jjwt”、“Nimbus JOSE + JWT”、“java-jwt” 等。这些库提供了简单易用的 API,可以方便地生成、验证和解析 JWT,并提供了一些配置选项,用于自定义 JWT 的处理逻辑,以满足应用程序的需求。具体使用方式和代码示例如下:

  1. 使用 “jjwt” 库生成 JWT:
javaCopy codeimport io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

// 生成 JWT
String secretKey = "your-secret-key";
String jwt = Jwts.builder()
            .setSubject("user123")
            .signWith(SignatureAlgorithm.HS256, secretKey)
            .compact();
  1. 使用 “jjwt” 库验证和解析 JWT:
javaCopy codeimport io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;

// 验证和解析 JWT
String jwt = "your-jwt-token";
String secretKey = "your-secret-key";
Claims claims = Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(jwt)
                .getBody();

// 获取载荷中的信息
String subject = claims.getSubject();

需要注意的是,生成 JWT 时需要指定一个密钥用于签名,该密钥需要妥善保管,不应该泄漏。在验证和解析 JWT 时,也需要使用相同的密钥进行签名算法的验证,以确保JWT 的完整性和安全性。

优点:

  1. 无状态:由于 JWT 是基于 token 的认证机制,不需要在服务器端存储用户的登录状态,因此可以实现无状态的认证和授权,减轻服务器的负担,并且可以更好地适应分布式和扩展性要求。
  2. 简单和可扩展:JWT 的结构简单,易于实现和扩展,可以根据实际需求进行自定义的配置和扩展,例如在载荷中添加自定义的信息、设置过期时间等。
  3. 跨平台和跨语言:JWT 是一种跨平台和跨语言的认证和授权机制,可以在不同的平台和语言之间使用,例如 Web、移动应用、IoT 设备等。
  4. 安全性:JWT 使用签名算法对令牌进行签名,可以防止篡改和伪造,从而保证令牌的安全性。

缺点:

  1. 令牌过大:由于 JWT 包含了签名和载荷信息,因此令牌的大小通常较大,可能会增加网络传输和存储的开销。
  2. 无法撤销:一旦 JWT 生成后,无法在有效期内撤销或更改令牌的内容,除非等待令牌自动过期。因此,当令牌被盗用或存在安全风险时,需要等待令牌过期或手动撤销密钥来解决问题。
  3. 载荷信息可见:虽然 JWT 的载荷部分可以加密,但默认情况下是明文传输的,可能导致敏感信息泄漏的风险。因此,在使用 JWT 时需要注意不要在载荷中存储敏感信息,或者考虑对载荷进行加密。
  4. 无法处理会话管理:与传统的基于会话的认证机制不同,JWT 是无状态的,无法直接处理会话管理、会话超时等需求,需要通过其他方式进行处理,例如在令牌中设置过期时间或通过定时刷新令牌等方式。

总的来说,JWT 是一种简单、轻量级且安全的认证和授权机制,适用于无状态的分布式应用场景,特别适合用于移动应用、微服务架构、跨平台和跨语言的应用场景。然而,在使用 JWT 时需要注意保护密钥的安全性,避免在载荷中存储敏感信息,同时也需要考虑到令牌过大、无法撤销和无法处理会话管理等缺点。在实际应用中,需要根据具体的需求和安全要求来选择合适的认证和授权机制,以确保系统的安全性和性能。

使用场景: JWT 可以在各种场景中使用,特别适合以下情况:

  1. 跨平台和跨语言应用:由于 JWT 是基于 token 的认证机制,可以在不同的平台和语言之间进行传递和验证,例如在 Web 应用、移动应用和 IoT 设备之间进行认证和授权。
  2. 无状态和分布式应用:由于 JWT 是无状态的认证和授权机制,不需要在服务器端存储用户的登录状态,适用于无状态和分布式的应用场景,例如微服务架构、多服务器环境等。
  3. 客户端密钥管理:由于 JWT 使用签名算法对令牌进行签名,因此适用于客户端密钥管理的场景,例如移动应用和前端应用等。
  4. 需要可扩展性和灵活性:由于 JWT 的结构简单且可扩展,可以根据实际需求进行自定义的配置和扩展,适用于需要灵活性和可扩展性的应用场景。

总的来说,JWT 适用于需要简单、轻量级、无状态且跨平台的认证和授权需求,特别适合在分布式和跨语言的应用中使用。然而,在选择使用 JWT 时,需要根据具体的业务需求、安全要求和性能要求来进行权衡和选择。

6.Spring初始化过程

Spring框架的初始化过程主要分为以下几个步骤:

  1. 加载配置文件:Spring框架会通过配置文件来获取应用程序需要的配置信息,例如Bean的定义、依赖关系、AOP配置等。常见的配置文件包括XML、Java注解或者Java配置类。
  2. 创建IOC容器:Spring框架会根据配置文件的信息,创建一个IoC(Inversion of Control)容器,这个容器具有Bean的实例化、依赖注入、AOP的功能。常见的IoC容器包括ApplicationContext和BeanFactory。
  3. 实例化Bean:根据配置信息,Spring框架会将配置的Bean进行实例化。如果Bean是单例模式(默认),则会在容器初始化时创建Bean实例;如果Bean是原型模式,则会在每次请求时创建新的Bean实例。
  4. 实现依赖注入:当Bean实例化之后,Spring框架会根据配置信息,将对应的依赖注入到Bean中。Spring框架通过反射机制实现依赖注入,根据配置信息中的依赖关系,自动为Bean注入依赖的对象。
  5. 处理Bean的生命周期:Spring框架可以管理Bean的整个生命周期,包括初始化、使用、销毁等。在初始化阶段,Spring可以执行一些特殊的处理,例如调用Bean的初始化方法、实现Bean的代理等。在销毁阶段,Spring可以调用Bean的销毁方法,在容器销毁时释放Bean占用的资源。
  6. 提供AOP功能:Spring框架提供了AOP(Aspect-Oriented Programming)功能,可以通过配置文件或者注解的方式实现横切关注点的编程。在初始化过程中,Spring会扫描配置的切面和切点,生成代理对象,并将代理对象与原始对象关联起来。
  7. 提供其他可选功能:除了基本的初始化过程,Spring还提供了很多其他特性,例如国际化、事件驱动等。在初始化过程中,Spring可以根据配置信息,加载国际化资源,生成事件对象等。

7.MyBatis和MP区别和联系

MyBatis和MyBatis Plus是两个与Java持久层开发相关的开源框架,它们有一些区别和联系。

区别:

  1. 使用方式:MyBatis是一款基于XML配置文件和SQL语句的ORM框架,需要手动编写SQL语句和映射关系;而MyBatis Plus在MyBatis的基础上进行了封装,提供了更加便捷的API和代码生成器,可以使用代码进行动态SQL构建和数据库操作。
  2. 功能扩展:MyBatis仅提供了基本的SQL映射操作,例如增删改查等;而MyBatis Plus在此基础上提供了更多实用的功能,例如分页、逻辑删除、乐观锁、自动填充等。
  3. 易用性:MyBatis Plus使用了简化的API和更加智能的提供者查询条件封装,使得开发变得更加简单和高效。
  4. 社区活跃度:MyBatis是一个相对成熟和活跃的框架,拥有庞大的开发者社区和丰富的生态系统;MyBatis Plus作为MyBatis的增强版本,因其提供的便利功能和易用性受到了越来越多的开发者喜爱,并逐渐形成了自己的社区和生态系统。
  5. Lambda表达式:MyBatis不支持Lambda形式调用,MyBatisPlus支持Lambda形式调用
  6. SQL语句:MyBatis所有SQL语句自己写,MP提供基本的CRUD功能,不需要自己编写SQL。
  7. MyBatisX: 插件自动生成实体类,mapper,xml文件

联系:

  1. 基于MyBatis:MyBatis Plus是基于MyBatis的增强版本,能够完全兼容MyBatis的特性和功能。
  2. 共享资源:MyBatis和MyBatis Plus的许多资源可以相互共享和复用,例如数据源、事务管理等。
  3. 共同目标:MyBatis和MyBatis Plus旨在提供灵活、高效、易用的持久层开发解决方案,帮助开发者更加便捷地进行数据库操作。

8.Bean的生命周期

  • Bean生命周期有七步

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

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

(3)把bean实例传递bean后置处理器的方法postProcessBeforeInitialization

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

(5)把bean实例传递bean后置处理器的方法 postProcessAfterInitialization

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

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

9.Bean的作用域

scope:singleton | prototype设置Bean的作用域

Singleton和prototype区别: 第一 singleton单实例,prototype多实例 第二 设置scope值是singleton时候,加载spring配置文件时候就会创建单实例对象 设置scope值是prototype时候,不是在加载spring配置文件时候创建 对象,在调用 getBean方法时候创建多实例对象

10.Spring如何解决循环依赖问题?

构造函数注入:通过将依赖关系通过构造函数传递,可以解决循环依赖。当两个bean相互依赖时,Spring会优先创建其中一个bean,并将其作为参数传递给另一个bean的构造函数。

setter方法注入:通过setter方法注入依赖关系,同样可以解决循环依赖。当两个bean相互依赖时,Spring会先创建其中一个bean,并将其注入到另一个bean的setter方法中。

使用@Lazy注解:@Lazy注解可以延迟创建bean的实例,从而解决循环依赖问题。当两个bean相互依赖时,可以使用@Lazy注解将其中一个bean的创建延迟到需要使用时再创建。 需要注意的是,循环依赖可能会导致死锁或无限递归的问题,因此在设计应用程序时应尽量避免循环依赖的产生。如果无法避免,可以通过合理的设计和使用上述解决方式来解决循环依赖问题。

你可能感兴趣的:(面试八股文系列,面试,java,职场和发展)