JAVA面试(三)

Spring框架核心概念

Spring

一个轻量级JAVA开发框架,包含了很多模块

IOC (控制反转)

控制,指对象的创建(实例化、管理)等权力
反转, 控制权交给外部环境(Spring 框架、IoC 容器)
在这里插入图片描述
IOC:将对象的控制权(创建、管理)交由 IoC 容器去管理(只需要配置好配置文件/注解即可),我们在使用的时候直接向 IoC 容器 “要” 就可以了,完全不用考虑对象是如何被创建出来的。
好处: 对象间的耦合度降低,资源易于管理
IoC 最常见以及最合理的实现方式叫做依赖注入(Dependency Injection,简称 DI

基于注解的容器初始化

依赖注入的相关注解

@Autowried:自动按类型注入,

  • @Resource:安装bean的id(名称)注入
  • @value:基于基本类型和String

注入方式(3种)

  • setter方法注入
  • 构造方法注入
  • 接口注入: 这种方式对代码入侵性强

Spring Bean

什么是bean

就是由IOC容器创建实例、组装和管理的对象。

Bean的作用域

  • Singleton-单例模式:(默认),Spring Ioc容器只会创建一个共享的bean实例
  • prototype-原型模式:每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()。
  • request:每次HTTP请求都会创建一个新的Bean
  • session:同一个HTTP Session共享一个Bean
  • global-session: 全局 session 作用域,仅在基于 Portlet 的 web 应用中才有意义,Spring5 已经没有了。

Spring Bean生命周期

实例化Bean—> 属性赋值 —> 检查bean是否实现了Awear相关接口,并设置相关依赖 —> bean后处理器的before执行 —> 初始化Bean—> bean后处理器的after执行 —>使用Bean—> 检查bean是否实现了DisposableBean接口,并调用接口方法 —>销毁Bean
在这里插入图片描述
BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这些接口的方法。每个Bean选择实现,可选择各自的个性化操作。

注解

@PreConstruct:自定义初始化方法
@PostConstruct:自定义销毁方法

Spring Bean创建过程

对象创建方式

  • 1、new创建
  • 2、使用Class类的newInstance方法(调用了构造函数)
Employee emp2 = (Employee) Class.forName("包名").newInstance();
Employee emp2 = Employee.class.newInstance();
  • 3、使用Constructor类的newInstance方法(调用了构造函数)
import java.lang.reflect.ConstructorConstructor<Employee> constructor = Employee.class.getConstructor();
Employee emp3 = constructor.newInstance();
  • 4、使用clone方法(调用了构造函数)

  • 5、使用反序列化

//让我们的类实现Serializable接口
ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj"));
Employee emp5 = (Employee) in.readObject();

AOP(面向切面)

概括:将重复代码提取出来,在需要执行的时候使用动态代理方式,在不修改原代码前提下增强,这部分重复代码是与核心业务关联性小的业务逻辑。
将横切关注点从核心业务逻辑中分离出来,形成一个个的切面
好处:将一些分散在多个类或对象中的公共行为横切关注点,避免再类中重复实现这些行为,导致代码的冗余、复杂和难以维护

AOP实现原理

将公共代码逻辑抽象出一个切面
通过代理方式,将切需求注入切面的对象进行代理
在调用时将公共逻辑添加进去
代理2种方式 -

AOP使用场景

  • 权限认证、错误处理
  • 日志记录
  • 性能统计:利用 AOP 在目标方法的执行前后统计方法的执行时间,方便优化和分析
  • 事务管理:@Transactional注解,让 Spring 为我们进行事务管理比如回滚异常操作,免去了重复的事务管理逻辑
  • 缓存管理:利用 AOP 在目标方法执行前后进行缓存的读取和更新。

日志案例

/** 第一步,定义日志注解 **/
@Target({ElementType.PARAMETER,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
    // 描述
    String description() default "";
    //方法类型 INSERT DELETE UPDATE OTHER
    MethodType methodType() default MethodType.OTHER;
}

/** 第二步,定义日志切面 **/
@Component
@Aspect
public class LogAspect {
  // 切入点,所有被 Log 注解标注的方法
  @Pointcut("@annotation(cn.javaguide.annotation.Log)")
  public void webLog() {
  }
   //环绕通知
  @Around("webLog()")
  public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
    // 省略具体的处理逻辑
  }
  // 省略其他代码
}

/** 第三步,我们一行注解即可实现日志记录 **/
@Log(description = "method1",methodType = MethodType.INSERT)
public CommonResponse<Object> method1() {
      // 业务逻辑
      xxService.method1();
      // 省略具体的业务处理逻辑
      return CommonResponse.success();
}

Spring 事务

程序是否支持事务首先取决于数据库!

事务属性

  • 隔离级别
  • 传播行为
  • 回滚规则
  • 是否只读
  • 事务超时

事务管理

事务是逻辑上的一组操作,要么都执行,要么都不执行

1. 编程式事务管理

通过 TransactionTemplate或者TransactionManager手动管理事务

  • TransactionTemplate
@Autowired
private TransactionTemplate transactionTemplate;
public void testTransaction() {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                try {
                    // ....  业务代码
                } catch (Exception e){
                    //回滚
                   transactionStatus.setRollbackOnly();
                }
           }
        });
}
  • TransactionManager
