Spring
1、Spring是什么?
Spring是一款开源的轻量级Java框架,主要是用来提高Java开发人员的效率
Spring框架包含很多模块:自带的IoC、AOP,集成的第三方组件(任务、调度、缓存)
2、Spring核心模块?
Spring Core:最核心的模块,提供IoC依赖注入
Spring AOP:面向切面的编程实现
Spring Web:
- Spring-Web:web功能基础支持
- Spring-WebMvc:提供对SpringMVC的实现
- Spring-websocket:
- spring-webflux:
Spring Test:支持Junit
3、Spring、SpringMVC、SpringBoot的区别?
Spring MVC是Spring中的一个模块,主要提供构建MVC架构的Web程序的能力
SpringBoot是在Spring基础上做了一些简化配置的操作,也简化了Spring的开发
4、什么是IoC?
控制反转是一种设计思想。将原本在程序汇总手动创建对象的控制权交给Spring框架来管理
- 控制:指的是对象创建的权力
- 反转:控制权交给外部环境(Spring框架、IoC容器)
将对象之间相互依赖的关系交给IoC容器管理,并由IoC容器完成对象的注入。 ,IoC容器实际上就是一个Map(key,value)
org.springframework.beans 和 org.springframework.context 这两个包是 IoC 实现的基础
5、什么是AOP?
面向切面变成,将一些与业务无关,却为业务模块所共同调用的逻辑和责任(日志、事务处理、权限控制)等封装起来,减少系统的重复代码,降低耦合
AOP是基于动态代理的,如果要代理的对象,实现了某个接口,那么 Spring AOP 会使用 JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候 Spring AOP 会使用 Cglib 生成一个被代理对象的子类来作为代理
6、Spring AOP和Aspect AOP的区别?
Spring AOP属于运行时增强,基于代理,AspectJAOP属于编译时增强,基于字节码
7、什么是Spring Bean?
被IoC容器管理的对象成为Spring Bean。通过配置让Spring知道,xml、注解、Java配置类等
如何将一个类声明为Spring Bean:
@Component:标注类是组件@Respository:对应的是持久层,也就是DAO层,与数据库相关@Service:对应的是服务层@Controller:对应的是Spring MVC的控制层,接收用户请求并调用服务层返回给前端
8、@Component 和@Bean的区别?
@Component 是作用在类上的,@Bean注解作用于方法
@Component 通常是通过类路径扫描来自动侦测以及自动装配到 Spring 容器中
9、使用和注入Bean的时候有哪些注解?
@Autowired:Spring 2.5+。Spring内置注解,默认注入方式是根据类型进行匹配,存在多个满足条件的选择时,会使用名称匹配的注入方式,通常是类名首字母小写
// 报错,byName 和 byType 都无法匹配到 bean
@Autowired
private SmsService smsService;
// 正确注入 按照变量名:SmsServiceImpl1 对象对应的 bean
@Autowired
private SmsService smsServiceImpl1;
// 正确注入 SmsServiceImpl1 对象对应的 bean
// smsServiceImpl1 就是我们上面所说的名称
@Autowired
@Qualifier(value = "smsServiceImpl1") // 显示指定名称不是依赖变量的名称
private SmsService smsService;
@Resource:JDK提供的注解。默认注入方式是通过名称 byName 注入,如果通过名称无法找到的话,注入方式会变成byType
// 报错,byName 和 byType 都无法匹配到 bean
@Resource
private SmsService smsService;
// 正确注入 SmsServiceImpl1 对象对应的 bean
@Resource
private SmsService smsServiceImpl1;
// 正确注入 SmsServiceImpl1 对象对应的 bean(比较推荐这种方式),显示指定名称
@Resource(name = "smsServiceImpl1")
private SmsService smsService;
@Inject:
10、Bean的作用域有哪些?
- singleton:全局唯一bean实例,Spring 中bean默认都是单例的
- prototype:每次请求都会创建一个新的bean实例
- request:每一次http请求都会产生一个新的bean,在本次请求内使用
- session:每一次来自新 session 的 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效
如何配置Bean的作用域?
xml形式:
<bean id = "..." class="..." scope="singleton"></bean>
注解形式
@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
public Person personPrototype() {
return new Person();
}
11、单例Bean的线程安全问题
有状态的bean:
无状态的bean:
解决办法:
- 在Bean中避免定义可变的成员变量
- 在类中定义一个
ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal中
12、Bean的声明周期###
13、Spring MVC
分为三部分:Model、View、Controller,通过这种结构更清晰的实现了API的开发
SoringMVC的工作原理
流程说明(重要):
- 客户端(浏览器)发送请求,直接请求到
DispatcherServlet。 DispatcherServlet根据请求信息调用HandlerMapping,解析请求对应的Handler。- 解析到对应的
Handler(也就是我们平常说的Controller控制器)后,开始由HandlerAdapter适配器处理。 HandlerAdapter会根据Handler来调用真正的处理器开处理请求,并处理相应的业务逻辑。- 处理器处理完业务后,会返回一个
ModelAndView对象,Model是返回的数据对象,View是个逻辑上的View。 ViewResolver会根据逻辑View查找实际的View。DispaterServlet把返回的Model传给View(视图渲染)。- 把
View返回给请求者(浏览器)
14、Spring中使用到的设计模式
- 代理模式:Spring AOP功能的实现
- 单例模式:Spring中bean默认都是单例的
- 工厂模式:Spring使用工厂模式通过
BeanFactory、ApplicationContext创建 bean 对象 - 适配器模式 : Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配
Controller
Spring事务
1、Spring 管理事务的方式
- 注解形式:
@Transactional
2、事务传播行为
1) required(默认属性)
** Spring中默认传播类型**。
TransactionDefinition.PROPAGATION_REQUIRED
如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。 被设置成这个级别时,会为每一个被调用的方法创建一个逻辑事务域。如果前面的方法已经创建了事务,那么后面的方法支持当前的事务,如果当前没有事务会重新建立事务。
2) Mandatory 支持当前事务,如果当前没有事务,就抛出异常。
3) Never 以非事务方式执行,如果当前存在事务,则抛出异常。
4) Not_supports 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
5) requires_new 始终新建事务,如果当前存在事务,把当前事务挂起。
6) Supports 支持当前事务,如果当前没有事务,就以非事务方式执行。
7) Nested 支持当前事务,新增Savepoint点,与当前事务同步提交或回滚。 嵌套事务一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚。
常用的类型:required、not_supports、requires_new
常问问题:Nested与requires_new的区别?
3、事务隔离级别
5种隔离级别。
Spring事务隔离级别比数据库事务隔离级别多一个default
1) DEFAULT (默认) 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别(RR)
另外四个与JDBC的隔离级别相对应。
2) READ_UNCOMMITTED (读未提交) 这是事务最低的隔离级别,它允许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。
3) READ_COMMITTED (读已提交) 保证一个事务修改的数据提交后才能被另外一个事务读取,另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。
4) REPEATABLE_READ (可重复读) 这种事务隔离级别可以防止脏读、不可重复读,但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了不可重复读。
5) SERIALIZABLE(串行化) 这是花费最高代价但是最可靠的事务隔离级别,事务被处理为顺序执行。除了防止脏读、不可重复读外,还避免了幻读。
4、事务回滚时机
使用方式:@Transactional(rollBackFor="Exception")
不配置exception时,默认是遇到RuntimeException的时候才会回滚
5、不持久化一个字段方式
static String transient1; // not persistent because of static
final String transient2 = "Satish"; // not persistent because of final
transient String transient3; // not persistent because of transient
@Transient // 使用该注解,可以将PO对象中的某个字段不持久化到数据库
String transient4; // not persistent because of @Transient
注解
5、Spring、SpringBoot常见注解
@SpringBootApplication:启动类的基础注解,作用相当于=@Configuration、@EnableAutoConfiguration、@ComponentScan 注解的集合
@Autowire:自动导入对象到类中
@Component @Repository @Service @Controller
@RestController @Controller和@ResponseBody的合集
@Scope:声明Spring Bean的作用域
@Configuration :声明配置类,可以使用@Component注解替代
@Post、@Get、@Delete、@Put:http的请求类型
@GetMapping("users")
@RequestMapping(value="/users",method=RequestMethod.GET)
@PostMapping("users")
@RequestMapping(value="/users",method=RequestMethod.POST)
@PutMapping("/users/{userId}")
@RequestMapping(value="/users/{userId}",method=RequestMethod.PUT)
@DeleteMapping("/users/{userId}")
@RequestMapping(value="/users/{userId}",method=RequestMethod.DELETE)
@PathVariable用于获取路径参数,@RequestParam用于获取查询参数。
@RequestBody :用于读取 Request 请求(可能是 POST,PUT,DELETE,GET 请求)的 body 部分并且Content-Type 为 application/json 格式的数据,接收到数据之后会自动将数据绑定到 Java 对象上去。一个请求只能有一个**@RequestBody,但是可以有多个@RequestParam和@PathVariable**
6、读取配置文件
@Value(${property})
@ConfigurationProperties(prefix = "library")
7、返回Json数据的一些处理
@JsonIgnoreProperties 作用在类上用于过滤掉特定字段不返回或者不解析。
@JsonIgnore一般用于类的属性上
Spring自动装配原理
1、什么是 SpringBoot 自动装配?
通过注解或者一些简单的配置就能在Spring Boot的帮助下实现某种功能
需要引入依赖:spring-boot-starter-XXX
2、SpringBoot 是如何实现自动装配的?如何实现按需加载?
@SpringBootApplication注解,该注解包含三部分:
1、@EnableAutoConfiguration:重点!!!启动SpringBoot的自动配置机制。@EnableAutoConfiguration底层也是通过AutoConfigurationImportSelector类实现的
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage //作用:将main包下的所有组件注册到容器中
@Import({AutoConfigurationImportSelector.class}) //加载自动装配类 xxxAutoconfiguration
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
@EnableAutoConfiguration -> AutoConfigurationImportSelector.class -> ImportSelector 接口 -> selectImports()方法
该方法用于获取所有符合条件的类全限定名,这些类需要被加载到IoC容器中
该类的实现流程:
private static final String[] NO_IMPORTS = new String[0];
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// <1>.判断自动装配开关是否打开
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
//<2>.获取所有需要装配的bean
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata); // 重点!!!
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();
// getAutoConfigurationEntry 的具体实现
AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
//<1>.
if (!this.isEnabled(annotationMetadata)) { // 判断自动装配开关是否打开?默认spring.boot.enableautoconfiguration=true
return EMPTY_ENTRY;
} else {
//<2>.
AnnotationAttributes attributes = this.getAttributes(annotationMetadata); // 获取EnableAutoConfiguration注解中配置的 exclude 和 excludeName
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes); // 重点!!!
//<4>.
configurations = this.removeDuplicates(configurations);
// 获取SpringBootApplication注解配置上的exclude的配置类,过滤掉
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 过滤一遍
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
List configurations = this.getCandidateConfigurations(annotationMetadata, attributes); // 重点!!! 例如项目有XXX-starter的依赖,这个依赖下的META-INF/spring.factories被读取到,整个Spring Boot Starter 下的META-INF/spring.factories都会被读取到
每次读取到的XXXConfiguration 也会经过一次过滤
2、@Configuration:允许在上下文中注册额外的bean或者导入其配置
3、@ComponentScan:扫描被@Service、@Component、@Controller注解标注的Bean,默认会扫描启动类本身所在包下所有的类,
@ComponentScan(excludeFilters = { // 可以指定剔除不加载某些class
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
- 如何实现一个 Starter?
S1:创建一个模块
S2:定义一个XXXAutoConfiguration的类,使用@Configuration注解标注
S3:模块下resources目录下创建META-INF目录,该目录下添加spring.factories文件,文件中添加org.springframework.boot.autoconfigure.EnableAutoConfiguration=XXXAutoConfiguration(类的全路径名)
Spring 中的设计模式
工厂模式:Spring 使用工厂模式可以通过BeanFactory 或者ApplicationContext创建bean对象
BeanFactory:延迟注入(使用到某个 bean 的时候才会注入),相比于ApplicationContext来说会占用更少的内存,程序启动速度更快。ApplicationContext:容器启动的时候,不管你用没用到,一次性创建所有 bean 。BeanFactory仅提供了最基本的依赖注入支持,ApplicationContext扩展了BeanFactory,除了有BeanFactory的功能还有额外更多功能,所以一般开发人员使用ApplicationContext会更多。
单例模式:
Spring 通过 ConcurrentHashMap 实现单例注册表的特殊方式实现单例模式
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64); // key是beanName,value是Object对象
Spring Cloud
什么是Spring Cloud?
微服务系统架构的一站式解决方案。提供了一套简易的编程模型:支持服务注册发现、配置中心、消息总线、负载均衡、数据监控等
\