1、聊一下什么是Spring,以及核心思想?
主要有两大思想,IOC和AOP
(1)IOC是控制反转,就是控制权的转移,原先我们自己去创建对象的过程,现在交由Spring容器来管理,使得我们不用专注于对象的生死存亡,同时将对象的创建由原来的编译时延期到现在的运行时。
使用IOC容器来创建对象有两种方式,分别是xml方式和注解方式。
①先说一下xml方式:只需在xml配置文件中声明一个bean标签,并指定bean的id,和此bean的类型class,就可以创建一个对象了。如果需要注入属性,我们也有很多种方式注入,比如set注入(需要在对象实体中声明setter方法)、构造器注入(同样需要在对象实体中声明相应的构造器)、p命名空间注入,这个方式需要在头部引入相关的名称空间,等等。当然属性的注入支持多种类型的属性注入,有List、Map等等,使用相应的标签即可。在程序中如果需要获取注入到ioc容器中的对象,则需通过ApplicationContext的getBean(id方法将对象取出,这时候的对象就可以使用了。
②再说下注解方式:使用注解的前提是在xml配置文件中开启了注解扫描功能context:component-scan,需要定义一下要扫描的包。如果我们需要在程序中将一个对象交由springIOC容器去管理,我们可以使用@Component、@Service、@Controller、@Repository注解,这四个注解的功能其实是一样的,都是用于将类的对象放入Spring容器中,创建bean的实例,只不过使用的位置有些区别,component用在普通类、Service用在业务层、Controller用在控制层、Repository用在持久层。如果说在一个程序中需要使用刚刚放入到ioc容器的对象,可以使用@Autowired注解来将其注入到程序中,这时候对象是已经创建完成的,直接使用即可,比如说UserHandler中需要用到UserService,那就在UserService上加上@Service注解来进行实例化业务层的bean,然后在UserHandler中使用@Autowired private UserService userService进行注入。当然也可以使用@Resource注解来进行注入,具体的区别是@Autowired默认根据属性类型进行注入,而@Resource默认根据属性名称进行注入。还而已使用@Value注解来进行普通类型的属性注入,@Value("Tom") private String name;。
③也可以完全舍弃xml配置文件,这也是SpringBoot中的主要手段,声明一个配置类,类上使用@Configuration注解来标记此类是一个配置类。然后开启注解扫描功能,使用@ComponentScan("")注解,里面定义一下扫描的包即可。在此类中的方法上使用 @Bean注解,可以将此方法的return返回值作为一个bean实例放入到ioc容器中,相当于xml里面的bean标签
AOP是面向切面编程,将那些与业务无关,却为业务模块所使用的逻辑封装起来,比如说日志、通知,可以减少系统的重复代码,降低模块间的耦合度,能更好的进行扩展和维护。通俗地说:AOP可以在不修改源代码的基础上进行功能的添加、增强
Spring框架一般都是基于AspectJ实现AOP操作。有两种方式,一个是xml配合文件,一个是注解方式。
①xml配置文件:实现AOP需要在Spring配置文件中配置相应的通知和切入点。首先是要aop:pointcut来定义切入点,需要指定expression切入点表达式属性。然后使用aop:aspect来配置通知,method属性用来指定在哪个方法上应用此通知,pointcut-ref属性用于指定切入点,具体的有前置通知(在方法前执行)、后置通知(在方法后执行)、环绕通知(方法前后均执行)、最终通知(类似于finally,结束后执行,并且一定会执行)、异常通知(抛出异常后执行)。也可以使用AOP来实现事物功能,配置相应的aop:advisor切面和tx:advice事务通知,以及配置一下事物属性tx:attributes,使用tx:method可以为某些方法配置成只读,也可以配置某些方法的传播行为,以及何时回滚,这些增强配置完成后,将pointcut与当前的增强连接起来,就实现了一个AOP事物操作。
②注解方式:前提先在spring配置文件中开启注解扫描component-scan;然后实例化被增强的类,例如在User类上使用@Component注解来创建对象;接着定义一个代理类UserProxy来实现相应的增强方法,并且使用@Aspect注解来标记此类是一个增强类;配置文件中使用aspectj-***标签开启自动生成代理对象;里面的每个方法定义都需要使用@Around、@Before、@After等注解来声明此方法所对应的通知类型,并且在此注解的value属性中定义切入点表达式,声明切入点。如果多个方法使用了相同的切入点,可以使用@Pointcut注解进行抽取,然后在其他地方引用即可
2、Spring中有哪些容器
IOC有两大容器,分别是BeanFactory和ApplicationContext。BeanFactory是顶层接口,提供的是基础的IOC容器服务;而ApplicationContext是BeanFactory的子接口,提供更高级的IOC服务,比如有事件发布、国际化支持等等,当然我们正常情况下都是使用的ApplicationContext。ApplicationContext也有很多实现类:ClassPathXmlApplicationContext主要用在在类路径加载xml文件的场景,FileSystemXmlApplicationContext主要用在在文件系统中加载xml文件的场景,XmlWebApplicationContext主要用在在Web环境中加载xml文件的场景。
3、Spring的工作机制?
定位xml文件、解析xml文件、注册bean、获取bean实例。
通过applicationContext的实现类ClassPathResource来找到xml文件;接着通过BeanDefinition解析xml文件,解析后的结果封装成一个BeanDefinitionHolder;然后通过DefaultListableBeanFactory类来创建ConcurrentHashMap集合,通过beanDefinition提供的信息,将bean的name和class保存在Map集合中,完成bean的注册和实例化;最后通过BeanFactory的getBean()来获取bean实例。
4、BeanFactory和FactoryBean的区别?
BeanFactory是顶层IOC容器服务接口,提供了基本的容器服务。
而FactoryBean是一个Bean,Bean主要分为普通bean和工厂bean,而这个工厂bean就是FactoryBean。如果我们想自己来实现一个bean的创建操作,可以通过FactoryBean接口实现。我们可以通过该实现接口来定制实例化Bean的逻辑。接口中主要含有3个方法:
T getObject():返回由FactoryBean创建的Bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中单实例的缓存池中。
Class> getObjectType():返回FactoryBean创建的Bean类型,也就是bean标签中配置的class属性,要与这里的方法返回的类型要一致。
default boolean isSingleton():返回Bean实例是singleton还是prototype的,默认是返回true,也就是使用singleton的
如果有一个类,比如说User类,并且实现了FactoryBean接口,重写了getObject()、getObjectType()、isSingleton()方法,那么在使用bean标签进行实例化bean时,在class属性是getObjectType()的值的全限定名。当取出对象getBean("user")时,Spring通过反射机制发现要返回的User类实现了FactoryBean接口,那么他会调用接口方法User.getObject()方法返回此实例,而不是使用默认的方法进行返回。因此也能说明,配置文件定义普通bean时,定义的bean类型就是返回类型,而定义工厂bean时,定义的bean类型可以和返回类型不一样,完全由getObject()来决定的。
5、AOP的底层实现是怎样的?
①在有接口的情况下,比如说对UserServiceImpl实现类进行AOP增强,则底层使用的是动态代理,创建接口实现类的代理对象,进行增强类中的方法
②在没有接口的情况下,底层使用的是cglib动态代理,创建子类的代理对象,进行增强类中的方法
动态代理的话就是新建一个代理类,实现InvocationHanler接口,重写invoke方法,此方法就是增强的功能,注意需要将被代理的对象属性注入到代理类中,即UserServiceImpl。在使用被代理的类方法时,我们可以调用Proxy.newProxyInstance()方法创建代理对象,传入动态代理的类加载器、被代理的接口、以及代理类对象,然后调用代理对象的相关方法,就能实现相应的增强功能
6、说一下bean的生命周期
分两种情况:一个是不带后置处理器的,一个是带后置处理器的
(1)不带后置处理器,总共5步:
①通过无参构造器构造一个bean的实例
②对bean中的属性进行设值和设置对其他bean的引用,调用setter方法,进行依赖注入
③调用bean的初始化方法
④这时bean就可以使用了
⑤容器关闭时,调用bean的销毁方法。
(2)带后置处理器,总共7步:
①通过无参构造器构造一个bean的实例
②对bean中的属性进行设值和设置对其他bean的引用,调用setter方法,进行依赖注入
③调用初始化方法之前,首先执行后置处理器的postProcessBeforeInitialization()方法,这是我们自己写的逻辑,在初始化之前完成一些特定的任务
④调用bean的初始化方法
⑤执行后置处理器的postProcessAfterInitialization()方法,对完成初始化的bean进行后续的额外操作
⑥这时bean就可以使用了
⑦容器关闭时,调用bean的销毁方法。
7、为什么要使用 spring?
简化开发,各个层次解耦。原本的MVC三层结构是紧密相连的,频繁使用了new创建对象操作,如果一个功能改变,其他两层的代码可能也会发生改变,这类系统进行维护和更新会变得繁琐。使用了Spring可以大大减少代码的修改,因为耦合度低了,对象的创建完全交由IOC容器完成,即时代码修改了,也不会对其他层次的代码造成太大影响。同时Spring支持aop编程,能更方便地在不修改源代码的基础上进行功能的增强。
8、Spring框架主要有哪些模块?
①Spring AOP 面相切面编程
②Spring ORM Hibernate|mybatis|JDO
③Spring Core 提供bean工厂 IOC
④Spring Dao JDBC支持
⑤Spring Context 提供了关于UI支持,邮件支持等
⑥Spring Web 提供了web的一些工具类的支持
⑦Spring MVC 提供了web mvc , webviews , jsp ,pdf ,export
9、spring 常用的注入方式有哪些?
①setter注入
②构造器注入
③p命名空间注入
④c命名空间注入
⑤接口注入(如@Service注解)
10、spring 中的 bean 是线程安全的吗?
不是,容器本身并没有提供Bean的线程安全策略
11、spring 支持几种 bean 的作用域?
常用的有singleton单例和prototype原型,还有较为少见的request、session等
12、spring 自动装配 bean 有哪些方式?
①byName根据名称进行自动装配
②byType根据类型自动装配
③constructor根据构造器自动装配
④no人工指定
13、spring 事务实现方式有哪些
①使用编程式事物,手动调用commit()、rollback()等方法进行事物管理
②基于注解 @Transactional的声明式事物管理
③基于AspectJ AOP的xml配置文件来配置声明式事物
④基于TransactionProxyFactoryBean事务代理工厂的声明式事务管理
1、说一下spring mvc运行流程?
①前端发送请求,前端控制器DispatcherServlet进行拦截
②前端控制器DispatcherServlet调用处理器映射器HandlerMapping,根据url寻找相应的Handler
③寻找到Handler后生成处理器执行链HandlerExecutionChain,并返回给前端控制器
④前端控制器DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter,准备执行相应的handler
⑤执行Handler,返回ModelAndView到处理器适配器HandlerAdapter
⑥处理器适配器HandlerAdapter将Handler执行的结果ModelAndView返回到前端控制器DispatcherServlet
⑦前端控制器DispatcherServlet将ModelAndView传递给视图解析器ViewResolver
⑧视图解析器ViewResolver进行解析,返回View视图给前端控制器DispatcherServlet
⑨前端控制器DispatcherServlet进行渲染view视图,然后返回给用户
2、spring mvc 有哪些组件?
①前端控制器DispatcherServlet
②处理器Handler
③处理器映射器HandlerMapping
④处理器适配器HandlerAdapter
⑤拦截器HandlerInterceptor
⑥视图解析器ViewResolver
⑦视图View
⑧数据转换DataBinder
⑨消息转换组件HttpMessageConverter
3、@RequestMapping 的作用是什么?
用于接收请求,标识http请求地址与后端Controller层之间的映射关系,一般作用方法上,也能作用于类上。
该注解有6个属性:
value:指定请求地址
method:指定请求方式
consumes:指定请求提交的数据类型
produces:指定返回数据类型
params:指定请求中必须包含某些参数,才能进行处理
headers:指定请求中必须包含某些头部信息,才能进行处理
4、@Autowired 的作用是什么?
让spring进行bean的自动装配,默认根据ByType进行装配,即在IOC容器中寻找到类型匹配的实例对象进行注入
5、SpringMVC常用注解?
@Controller:用于标记一个类是控制层
@RequestMapping:用于定义请求
@Resource&@Autowired:进行bean的注入装配
@PathVariable:从请求路径中获取参数
@RequestParam:获取请求域中的参数
@ResponseBody:将对象放至response对象的body数据区,如json数据
@RequestBody:从request对象的body数据区获取对象
@RestController:是@Controller和@ResponseBody的合体
mybatis我遇到的问题不多,也希望各位不要仅复习下面这几个题目,仅供参考。
1、mybatis 中 #{}和 ${}的区别是什么?
①#{} 能够很大程度防止 sql 注入,${} 无法防止 sql 注入
②#{} 是预编译处理,${} 是字符串替换
Mybatis 在处理 #{} 时,会将 sql 中的 #{} 替换为 '?' ,调用 PreparedStatement 的 set 方法来赋值,会将所有传入的参数作为一个字符串来处理,假设有个字符串('' or 1=1),那么使用 # 则直接将此字符串包裹在引号 ' ' 内,有效防止了 sql 注入
Mybatis 在处理 ${} 时,就是把 ${} 替换成变量的值,相当于进行了拼接,并没有使用引号 ' ' 包裹住
2、mybatis 有几种分页方式?
①数组分页,java层面的分页方式,逻辑分页。获取所有数据后,使用 List 的 subList() 进行筛选,最原始的方式
②limit分页,直接在数据库中进行分页,物理分页
③RowBounds分页,java层面的分页方式,逻辑分页
④PageHelper分页插件,也是数据库层面的分页方式,物理分页
3、物理分页与逻辑分页的区别?
分页插件、limit 分页,都是物理分页,优点是效率高,缺点是不同的数据库有不同的写法,无法统一
RowBounds、数组分页是 java 层面的,因此是逻辑分页,优点是所有数据库都统一,缺点是效率低
尽量使用物理分页,因为没有必要将数据库层的压力加到应用层上来,现在大多数客户需求都是低延迟的,尽量提高用户体验,使用物理分页最佳
4、说一下Mybatis的一级缓存和二级缓存?
一级缓存是默认开启的,也叫做本地缓存,它的作用范围是sqlSession对象的创建直至对象调用了close()。在与数据库的同一次会话中,查询到的数据会放到本地缓存中,对于sql完全一样的查询,直接从缓存中拿,无需再访问数据库
二级缓存需手动开启,也称全局缓存,是一个基于namespace级别的缓存,可以使用 标签进行开启,如果未指定readOnly=true,则实体类需要实现序列化接口。只要开启了二级缓存,那么在同一个Mapper下是生效的,无论是否开启了新会话。但是,如果开启了二级缓存,所有的 数据会先放在一级缓存中,只有当会话提交,或者关闭的时候,才会将一级缓存的内容提交到二级缓存中,也类似Java中的L1、L2、L3缓存。
5、mybatis 有哪些执行器(Executor)?
simpleexecutor简单执行器:每次进行数据库操作时,都新建一个statement对象,用完后关闭
reuseexecutor可重用执行器:每次进行数据库操作时,都以当前的sql作为key来查找statement,如果有则取出使用,如果没有则创建,使用完毕后不会关闭,而是放入一个Map集合中,以供下次使用
batchexecutor批处理执行器:会将所有的update语句都添加到批处理中,统一执行。
6、Mybatis有哪些常用标签?
select、update、insert、delete:编写增删查改 sql 语句
resultMap:配置结果集映射
mapper:一个mapper文件需要对应一个mapper标签,用于指定相应的namespace
sql、include:定义并重用 sql 片段,使用 include 进行引用
cache:用于开启二级缓存
if、where、set、choose、when、otherwise、foreach:用于编写动态sql,可以根据不同条件生成不同的sql语句,
association、collection:用于处理复杂映射关系,比如一对多和多对一,一对多需要使用集合collection,多对一需要使用association,注意相应的属性column和property的配置即可,同时也要结合resultMap使用
7、如何配置将mapper映射文件与Spring关联上?
在注入SqlSessionFactory时,配置相应的属性;
如果要绑定 mybatis 核心配置文件,使用 configLocation;如果要绑定 mapper 映射文件,使用 mapperLocations。
例如:
8、ResultType和ResultMap的区别
1.如果只是返回一个值,比如说String或者int,那直接用resultType就行了
2.如果sql查询结果返回的列名和实体类中的字段名一致,可以使用resultType,MyBatis会自动把查询结果赋值给和字段名一致的字段
public class Urder {
private Long id;
private String userName;
private String sex;
}
3.如果不一致,mapper里的sql语句中可以使用别名的方式使其一致。
4.当sql的列名和实体类的列名不一致,这时就可以使用resultMap了
property是实体类的字段名,column是sql查询的列名
对于简单的映射,resultType和resultMap区别不大。但是resultMap功能更强大,可以通过设置typeHander来自定义实现功能