@Autowired
private PlatformTransactionManager transactionManager;
public void testTransaction() {
 TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
         try {
              // ....  业务代码
             transactionManager.commit(status);
        } catch (Exception e) {
             transactionManager.rollback(status);
         }
}
2. 声明式事务管理(代码入侵少,推荐使用)

实际是通过 AOP 实现(基于@Transactional 的全注解方式使用最多)

@Transactional(propagation = Propagation.REQUIRED)
public void aMethod {
 //do something
}

事务传播行为

为了解决业务层方法之间互相调用的事务问题

常见面试题

1. Spring,Spring MVC,Spring Boot 之间什么关系?

m

这里是引用
Spring 时代我们一般通过 XML 文件来配置 Bean,后来开发人员觉得 XML 文件来配置不太好,于是 SpringBoot 注解配置就慢慢开始流行起来。

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

  • 单例的setter注入,可解决 - 使用了三级缓存。
    多例的setter注入,不能解决
    构造器方式注入,不能解决
    DependsOn循环依赖,不能解决
  • spring内部有三级缓存
    1、singletonObjects 一级缓存,用于保存实例化、注入、初始化完成的bean实例
    2、earlySingletonObjects 二级缓存,用于保存实例化完成的bean实例
    3、singletonFactories 三级缓存,用于保存bean创建工厂,以便于后面扩展有机会创建代理对象。
  • Springboot
    @DependsOn注解:指定顺序
    @Autowired注解的required 设置为false
    通过构造函数注入

3. @Tranctional注解什么情况下会失效

4、@Autowired 与@Resource的区别

-提供方不一样:@Autowired-Spring提供; @Resource-J2EE提供

  • @Autowired 根据类型注入; @Resource 默认根据名字注入,其次按照类型搜索
  • @Autowired 、@Qualifie(“userService”) 两个结合起来可以根据名字和类型注入

5. Spring获取Bean的方式

Mybatis

基本概念

半自动ORM映射工具。因为在查询关联对象或关联集合对象时候,需要手动编写SQL来完成,所以称为半自动。
特点:

  • 优:基于sql编程,相当灵活,支持编写动态sql,可复用。
    很好对与各种数据库兼容
    能够与Spring很好对集成
  • 缺:sql语句工作量大,尤其字段多、关联表多的时候
    依赖于数据库,导致数据库移植性差

原理,dao与xml如何对接

Dao接口代理 但是Dao接口并没有具体的实现类,那么在被调用时,最终又是怎样找到我们的SQL语句的呢?

