Spring
- 请说明一下Spring中BeanFactory和ApplicationContext的区别是什么?
BeanFactory:
是Spring核心容器的顶层接口,在构建核心容器的时,创建Bean对象采用的是延迟加载方式,即什么时候需要使用这个Bean对象才创建,适合于多例对象的创建情况;
ApplicationContext:
是BeanFactory的子接口,功能更加的完善,可以使用AOP等功能,创建Bean对象是采用立即加载方式,即一读取完配置文件就实例化Bean对象,适合于单例对象的创建; - 实例化 Bean 的三种方式
- 通过类中的默认无参构造函数创建,如果这个类中没有默认无参构造函数,则Bean对象会创建失败
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"/>
- 使用实例工厂的方法创建 (实例工厂就是一个工厂类,利用其成员方法实例化Bean对象)
首先将工厂交给Spring管理,通过工厂的Bean对象来获取来调用其中的方法;
<bean id="instancFactory" class="com.itheima.factory.InstanceFactory"></bean>
<bean id="accountService"
factory-bean="instancFactory" factory-method="createAccountService"></bean>
- 使用静态工厂中的方法创建(通过一个工厂类中的静态方法实例化Bean对象)
<bean id="accountService"
class="com.itheima.factory.StaticFactory" factory-method="createAccountService"></bean>
- bean对象的作用范围
singleton:
单例
prototype:
多例
request:
web应用的请求范围,每次HTTP请求都会创建一个新的Bean
session:
web应用的会话范围,同一个HttpSession共享同一个Bean,不同的HttpSession使用不同的Bean
global-session:
集群环境的会话范围,同一个全局Session共享一个Bean - 请介绍一下bean的作用范围和生命周期
创建,初始化,服务,销毁
单例对象:
一个应用只会创建一个对象实例,所以作用范围是整个应用,随着容器创建而创建,容器在被使用就会一直存在,容器销毁,则对象也被销毁;
多例对象:
当我们使用的时候Spring会为我们创建对象,只要这个对象在被使用就一直存在,当对象长时间不用,由java垃圾回收器回收; - 请问什么是IoC和DI?并且简要说明一下DI是如何实现的?什么是AOP?
IoC是控制反转,是Spring的核心之一。原来我们要实例化一个对象需要自己new一个对象出来,但是如果这个对象不存在的话编译期就会报错,依赖性很强。现在我们把创建和管理对象的权利交给Spring容器,这样就消减了编译期依赖;
DI是依赖注入,其实就是IoC更详细的描述,就是由容器动态的将某种依赖关系注入到组件中,比如当A类需要用到B类的对象,我们只需要在配置文件中配置B类的的Bean对象,交给Spring容器创建,再由Spring容器将B类的Bean对象注入到A类中;
Spring支持Setter
注入和构造器注入
,静态工厂注入(参考Bean实例化的第三种方式)
,实例工厂注入(参考Bean实例化的第三种方式)
AOP用通俗点例子解释,每天上班正常流程是打卡,上班,打开,下班。现在疫情来了,需要在打卡,上班间增加一个测体温步骤,就可以利用AOP直接就将测体温环节插入,说白了就是很方便的在整个流程中增加步骤。 - 常用注解
使用注解时需要先将bean.xml中的头文件修改并且通过context标签中component-scan属性告诉spring需要扫描的包
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.itheima"></context:component-scan>
</beans>
XML配置的bean对象:
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"
* scope="" init-method="" destroy-method="">
* <property name="" value="" | ref=""></property>
* </bean>
- 创建对象:
相当于<bean>标签
-
component:
作用:将当前类对象放入spring容器中
属性:value 用于指定bean的id。当我们不写时,它的默认值是当前类名,且首字母改小写。
-
Controller:一般用在表现层
-
Service:一般用在业务层
-
Repository:一般用在持久层
-
以上三个注解他们的作用和属性与Component是一模一样。
- 注入数据:
相当于<property>标签
请谈一下autowired 和resource区别是什么?
-
Autowired:
作用:自动按类型注入
若spring容器中有一个bean对象的类型和id值与要注入变量类型和id值相匹配,就可以注入成功;
若spring容器中没有bean对象的类型与要注入变量类型相匹配,则注入失败;
若spring容器中存在多个类型相同(map容器中value相同
)但是id不同的bean对象(map容器中key不同
),则要注入的变量名必须和某个与其类型相同的bean对象id一致,否则注入失败;
在上述第三种情况下, Autowired注解可以和Qualifier注解绑定使用,这样注入的变量名可以和某个与其类型相同的bean对象id可以不一致;
-
Qualifier("baseDao"):
作用:在按照类中注入的基础之上再按照名称注入。它在给类成员注入时不能单独使用。但是在给方法参数注入时可以
属性:value:用于指定注入bean的id。
-
Resource(name="baseDao"):默认按照ByName自动注入
作用:即可以直接按照bean的id注入也可以按照bean的类型注入。它可以独立使用
属性: name:用于指定bean的id。
type:指定bean的类型
注:
以上三个注入都只能注入其他bean类型的数据,而基本类型和String类型使用value注解实现。另外,集合类型的注入只能通过XML来实现。
- 作用范围:
相当于scope属性
作用:用于指定bean的作用范围
属性:value:指定范围的取值。常用取值:singleton prototype - 生命周期:
相当于init-method和destroy-methode属性
PreDestroy
作用:用于指定销毁方法
PostConstruct
作用:用于指定初始化方法
结合day2笔记:
@Configuration
@ComponentScan
@Bean
@PropertySource
@Import
-
Spring整合Junit
why?
Junit并不知道我们使用了spring框架,所以获取容器以及依赖注入等操作需要我们自己完成how?
- 通过将Junit本身集合的Runner函数替换,换成spring提供的Runner函数,这个Runner函数包含了获取容器以及依赖注入等操作。
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith
作用就是可以让我们替换掉它Runner函数
- 告诉Junit是通过纯注解方式还是XML方式配置以及配置类或者配置文件的位置
@ContextConfiguration(locations= {"classpath:bean.xml"})
locations:XML方式
class:纯注解方式
- 你如何理解AOP中的连接点(Joinpoint)、切点(Pointcut)、增强(Advice)、引介(Introduction)、织入(Weaving)、切面(Aspect)这些概念?
Weaving:
比如原来对象没有一些功能,但是通过创建代理对象并且在代理对象中加入了一些增强功能,这就是织入;
Joinpoint:
可以使用通知的地方,其实就是切点,可以在方法的前后或者抛出异常时;
Pointcut:
在所有连接点中你想使用的那几个连接点;
Advice:
你想要在切点加入的功能,比如打印日志啥的
Introduction:
把切面用到目标类中
Aspect:
就是通知加切点,通知说明干什么以及啥时候干,切点说明了在哪里干,组成了切面 - 在 dao 中使用 JdbcTemplate的两种方式
- 直接在类中注入 JdbcTemplate的Bean对象,这种方式既可以使用注解配置也可以使用XML配置,但是每写dao都要重新声明JdbcTemplate,出现两行冗余代码,如下
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate;
}
- 可以通过继承Spring提供的JdbcDaoSupport类来解决冗余代码问题,JdbcDaoSupport类中定义了一个 JdbcTemplate 对象,我们可以直接获取使用,但是要想创建该对象,需要为其提供一个数据源,(1)此数据源直接在XML中注入到dao的Bean对象中,(2)这样在创建dao的Bean对象时就会注入数据源对象,就会触发JdbcDaoSupport类中setDataSource方法,此方法会创建一个JdbcTemplate 的Bean对象并将数据源注入放入容器中,dao中直接获取即可,此方法只能用XML配置
(1)
(2)
- 五种不同的装配方式
Spring包括两种装配手动装配和自动装配:
手动装配:
基于XML装配,构造方法装配,setter方法装配
自动装配:
- no:默认方式不进行自动装配,通过ref属性来装配;
- byName:通过参数名进行装配,注入变量的变量类型和变量名存在和容器中的bean一致,则可成功装配;
- byType:通过参数名进行装,若容器存在唯一与注入变量的类型相同的bean对象,则可以装配成功,若有多个bean对象符合条件则抛出异常;
- constructor:与byType类似,要提供构造器参数,否则抛出异常;
- autodetect:首先尝试使用constructor来自动装配,无法成功转用byType;
- Spring处理异常的方式
- 实现HandlerExceptionResolver接口,在配置文件中配置异常处理器的bean对象
- @ControllerAdvice+@ExceptionHandler
- Spring声明式事务实现原理
基于AOP,使用事务拦截器来驱动事务完成 - 事务传播特性?
REQUIRED:
如果当前没 有事务,就 新建一个 事务,如 果已经存在 一个事务 中,加入 到这个事务 中。一般 的选 择(默认值)
SUPPORTS:
支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)
MANDATORY:
使用当前的事务,如果当前没有事务,就抛出异常
REQUERS_NEW:
新建事务,如果当前在事务中,把当前事务挂起。
NOT_SUPPORTED:
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
NEVER:
以非事务方式运行,如果当前存在事务,抛出异常
NESTED:
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行 REQUIRED 类似的操作 - 事务注解在接口和类上区别?
- @Transactional注解在接口上时,必须使用基于接口的代理才行,即JDK动态代理。 JDK动态代理只能为接口创建动态代理实例,而不能对类创建动态代理。需要获得被目标类的接口信息(应用Java的反射技术),生成一个实现了代理接口的动态代理类(字节码),再通过反射机制获得动态代理类的构造函数,利用构造函数生成动态代理类的实例对象,在调用具体方法前调用invokeHandler方法来处理
- @Transactional注解在类上时,使用基于类的代理,即CGLIB。CGLib动态代理是代理类去继承目标类,然后重写其中目标类的方法啊,这样也可以保证代理类拥有目标类的同名方法;
- 如何配置回滚异常?
- 使用@Transactional注解的rollbackFor/rollbackForClassName属性,可以精确配置导致回滚的异常类型;
- noRollbackFor/noRollbackForClassName属性,可以配置不导致回滚的异常类型;
- Spring事务三要素
-
数据源:表示具体的事务性资源,是事务的真正处理者,如MySQL等。
-
事务管理器:像一个大管家,从整体上管理事务的处理过程,如打开、提交、回滚等。
-
事务应用和属性配置:像一个标识符,表明哪些方法要参与事务,如何参与事务,以及一些相关属性如隔离级别、超时时间等。
- Spring怎么实现控制事务?
- 编程式事务控制
使用TransactionTemplate通过编写代码的方式实现事务的控制,需要在业务逻辑代码中加入事务管理的代码; - 声明式事务控制:基于AOP实现
基于XML声明式事务控制:
数据源,事务管理器,事务增强,配置切点、事务通知
基于@Transactional声明式事务控制:
- Spring怎么操作数据库的?
使用JdbcTemplate操作 - 五种通知类型:
before
after-returning
after-throwing
after
around
SpringMVC
- 三层架构
- MVC模型:
- Model: javabean
- View: jsp或者html
- Controller: servlet
- 什么是SpringMVC?优点是啥?
- Spring MVC的工作原理是怎样的?
- 首先客户端所有的请求都交给前端控制器DispatcherServlet来处理,调用系统的其他组件去处理;
- 前端控制器会调用处理器映射器HandlerMapping根据请求方式找到相应的Handler;
- 调用处理器适配器HandlerAdapter根据不同Handler规则执行不同Handler,返回ModelAndView对象给前端控制器
- 前端控制器调用视图解析器对ModelAndView对象进行解析,返回view对象;
- 前端控制器对view对象进行渲染(即将模型数据填充至视图中),返回给浏览器
Mybatis
- 涉及哪些设计模式
- 构造者模式:封装了创建对象的细节,直接调用方法创建对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory =sqlSessionFactoryBuilder.build(in);
- 工厂模式:通过反射创建连接对象,降低了类之间的耦合
SqlSession session = factory.openSession();
- 代理模式:创建Dao接口实现类使用了代理模式,不修改源码的基础上对原有方法增强
UserDao userDao = session.getMapper(UserDao.class);
- Mybatis中#{}和${}的区别?
- 使用${}时,不会预编译sql语句,直接将传入的参数拼接到sql语句中进行编译执行,容易产生sql注入现象;
- 使用#{}时,会首先进行sql语句的预编译,参数位置用占位符?,传入参数时不会进行sql语句的拼接,就不会产生sql注入现象
- 拦截器和过滤器区别?
过滤器属于Servlet规范,会对所有请求进行拦截;
拦截器属于Spring框架,只有在是有Spring框架的时候才能使用,所有对Controller方法的请求会被拦截,有:
preHandle:
Controller方法执行前执行;
postHandle:
Controller方法执行后执行;
afterCompletion:
所有响应完成后执行; - link
- 一级缓存,二级缓存
什么是缓存:存在于内存中的临时数据
为什么使用缓存:减少与数据库的交互次数,提高执行效率
什么样的数据适合缓存:
- 经常查询不需要修改的数据
- 数据的正确与否对结果影响不大的数据
一级缓存:SqlSession对象的缓存,默认开启。当我们查询之后,SqlSession对象会提供一块内存区域,当我们再次查询相同的数据时,mybatis会先去SqlSession对象中查询是否有,有的话直接使用,当SqlSession对象消失,则mybatis的一级缓存也就消失,另外当调用SqlSession对象的增删改等方法会自动清空一级缓存;
二级缓存:SqlSessionFactory对象的缓存,默认关闭。由同一个SqlSessionFactory对象生产的SqlSession对象共享其缓存。开启二级缓存首先在xml配置文件设置开启,然后在映射文件中开启支持二级缓存,最后在select标签中设置开启支持二级缓存