Spring框架
1、说说你对Spring IOC的理解?
答:控制反转
将对象的创建和管理由程序员反转给spring程序管理
Spring反向控制应用程序所需要使用的外部资源 ,类原来自己主动new对象, 变成交给springIoc容器管理,配置好java对象的bean即可
Spring控制的资源全部放置在Spring容器中,该容器称为IoC容器
2、什么是Spring的依赖注入?
答:
有依赖关系,给成员变量赋值时,对象由ioc容器提供
- 给基本数据类型的成员变量进行DI:我们需要使用@Value注解完成 属性注解、方法注解
- 给引用数据类型的成员变量进行DI:我们需要使用@Autowired ,@Qualifier
3、依赖注入实现方式有哪些?
答:
1、基于属性注入
最常用的 private A a;
2、基于 setter 方法注入
3、基于构造器注入
: 当两个类属于强关联时,我们也可以通过构造器的方式来实现注入,在构造器的方法参数中注入
4、说说什么是Spring Bean?
答:IOC容器中创建管理的对象,指所有要加入spring容器的java对象 --实体
带以下注解的类的对象将交给ioc容器管理
@Component
@Controller
@Service
@Repository
使用四大注解声明的bean,要想生效,还需要被组件扫描注解@ComponentScan扫描
5、Spring Bean的作用域有哪些?scope
答:通过spring容器创建一个Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定的作用域。Spring支持如下5种作用域:
- singleton:单例模式,在整个Spring IoC容器中,使用singleton定义的Bean将只有一个实例
- prototype:原型模式,每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例
- request:对于每次HTTP请求,使用request定义的Bean都将产生一个新实例,即每次HTTP请求将会产生不同的Bean实例。只有在Web应用中使用Spring时,该作用域才有效
- session:对于每次HTTP Session,使用session定义的Bean豆浆产生一个新实例。同样只有在Web应用中使用Spring时,该作用域才有效
- globalsession:每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。典型情况下,仅在使用portlet context的时候有效。同样只有在Web应用中使用Spring时,该作用域才有效
其中比较常用的是singleton和prototype两种作用域。对于singleton作用域的Bean,每次请求该Bean都将获得相同的实例。容器负责跟踪Bean实例的状态,负责维护Bean实例的生命周期行为;如果一个Bean被设置成prototype作用域,程序每次请求该id的Bean,Spring都会新建一个Bean实例,然后返回给程序。在这种情况下,Spring容器仅仅使用new 关键字创建Bean实例,一旦创建成功,容器不在跟踪实例,也不会维护Bean实例的状态。
如果不指定Bean的作用域,Spring默认使用singleton作用域。Java在创建Java实例时,需要进行内存申请;销毁实例时,需要完成垃圾回收,这些工作都会导致系统开销的增加。因此,prototype作用域Bean的创建、销毁代价比较大。而singleton作用域的Bean实例一旦创建成功,可以重复使用。因此,除非必要,否则尽量避免将Bean被设置成prototype作用域。
6、Spring框架中的单例bean(singleton)是线程安全的吗?如果不是如何解决?
答 : 不是
单例是不安全的,会导致属性重复调用。
1、改为多例的(就是在class上面加一个@Scope("request)
万一必须要定义一个非静态成员变量时候,则通过注解@Scope("prototype"),将其设置为多例模式。
2、是采用ThreadLocal解决线程安全问题
7、简单说说Spring Bean的生命周期?
答:
8、使用@Autowired注解自动装配的过程是怎样的?
答 :
在成员变量上加入注解
@Autowired 默认按照类型进行注入操作
ps:如果一个类型存在多个对象:
@Primary :使用@Primary提高按类型自动装配的优先级,多个primary会导致优先级设置无效
@Autowired + @Qualifier("bean名称")
@Resourse(name="bean名称")
9、说说Spring常用的注解有哪些?
答:
控制反转层:bean对象里 【@Component、@Controller、@Service、@Repository】
组件扫描 : @ComponentScan
依赖注入 : @Autowired 、@Primary 、 @Qualifier、@Resourse
10、你们项目中的事务是如何处理的?一般事务在三层架构中的哪层进行处理?
答:
事务是一组操作的集合,整体要么一起成功,要么一起失败
我们项目中主要是添加注解来处理事务的
在启动类上加@EnableTransactonalManager
事务加在service层,把@transactional加在实现类上或者接口上都可以
11、Spring事务的隔离级别有哪些?
答:
Read Uncommited,读未提交,即一个事务可以读取另一个未提交事务的数据;并发操作会导致脏读
Read Commited,读操作,即一个事务要等到另一个事务提交后才能读取数据;解决脏读问题;并发操作会导致不可重复读
Repeatable Read,重复读,即开始读取数据(事务开启)时,不再允许修改操作;解决不可重复读问题;并发操作会导致幻读(对应insert操作)
Serializable,序列化,最高的事务隔离级别,该级别下,事务串行化顺序执行;避免脏读、不可重复读与幻读;但是该级别效率低下,比较消耗数据库性能,一般不用。
12、说说什么是Spring事务传播行为?
答:Spring事务传播行为就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制
方法运行的时候,首先会开启一个事务,在A方法当中又调用了B方法, B方法自身也具有事务,那么B方法在运行的时候,到底是加入到A方法的事务当中来,还是B方法在运行的时候新建一个事务?
通过属性控制事务的传播行为 @Transactional(propagation = "属性")
属性:
【见下表,关注高亮即可】
属性值 | 含义 |
---|---|
REQUIRED | 【默认值】需要事务,有则加入,无则创建新事务 |
REQUIRES_NEW | 需要新事务,无论有无,总是创建新事务 |
SUPPORTS | 支持事务,有则加入,无则在无事务状态中运行 |
NOT_SUPPORTED | 不支持事务,在无事务状态下运行,如果当前存在已有事务,则挂起当前事务 |
MANDATORY | 必须有事务,否则抛异常 |
NEVER | 必须没事务,否则抛异常 |
… |
13、Spring事务的传播行为有哪些?
答:
见上表
14、简单说说Spring事务的底层实现原理?
答:
策略设计模式
在使用JdbcTemplate的时候,我们在进行查询的时候我们可以对其传递一个RowMapper对象,而RorMapper是一个接口,我们在使用的时候传递其实是这个接口的实现类,传递不同的实现类,那么得到结果就是不同的,这其实就是策略设计模式。
策略模式(Strategy Pattern)使用不同策略的对象实现不同的行为方式,策略对象的变化导致行为的变化。
15、说说哪些情况下会导致spring事务失效?
答:
1、数据库引擎不支持事务
2、没有被 Spring 管理
3、方法不是 public 的
@Transactional 只能用于 public 的方法上,否则事务不会失效,如果要用在非 public 方法上,可以开启 AspectJ 代理模式
4、不支持事务
Propagation.NOT_SUPPORTED
5、使用try catch ,但不抛异常,事务无法回滚
6、异常类型错误,使用try catch ,抛异常错误,默认回滚的是:RuntimeException,如果你想触发其他异常的回 滚,需要在注解上配置一下,如:
@Transactional(rollbackFor = Exception.class)
16、说说什么是AOP?
答:
AOP全称:Aspect Oriented Programing,面向切面编程,是一种编程的思想, 一种编程范式。
是对OOP的补充, 怎么补充?就是把OOP中共性的内容抽取出来,形成独立的一部分
oop纵向; aop横向,aop就是用来开发共性功能,和工具类不同,工具类是要调工具类自己的方法,修改很不方便,而且aop可以运行时自动拼接
17、简单说说AOP的底层是基于什么实现的?
答:AOP的底层使用的动态代理。
动态代理有两种: 基于JDK的、 基于CGLIB的代理
JDK的动态代理是基于接口进行代理的,被代理的对象必须去实现指定的接口。并且JDK的动态代理所产生的代理对象和被代理类是平级的关系。
CGLIB的代理:可以对类直接进行代理,它所产生的代理对象和被代理类之间的关系是继承的关系(不能无中生有,所以要继承被代理的类)
两者本质都是对方法的增强
18、AOP的通知类型有哪些?
答:
前置通知(<aop:before>): 原始方法执行前执行,如果通知中抛出异常,自己仍会执行, 阻止原始方 法运行
后置通知(<aop:after>): 原始方法执行后执行,无论原始方法中是否出现异常,都将执行通知 都可
返回后通知(<aop:after-returning>): 原始方法正常执行完毕并返回结果后执行,如果原始方法中抛出异常, 无法执行 成功后
抛出异常后通知(<aop:after-throwing>): 原始方法抛出异常后执行,如果原始方法没有抛出异常,无法执行异常后
环绕通知(<aop:around>): 在原始方法执行前后均有对应执行,还可以阻止原始方法的执行
** 环绕通知的注意事项 **:
1、在环绕通知中我们需要去执行我们的原始方法,在进行执行原始方法的时候我们需要使用一个对象去调用原始方法,这个对象ProceedingJoinPoint ,JoinPoint父类,连接点是目标对象类的所有方法,所以这个对象可以获得所有方法相关的信息和参数
2、这个ProceedingJoinPoint这个参数只能是环绕通知方法的第一个参数
3、一般情况下在定义我们这个环绕通知方法的时候,方法一般情况下我们需要定义返回值类型(Object)
20、说说AOP一般能用来干什么?在你的项目中有用到吗,如何使用的?
答:
方法增强
在我之前的项目中用到了,刚好这部分是我处理的,我做了异步日记记录的功能,这个功能可以异步记录操作我们系统的操作人的信息、执行了哪些操作等
具体实现:
1、自定义一个注解@Log
2、编写日志表,封装数据
3、编写AOP代码实现记录日志的功能:定义一个通知类【@Aspect】,在通知类中实现记录日志的操作,完成代码增强
4、执行异步多线程,保证在你的项目中加入@Log注解时,主项目不会报错
21、Spring 框架中都用到了哪些设计模式,简单说说?
答:
- 单例模式
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
spring中的单例模式完成了后半句话,即提供了全局的访问点BeanFactory。但没有从构造器级别去控制单例,这是因为spring管理的是是任意的java对象。
- **适配器模式**
在Spring的Aop中,使用的Advice(通知)来增强被代理类的功能。Spring实现这一AOP功能的原理就使用代理模式(1、JDK动态代理。2、CGLib字节码生成技术代理。)对类进行方法级别的切面增强,即,生成被代理类的代理类, 并在代理类的方法前,设置拦截器,通过执行拦截器重的内容增强了代理方法的功能,实现的面向切面编程。
- **工厂方法模式**
IoC的出现——工厂模式衍化而来
一般情况下,应用程序有自己的工厂对象来创建bean.如果将应用程序自己的工厂对象交给Spring管理,那么Spring管理的就不是普通的bean,而是工厂Bean。
22、知道Spring是如何解决Bean的循环依赖的吗 ?
答:
找一个中间缓存(三级缓存),Spring 在创建 bean 的时候并不是等它完全完成,而是将创建中的 bean 提前曝光(即加入到 singletonFactories 三级缓存中),当下一个 bean 创建的时候需要依赖此 bean ,则从三级缓存中获取。
**拓展** 描述一下 Spring 解决循环依赖的过程:
先创建 A 对象,并将创建出来的 A 对象放到 Spring 的三级缓存中;
此时 A 对象的 b 属性为空,需要填充 b 属性,到缓存中查询 B 对象,没有查到,触发 B 对象的创建流程;
创建 B 对象,并将创建出来的 B 对象放到 Spring 的三级缓存中;
B 对象的 a 属性为空,需要填充 a 属性,随后在缓存中找到 A 对象,完成填充注入;
最后再对 A 对象的 b 属性进行填充,从缓存中顺利拿到 B 对象,完成属性注入,循环依赖到此解决。
23、动态代理的方式有哪些?
答:
两种
动态代理有两种: 基于JDK的、 基于CGLIB的代理
JDK的动态代理是基于接口进行代理的,被代理的对象必须去实现指定的接口。并且JDK的动态代理所产生的代理对象和被代理类是平级的关系。
CGLIB的代理:可以对类直接进行代理,它所产生的代理对象和被代理类之间的关系是继承的关系(不能无中生有,所以要继承被代理的类)
两者本质都是对方法的增强
24、FactoryBean 和 BeanFactory的区别?
FactoryBean : 封装单个bean的创建过程
BeanFactory : Spring容器顶层接口,定义了bean相关的获取操作
25、说说spring和springboot的关系?
springboot中集成了spring和springmvc的组件,
26、Spring Boot如何实现自动配置?
依赖于@Conditional配置类
SpringBoot中对@Conditional的引用链如下:
@SpringBootApplication注解主要包含3个注解:@SpringBootConfiguration 、@EnableAutoConfiguration 、@ComponentScan。
1.SpringBoot启动的时候加载主启动类,通过@EnableAutoConfiguration开启自动配置功能。
2.@EnableAutoConfiguration利用AutoConfigurationImportSelector给容器中导入一些组件。
3.通过protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes)获取候选的配置和核心方法,扫描所有jar包类路径下"META-INF/spring.factories",通过@AutoConfigurationPackage自动配置包。
4.把扫描到的文件包装成Properties对象。
5.从properties中获取到EnableAutoConfiguration.class类名对应的值,并把他们添加在容器中。
6.整个过程就是将类路径下"META-INF/spring.factories"里面配置的所有EnableAutoConfiguration的值加入到容器中。
7.根据@Conditional注解中的条件判断,决定这个配置是否生效。
27、@EnableXxx注解的作用是什么?你有用过哪些?
开启某个功能
@EnableRetry:开启 Spring 的重试功能;
@EnableScheduling:开启 Spring 的定时功能;
@EnableAsync:开启 Spring 的异步功能;
@EnableAutoConfiguration:开启 Spring 的自动装配功能;
我用过事务的EnableTransactonalManager
28、Spring Boot与Spring Cloud的关系是什么?
Spring Cloud是基于Spring Boot实现的
Spring Boot分为单体架构和微服务架构
Spring Cloud是解决微服务架构中出现的各种问题的一套解决方案
29、SpringBoot的常用注解有哪些?
常用的有@RequestMapping、@Autowired、@Value、@EnableAutoConfiguration等
拓展:
常用注解:
@SpringBootApplication
:用于标记主启动类,表示这是一个Spring Boot应用程序的入口点。它包含了@Configuration
、@EnableAutoConfiguration
和@ComponentScan
三个注解的功能。@RestController
:用于标记一个类,表示这是一个RESTful风格的控制器。它组合了@Controller
和@ResponseBody
注解。@RequestMapping
:用于映射HTTP请求到控制器方法。可以用于类级别和方法级别,用于指定URL路径和请求方法。@GetMapping
、@PostMapping
、@PutMapping
、@DeleteMapping
:用于简化常见的HTTP请求映射,分别对应GET、POST、PUT、DELETE请求。@Autowired
:用于自动装配依赖关系,通过类型或名称进行依赖注入。@Value
:用于注入配置属性值。@Configuration
:用于标记配置类,定义应用程序的配置。@EnableAutoConfiguration
:启用自动配置,根据项目的依赖自动配置Spring应用程序。@ComponentScan
:指定要扫描的包,自动发现和注册Bean组件。@Conditional
:根据特定的条件进行条件化配置。@EnableCaching
:启用缓存功能。@EnableAsync
:启用异步方法执行。@EnableScheduling
:启用定时任务调度。@Transactional
:声明事务的注解。
30、SpringBoot读取配置文件的方式有哪些?
常用的方式有配置application.properties和application.yml文件,使用@ConfigurationProperties注解将配置属性绑定到Java类中。
拓展:
application.properties
文件: 在Spring Boot项目的src/main/resources
目录下创建名为application.properties
的文件,可以在该文件中定义应用程序的配置属性。Spring Boot会自动读取并加载这些属性,供应用程序使用。application.yml
文件: 与application.properties
类似,application.yml
文件也用于定义应用程序的配置属性。它使用了YAML(YAML Ain't Markup Language)语法,提供了一种更加简洁和可读性高的配置格式。- 命令行参数: 通过在命令行中使用
--
或-D
参数的方式,可以覆盖或添加应用程序的配置属性。例如,java -jar myapp.jar --server.port=8081
可以指定应用程序的端口号为8081。 - 环境变量: Spring Boot可以读取环境变量中的配置属性。可以将配置属性以
SPRING_APPLICATION_
开头的环境变量的形式设置,Spring Boot会自动加载这些属性。 - 外部配置文件: Spring Boot支持在不同位置的外部配置文件中定义配置属性。可以通过指定
spring.config.name
和spring.config.location
属性来指定外部配置文件的名称和路径。例如,可以使用--spring.config.name=myconfig --spring.config.location=/path/to/config/
来指定自定义的配置文件。 @ConfigurationProperties
注解: 可以使用@ConfigurationProperties
注解将配置属性绑定到Java类中。通过在Java类中定义与配置属性对应的字段或方法,Spring Boot会自动将配置文件中的属性值注入到该类中。