@MapperScan(“com.xxx.dao”),这个注解会将包路径下的所有类注册到 Spring Bean 中,并将它们的beanClass设置为 MapperFactoryBean,MapperFactoryBean 实现了 FactoryBean 接口
通过 @Autowired 注入这个Dao接口时,返回的对象就是 MapperFactoryBean 这个工厂Bean中的 getObject() 方法对象(实际会通过JDK动态代理,返回了一个Dao接口的代理对象 MapperProxy,当我们通过 @Autowired 注入Dao接口时,注入的就是这个代理对象)
调用 Dao接口中的方法时,则会调用到 MapperProxy 对象的invoke()方法

总结:

  • SqlSource以及动态标签SqlNode
    mybatis会把每个SQL标签封装成SqlSource对象:静态SQL是一段String类型的sql语句、而动态SQL则是由一个个SqlNode组成。
  • MappedStatement对象
    Mybatis会为XML中的每个SQL标签都生成一个MappedStatement对象,这里面有两个属性很重要:
    ① id:全限定类名+方法名组成的ID
    ② sqlSource:当前SQL标签对应的SqlSource对象
  • Spring 工厂Bean 以及动态代理
  • SqlSession以及执行器
    不管有几个XML和Dao建立关系,只要保证namespace+id唯一即可

缓存级别

mybatis提供了查询缓存,用于减轻数据压力,提高数据库性能。
在这里插入图片描述

常见面试题

1. ${} 和 #{} 的区别

  • #{} 参数占位符,在mybatis中,会被解析成?。若是String类型,会自动加上引号,主要可以防止SQL注入,
  • ${}:变量占位符,不会对参数解析,多用在字符串拼接,可以用在模糊查询、

2. MyBatis 的 xml 映射文件中,不同的 xml 映射文件,id 是否可以重复

namespace+id 组成唯一key

3. MyBatis 动态 sql 是做什么的?都有哪些动态 sql?能简述一下动态 sql 的执行原理不?

  • 指根据条件拼接SQL语句的功能
  • choose、when、otherwise、if、foreach、where、set、trim 、bind
  • 通过XmlScriptBuilder类的递归解析,可以将各种类型的动态SQL节点转换成SqlNode接口的实现,然后再通过MixdSqlNode类组合对应完整的SQL片段

4. MyBatis 是如何进行分页的?分页插件的原理是什么?

(1)Mybatis使用RowBounds对象分页,也可以直接编写sql分页,也可用Mybatis的分页插件分页。

5. Hibernate和mybatis的区别

都是对jdbc的封装,持久层的框架,用于dao层的开发

HibernateMybatis
映射关系全表映射半自动映射
sql优化和移植性若支持多种数据库,代码开发量少,但SQL语句优化困难需手动编写sql,sql优化容易

6. MyBatis 一对一?

使用association标签, 案例
<association property="user" javaType="User" column="user_id" resultMap="UserMap" />

  • property:对象属性的名称
  • javaType:对象属性的类型
  • column:所对应的外键字段名称
  • select:使用另一个查询封装的结果

7. MyBatis 一对多?

使用collection标签
<collection property="list" ofType="object" resultMap="resultMap" />

  • property:指定集合属性的名(具体实体类中list集合名)
  • ofType:指的是集合中元素的值,一般是类的完全限定名

Spring Boot

自动装配原理

什么是自动装配
SpringBoot 在启动时会扫描外部引用 jar 包中的META-INF/spring.factories文件,将文件中配置的类型信息加载到 Spring 容器,并执行类中定义的各种操作。对于外部 jar 来说,只需要按照 SpringBoot 定义的标准,就能将自己的功能装置进 SpringBoot。
原理
@SpringbootApplication注解里面有很多注解,其中有三个重要的注解@ComponentScan、@SpringBootConfiguration、@EnableAutoConfiguration

  • @ComponentScan会扫描包下的所有注解的类,当然可以用filter过滤扫描。常见的组件类。例如 @Component、@Service,@Controller
  • @SpringBootConfiguration:其本质就是@Configuration,允许在上下文中注册额外的 bean 或导入其他配置类
  • @EnableAutoConfiguration:启用 SpringBoot 的自动配置机制。 其本质是因为@Import({AutoConfigurationImportSelector.class}) 。AutoConfigurationImportSelector里面的selectImports()方法,会获取自动配置Entry,获取候选配置就从springframework下和当前应用下读取META-INF//spring.factories 文件,或取所有符合条件的类的全限定类名,加载到IOC容器

