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.Constructor; Constructor<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层的开发
Hibernate Mybatis 映射关系 全表映射 半自动映射 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个角色 - 注册中心、生产者、消费者。在具体项目上,我们应该会见过具体使用。
| 生产者(服务提供方) | 消费者 |
|---|---|
![]() | ![]() |
Spring框架核心概念







2991

被折叠的 条评论
为什么被折叠?



