Maven
1.dependency
groupId
定义附属的理论我的项目
artifactId
定义我的项目中的一个模块
version
定义依赖或我的项目的版本
2.maven依赖 生命周期scope
compile
默认值,示意以后依赖参加我的项目的编译、测试、运行阶段,属于强依赖,打包时,会打到包里去
test
仅仅参加测试,包含测试用例的编译和执行,比方Junit
runtime
依赖仅参加运行周期中的应用,个别这种类库都是接口与实现相拆散的类库,比方JDBC,在编译时依赖相干的接口,在具体运行时,须要mysql等驱动程序
provided
该依赖在打包过程中,不须要打进去,这个由运行环境提供,比方tomcat或者根底类库等
system
应用上与provided雷同,不同之处在于该依赖不从maven仓库中提取,而是从本地文件系统中提取,其会参加systemPath的属性进行提取依赖
import
只能在dependencyManagement中应用,能解决Maven单继承问题,import依赖关系实际上并不参加限度依赖关系的传递性
3.本地jar包装置到Maven仓库
mvn install:install-file
-Dfile=本地jar包门路
-DgroupId=jar包的groupId
-DartifactId=jar包artifactId
-Dversion=jar包版本
-Dpackaging=jar
Mybatis
1.MyBatis 编程步骤
- 创立 SqlSessionFactory 对象。
- 通过 SqlSessionFactory 获取 SqlSession 对象。
- 通过 SqlSession 取得 Mapper 代理对象。
- 通过 Mapper 代理对象,执行数据库操作。
- 执行胜利,则应用 SqlSession 提交事务。
- 执行失败,则应用 SqlSession 回滚事务。
- 最终,敞开会话。
2.MyBatis 如何执行批量插入
应用Sql 拼接,有语句大小限度
INSERT INTO [表名]([列名],[列名]) VALUES([列值],[列值])),([列值],[列值])),([列值],[列值]));
- 应用Mybatis 的批量插入方式
private static SqlSessionFactory sqlSessionFactory;@Testpublic void testBatch() { // 创立要插入的用户的名字的数组 List<String> names = new ArrayList<>(); names.add("张三"); names.add("李四"); names.add("李二"); names.add("王五"); // 取得执行器类型为 Batch 的 SqlSession 对象,并且 autoCommit = false ,禁止事务主动提交 try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH, false)) { // 取得 Mapper 对象 UserMapper mapper = session.getMapper(UserMapper.class); // 循环插入 for (String name : names) { mapper.insertUser(name); } // 提交批量操作 session.commit(); }}
- 应用循环一条条插入
3.Mybatis 的 XML Mapper文件中,不同的 XML 映射文件,id 是否能够反复?
不同的 XML Mapper 文件,如果配置了 "namespace"
,那么 id 能够反复;如果没有配置 "namespace"
,那么 id 不能反复。毕竟"namespace"
不是必须的,只是最佳实际而已。
起因就是,namespace + id
是作为 Map<String, MappedStatement>
的 key 应用的。如果没有 "namespace"
,就剩下 id ,那么 id 反复会导致数据相互笼罩。如果有了 "namespace"
,天然 id 就能够反复,"namespace"
不同,namespace + id
天然也就不同。
4.简述 Mybatis 的 XML 映射文件和 Mybatis 外部数据结构之间的映射关系
Mybatis 将所有 XML 配置信息都封装到 All-In-One 重量级对象Configuration外部。
在 XML Mapper 文件中:
<parameterMap>
标签,会被解析为 ParameterMap 对象,其每个子元素会被解析为 ParameterMapping 对象。<resultMap>
标签,会被解析为 ResultMap 对象,其每个子元素会被解析为 ResultMapping 对象。- 每一个
<select>
、<insert>
、<update>
、<delete>
标签,均会被解析为一个 MappedStatement 对象,标签内的 SQL 会被解析为一个 BoundSql 对象。
5.通常一个 XML 映射文件,都会写一个 Mapper 接口与之对应。请问,这个 Mapper 接口的工作原理是什么?Mapper 接口里的办法,参数不同时,办法能重载吗?
Mapper 接口,对应的关系如下:
- 接口的全限名,就是映射文件中的
"namespace"
的值。 - 接口的办法名,就是映射文件中 MappedStatement 的
"id"
值。 - 接口办法内的参数,就是传递给 SQL 的参数。
Mapper 接口是没有实现类的,当调用接口办法时,接口全限名 + 办法名拼接字符串作为 key 值,可惟一定位一个对应的 MappedStatement 。举例:com.mybatis3.mappers.StudentDao.findStudentById
,能够惟一找到 "namespace"
为 com.mybatis3.mappers.StudentDao
上面 "id"
为 findStudentById
的 MappedStatement 。
总结来说,在 Mybatis 中,每一个 <select />
、<insert />
、<update />
、<delete />
标签,都会被解析为一个 MappedStatement 对象。
另外,Mapper 接口的实现类,通过 MyBatis 应用 JDK Proxy 主动生成其代理对象 Proxy ,而代理对象 Proxy 会拦挡接口办法,从而“调用”对应的 MappedStatement 办法,最终执行 SQL ,返回执行后果。整体流程如下图:
其中,SqlSession 在调用 Executor 之前,会取得对应的 MappedStatement 办法。例如:DefaultSqlSession#select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler)
办法,代码如下:
// DefaultSqlSession.java@Overridepublic void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) { try { // 取得 MappedStatement 对象 MappedStatement ms = configuration.getMappedStatement(statement); // 执行查问 executor.query(ms, wrapCollection(parameter), rowBounds, handler); } catch (Exception e) { throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e); } finally { ErrorContext.instance().reset(); }}
Mapper 接口里的办法,是不能重载的,因为是全限名 + 办法名的保留和寻找策略
Spring
1.BeanFactory 与ApplicationContext 是干什么的,两者的区别
BeanFactory、ApplicationContext都代表容器,BeanFactory是一个根底接口,实现了容器根底的性能,ApplicationContext是器的高级状态,减少了许多了个性,顶级父类是BeanFactory。
跟FactoryBean的区别是:
FactoryBean 是一个Bean,用于生产润饰其余的Bean实例,典型利用是AOP代理类,应用'&'获取FactoryBean自身
BeanFactory 是一个工厂,是容器的顶层接口
2.BeanPostProcessor 的实现
Bean的后置处理器,是一个监听器,能够监听容器触发的事件。将它向IOC容器注册后,容器中治理的Bean具备了接管IOC容器事件回调的能力。BeanPostProcessor是一个接口类,有两个接口办法,postProcessBeforeInitialization提供Bean初始化前的回调入口;postProcessAfterInitialization 提供Bean初始化后的回调入口AbstractAutowireCapableBeanFactory#initializeBean
,这个类能够对我的项目中的Bean进行润饰,所有Bean都会调用该实现。
3.BeanDefinition 的实现
BeanDefinition形象了对Bean的定义,其是容器实现依赖反转性能的外围数据结构
4.Spring IOC容器的实现
Spring提供了各种各样的容器,有DefaultListableBeanFactory、FileSystemXmlApplicationContext等,这些容器都是基于BeanFactory,BeanFactory实现了容器的根底性能,包含containsBean可能判断容器是否含有指定名称的Bean,getBean获取指定名称参数的Bean等。
Spring通过refresh()
办法对容器进行初始化和资源的载入
首先通过ResourceLoader的Resource接口定位到存储Bean信息的门路
第二个过程是BeanDefinition载入,把定义好的Bean示意成IOC容器的外部数据结构BeanDefinition,通过定义BeanDefinition来治理利用的各种对象及依赖关系,其是容器实现依赖反转性能的外围数据结构
第三个过程是BeanDefinition注册,容器解析失去BeanDefinition后,须要在容器中注册,这由IOC实现BeanDefinitionRegistry接口来实现,注册过程是IOC容器外部保护了一个ConcurrentHasmap来保留失去的BeanDefinition。如果某些Bean设置了lazyinit属性,Bean的依赖注入会在这个过程事后实现,而不须要等到第一次应用Bean的时候才触发。
5.Spring DI(依赖注入)的实现
Spring 的依赖注入产生在以下两种状况:
- 用户第一次调用
getBean()
办法 - bean配置了lazy-init=false,容器会在解析注册Bean定义的时候进行预实例化,触发依赖注入
getBean()办法定义在BeanFactory接口中,具体实现在子类AbstractBeanFactory中,过程如下:
- getBean()办法最终是委托给doGetBean办法来实例化Bean,doGetBean办法会先从缓存中找是否有创立过,没有再从父工厂中去查找
- 如果父工厂中没有找到,会依据Bean定义的模式来创立Bean,单例模式的Bean会先从缓存中查找,确保只创立一次,原型模式的Bean每次都会创立,其余模式依据配置的不同生命周期来抉择适合的办法创立。创立的具体方法通过匿名类中getObject,并委托给createBean来实现bean的实例化。
- 在createBean中,先对Bean进行一些筹备工作,而后会利用配置的前后处理器,如果创立胜利就间接返回该代理Bean
- 没有创立代理Bean的话,会创立指定的Bean实例,委托给doCreateBean实现,该过程会通过提前实例化依赖Bean,并写入缓存来解决Bean的循环依赖
- 通过populateBean注入Bean属性,并调用init-method初始化办法
- 注册实例化的Bean
6.Spring如何解决循环依赖问题
比方A依赖B, B依赖A.
创立A的时候,会把A对应的ObjectFactory放入缓存中,当注入的时候发现须要B, 就会去调用B对象,B对象会先从singletonObjects 查找,没有再从earlySingletonObjects找,还没有就会调用singletonFactory创建对象B,B对象也是先从singletonObjects,earlySingletonObjects,singletonFactories三个缓存中搜寻,只有找到就返回,相干办法AbstractBeanFactory.doGetBean()
7.Spring Bean 生命周期
- Bean实例的创立
- 为Bean实例设置属性
- 调用Bean的初始化办法
- 利用能够通过IOC容器应用Bean
- 当容器敞开时,调用Bean的销毁办法
8.Spring Bean的作用域,默认是哪个?
Singleton: 单例模式,IOC容器中只会存在一个共享的Bean实例,是Spring的默认模式;
prototype: 原型模式,每次从IOC容器获取Bean的时候,都会创立一个新的Bean实例;
request: 每次申请都生成一个实例;
session: 在一次申请会话中,容器返回该Bean的同一实例,不同的Session申请不同的实例,实例仅在该Session内无效,申请完结,则实例销毁;
globalsession: 全局的session中,容器返回该Bean的同一个实例,仅在portlet context 无效
9.AOP两种代理形式
AOP面向切面编程,能够通过预编译和运行时动静代理,实现在不批改源代码的状况下给程序动静增加性能。
程序入口是:AbstractAutowireCapableBeanFactory -> doCreateBean -> initializeBean -> applyBeanPostProcessorsAfterInitialization
默认策略是如果指标类是接口,则应用JDK动静代理技术,否则应用Cglib来生成代理
JDK 动静代理
次要波及java.lang.reflect中的两个类,Proxy 和 InvocationHandler
InvocationHandler是一个接口,通过实现该接口来定义横切逻辑,并通过反射机制调用指标类的代码,动静将横切逻辑和业务逻辑编辑在一起。只能为实现接口的类创立代理。
Cglib 代理
是一个弱小的高性能,高质量的代码生成类库,能够在运行期扩大Java类与实现Java接口,Cglib封装了asm,能够在运行期动静生成新的class。能够是一般类,也能够是实现接口的类
10.Spring AOP实现原理
通过JDK代理,和CGLIB代理两种形式生成动静代理,结构不同的回调办法来对拦截器链的调用,比方JdkDynamicAopProxy的invoke办法,Cglib2AopProxy中的DynamicAdvisedInterceptor的intercept办法,首先获取配置的拦截器链,通过ReflectiveMethodInvocation的proceed办法实现对拦截器链的调用, 首先须要依据配置来对拦截器进行匹配,匹配胜利后,拦截器发挥作用,在对拦截器调用实现后,再对指标对象的办法调用,这样一个一般的Java对象的性能就失去了加强
11.哪些办法不能被AOP加强
- 基于JDK代理,除public外的其余所有办法,包含public static也不能被加强
- 基于CGLIB代理,因为其通过生成指标类子类的形式来加强,因而不能被子类继承的办法都不能被加强,private、static、final 办法
12.AOP 切点函数
类别 | 函数 | 入参 | 阐明 |
---|---|---|---|
办法切入点函数 | execution() | 办法匹配模式串 | 满足某一匹配模式的所有指标类办法连接点。<br/>如execution(* greetTo(..)) 示意所有指标类中的greetTo()办法 |
@annotation() | 办法注解类名 | 标注了特定注解的指标类办法连接点。<br/>如@annotation(com.smart.anno.NeedTest)示意任何标注了@NeedTest注解的指标类办法 | |
办法入参切入点函数 | args() | 类名 | 通过判断指标类办法运行时入参对象的类型定义指定连接点。<br/>如args(com.smart.Waiter)示意所有有且仅有一个按类型匹配于Waiter入参的办法 |
@args() | 类型注解类名 | 通过判断指标类办法运行时入参对象的类是否标注特定注解来指定连接点。<br/>如@args(com.smart.Monitorable)示意任何这样的一个指标办法:它有一个入参且入参对象的类 标注@Monitorable注解 | |
指标类切点函数 | within() | 类名匹配串 | 示意特定域下的所有连接点。 如within(com.smart.service.*) 示意com.smart.service 包中的所有连接点,即包中所有类的所有办法; 而within(com.smart.service.*Service)示意在com.smart.service包中所有以Service结尾的类的所有连接点 |
target() | 类名 | 如果指标类按类型匹配于指定类,则指标类的所有连接点匹配这个切点 如通过target(com.smart.Waiter),Waiter及Waiter实现类NaiveWaiter中的所有连接点都匹配该切点 | |
@within() | 类型注解类名 | 如果指标类型按类型匹配于某个类A, 且类A标注了特定注解,则指标类的所有连接点匹配该切点 如@within(com.smart.Monitorable) 如果Waiter类标注了@Monitorable注解,则Waiter的所有连接点都匹配该切点, 说是这个注解也会匹配Waiter的子类,但试了后并没有用,Spring 5.1 | |
@target | 类型注解类名 | 如果指标类标注了特定注解,则指标类的所有连接点都匹配该切点。 如@target(com.smart.Monitorable),如果NaiveWaiter标注了@Monitorable,则NaiveWaiter的所有连接点都匹配这个切点 | |
代理类切点函数 | this() | 类名 | 代理类按类型匹配于指定类,则被代理的指标类的所有连接点都匹配该切点。 如this(com.smart.Seller) 匹配任何运行期对象为Seller类型的类 |
13.六种加强类型
- @Before 前置加强,相当于BeforeAdvice
- @AfterReturning 后置加强,相当于AfterReturningAdvice
- @Around 盘绕加强,相当于MethodInterceptor
- @AfterThrowing 抛出加强,相当于ThrowsAdvice
- @AfterFinal加强,不论抛出异样还是失常退出,都会执行,没有对应的加强接口,个别用于开释资源
- @DeclareParents 引介加强,相当于IntroductionInterceptor
14.Spring MVC运行流程
- 客户端申请到DispatcherServlet
- DispatcherServlet依据申请地址查问映射处理器HandleMapping,获取Handler
- 申请HandlerAdatper执行Handler
- 执行相应的Controller办法,执行结束返回ModelAndView
- 通过ViewResolver解析视图,返回View
- 渲染视图,将Model数据转换为Response响应
- 将后果返回给客户端
2,3 两步都在DispatcherServlet -> doDispatch中进行解决
15.Spring MVC 启动流程
- 在Tomcat启动的时候,ServletContext 会依据web.xml加载ContextLoaderListener,继而通过ContextLoaderListener 载入IOC容器,具体过程有ContextLoader实现,这个IOC容器是在Web环境下应用的WebApplicationContext, 这个容器在前面的DispatcherServlet中作为双亲根上下文来应用
- IOC容器加载实现后,开始加载DIspatcherServlet,这是Spring MVC的外围,由
HttpServletBean -> initServeltBean
启动(HttpServletBean是DispatcherServlet的父类,HttpServletBean继承了HttpServlet),最终调用DispatcherServlet -> initStrategies
办法对HandlerMapping、ViewResolver等进行初始化,至此,DispatcherServelt就初始化实现了,它持有一个第一步实现的上下文作为根上下文,以本人的Servlet名称命名的IOC容器,这个容器是一个WebApplicationContext对象。
16.Spring 事务实现形式、事务的流传机制、默认的事务类别·
事务实现形式
- 申明式,在xml文件中通过tx:advice来配置事务
- 注解式,在xml文件中定一个事务管理对象(DataSourceTransactionManager),而后退出\<tx:annotation-driven/>, 这样就能够应用@Transactional注解配置事务
事务的流传机制
一共7种事务流传行为,相干code:
AbstractPlatformTransactionManager -> getTransaction
PROPAGATION_REQUIRED
如果以后没有事务,则新建一个事务;如果曾经存在一个事务,则退出到这个事务中,这也是默认事务类别
PROPAGATION_SUPPORTS
反对以后事务。如果以后没有事务,则以非事务形式执行
PROPAGATION_MANDATORY
应用以后事务。如果以后没有事务,则抛出异样
PROPAGATION_REQUIRES_NEW
新建事务。如果以后存在事务,则把以后事务挂起
PROPAGATION_NOT_SUPPORTED
以非事务形式执行操作。如果以后存在事务,则把以后事务挂起
PROPAGATION_NEVER
以非事务形式执行。如果以后存在事务,则抛出异样
PROPAGATION_NESTED
如果以后存在事务,则在嵌套事务内执行;如果以后没有事务,则执行与PROPAGATION_REQUIRED相似的操作
17.Spring 事务模版
TransactionTemplate 事务模版是对原始事务管理形式的封装,原始事务管理是基于TransactionDefinition
、PlatformTransactionManager
、TransactionStatus
的编程式事务
事务模版次要通过execute(TransactionCallback<T> action)来执行事务,TransactionCallback 有两种形式一种是有返回值TransactionCallback,一种是没有返回值TransactionCallbackWithoutResult。
18.Spring 事务底层原理
事务的筹备
在申明式事务处理中,须要Ioc容器配置TransactionProxyFactoryBean,其父类AbstractSingletonProxyFactoryBean实现了InitializingBeean接口,因而在初始化过程中会调用afterPropertiesSet办法,这个办法实例化了ProxyFactory, 并为其设置了告诉,指标对象后,最终返回Proxy代理对象,对象建设起来后,在调用其代理办法的时候,会调用相应的TransactionInterceptor拦截器,在这个调用中,会依据TransactionAttribute配置的事务属性进行配置,为事务处理做好筹备
事务拦截器实现
通过TransactionProxyFactoryBean的AOP包装后,此时如果对指标对象进行办法调用,实际上起作用的是一个Proxy代理对象,拦截器会拦挡其中的事务处理,在调用Proxy对象的代理办法时会触发invoke回调,其中会依据事务属性配置决定具体用哪一个PlatformTransactionManager来实现事务操作
19.什么是 Spring Boot?
Spring Boot是 Spring 的子项目,正如其名字,提供 Spring 的疏导( Boot )的性能。
通过 Spring Boot ,咱们开发者能够疾速配置 Spring 我的项目,引入各种 Spring MVC、Spring Transaction、Spring AOP、MyBatis 等等框架,而无需一直反复编写沉重的 Spring 配置,升高了 Spring 的应用老本。
20.Spring Boot启动流程
- 启动类外面调用SpringApplication.run办法
- 在run办法中,首先结构SpringApplication对象,而后再调用run办法
在结构SpringApplication对象中,做了如下工作
- 将sources放入primarySources变量中
- 判断webApplication是什么类型的
- 设置ApplicationContextInitializer,ApplicationListener,通过加载META-INF/spring.factories中配置的类
- 找到main办法找到启动主类
run办法中,做的工作
- StopWatch次要是监控启动过程,统计启动工夫,检测利用是否曾经启动或者进行。
- 加载SpringApplicationRunListener(也是通过META-INF/spring.factories),默认加载的是EventPublishingRunListener
- 调用RunListener.starting()办法。
- 依据args创立利用参数解析器ApplicationArguments;
- 筹备环境变量:获取环境变量environment,将利用参数放入到环境变量持有对象中,监听器监听环境变量对象的变动(listener.environmentPrepared)
- 打印Banner信息(SpringBootBanner)
- 创立SpringBoot的利用上下文(AnnotationConfigEmbeddedWebApplicationContext)
- prepareContext上下文之前的筹备
- refreshContext刷新上下文
- afterRefresh(ApplicationRunner,CommandLineRunner接口实现类的启动)
- 返回上下文对象
21.什么是 Spring Boot 主动配置?
- Spring Boot 在启动时扫描我的项目所依赖的 jar 包,寻找蕴含
spring.factories
文件的 jar 包。 - 依据
spring.factories
配置加载 AutoConfigure 类。 - 依据
@Conditional
等条件注解的条件,进行主动配置并将 Bean 注入 Spring IoC 中。