总结
Spring Boot 通过@EnableAutoConfiguration开启自动装配,通过 SpringFactoriesLoader 最终加载META-INF/spring.factories中的自动配置类实现自动装配,自动配置类其实就是通过@Conditional按需加载的配置类,想要其生效必须引入spring-boot-starter-xxx包实现起步依赖

启动原理

最好看一下源码,更容易理解

//1、首先找到被@SpringbootApplication注解的类,其中中会有个main方法
  SpringApplication.run(ClassName.class, args);
// 其内部其实就是创建一个Application对象,再执行run方法
// 底层代码为: return (new SpringApplication(primarySources)).run(args);
  

具体可看下图
在这里插入图片描述

spring.factory

# Initializers  初始值设定项
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

# Application Listeners 应用程序侦听器
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

# Environment Post Processors 环境后处理器
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.autoconfigure.integration.IntegrationPropertiesEnvironmentPostProcessor

# Auto Configuration Import Listeners 自动配置导入侦听器
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener

# Auto Configuration Import Filters 自动配置导入过滤器
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

# Failure analyzers 故障分析器
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.autoconfigure.data.redis.RedisUrlSyntaxFailureAnalyzer,\
org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\
org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\
org.springframework.boot.autoconfigure.jooq.NoDslContextBeanFailureAnalyzer,\
org.springframework.boot.autoconfigure.r2dbc.ConnectionFactoryBeanCreationFailureAnalyzer,\
org.springframework.boot.autoconfigure.r2dbc.MissingR2dbcPoolDependencyFailureAnalyzer,\
org.springframework.boot.autoconfigure.r2dbc.MultipleConnectionPoolConfigurationsFailureAnalyzer,\
org.springframework.boot.autoconfigure.r2dbc.NoConnectionFactoryBeanFailureAnalyzer,\
org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer

# Template availability providers 模板可用性提供程序
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider

# DataSource initializer detectors DataSource 初始值设定项检测器
org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector=\
org.springframework.boot.autoconfigure.flyway.FlywayMigrationInitializerDatabaseInitializerDetector

# Depends on database initialization detectors  数据库依赖初始化检测器
org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector=\
org.springframework.boot.autoconfigure.batch.JobRepositoryDependsOnDatabaseInitializationDetector,\
org.springframework.boot.autoconfigure.quartz.SchedulerDependsOnDatabaseInitializationDetector,\
org.springframework.boot.autoconfigure.session.JdbcIndexedSessionRepositoryDependsOnDatabaseInitializationDetector

多环境配置文件

Bootstaro.yaml

常见面试题

SpringBoot获取配置文件中的配置内容

  • @Value(${配置项key:默认值})
  • @ConfigurationProperties(value = “app”)
    配置文件中app配置项下的属性
  • Environment类
    environment.getProperty(“envir.system.group”));
  • @PropertySource注解
    @Component
    @ConfigurationProperties(prefix = “csdn”)
    @PropertySource(value = “classpath:alian.properties”, encoding = “UTF-8”, ignoreResourceNotFound = true) 配合使用

Spring Cloud

注册、配置中心

eureka

心跳机制

nacos

心跳机制

网关

Zuul

Spring Cloud Gateway

过滤拦截、路由转发

路由、断言
ribbon
hystrix

Dubbo

其实对于传统项目,还是这个架构用的多。对于我们使用来说,最常见的就是搭配Zookeeper注册中心。
服务间通信时RPC框架,可以扩展学习一下Netty,很多较大开源项目都有用到这个技术。

这里和Feign区别一下,Feign实现负载均衡,需要集成Ribbon。

RPC服务通信,需要知道3个角色 - 注册中心、生产者、消费者。在具体项目上,我们应该会见过具体使用。

生产者(服务提供方)消费者
在这里插入图片描述在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值