目录
一. Spring
1. 简单说一下Spring
2. IOC是怎么实现的 / Spring的Bean是如何加载的 / 生命周期是什么样的?
3. BeanFactory和ApplicationContext有什么区别?
4、ApplicationContext的实现类有哪些?
5. Spring中的单例Bean是线程安全的吗?Spring如何解决线程并发问题?
7. Autowired和Resource有什么区别?RequestMapping有什么作用?
8. SpringAOP了解吗?AOP有哪些实现方式?
9. 过滤器和拦截器有什么区别?
10. Spring是如何解决循环依赖问题的?
12. Spring是怎么扫描注解或者xml文件的?
13. 怎么自定义一个Spring注解?
14. 怎么用AOP实现一个日志拦截或者异常拦截?
15. Spring中的设计模式
二. SpringMVC
1. 描述一下SpringMVC的工作流程
三. Mybatis
1. 为什么要使用Mybatis?
2. Mybatis原理?
3. #{} 和 ${} 有什么区别?
4. Mybatis的映射文件中如何遍历?
5. mapper接口是怎么找到mapper.xml中对应的sql的?
6. Mybatis一级缓存和二级缓存?
7. Mybatis get()和load()的区别?
Spring是一个轻量级java开发框架,简化了java开发。Spring有两大核心,IOC和AOP。
Spring会先扫描xml文件或者注解拿到所有的beanDefination,然后把beanDefination放到map中,然后当调用的getBean方法的时候,先用beanDefination中的bean定义用反射的方式实例化bean,然后再进行属性注入,最后进行初始化(给属性赋值),再把bean放入ConcurrentHashMap中,整个就完成了bean的加载。我们使用的时候,就能直接从容器里获取bean了,所以IOC容器其实可以说是一个map。
BeanFactory和ApplicationContext都可以作为Spring的容器,BeanFactory是最底层的接口,ApplicationContext是BeanFactory的派生。BeanFactory是延迟加载,使用时才会加载,如果Bean的某一个属性没有注入,只有第一次使用时才出抛出异常。ApplicationContext在容器启动时,就会全部加载所有的Bean,虽然有些耗费内存,但是需要使用时无需等待。
不安全,但是大多数Bean都是无状态的,也就是不存储数据,所以某种程度上说不存在线程安全问题。
对于需要存储数据的Bean,我们可以把共享变量设为ThreadLocal变量,那么访问这个变量的每个线程都会有一个变量副本,实际操作的时候,也是使用的本地变量副本,从而规避了线程安全问题。
Autowired是按类型装配,Resource是按名称装配,名称不存在时按类型装配。RequestMapping用来映射URL。
SpringAOP是通过代理模式来实现的。代理模式分为静态代理和动态代理。
Spring动态代理主要有2中实现方式,JDK动态代理和CGLIB动态代理。
构造器注入的循环依赖是没有办法解决的,Spring解决了属性注入方式的循环依赖问题。比如A依赖B,B又依赖A,Spring会先在三级缓存中获取A是否存在,此时A肯定不存在,于是初始化A(因为B是以@Autowired注入的,所以此时并不会出发初始化B),并把A放入三级缓存中,然后进行populateBean(属性注入),此时初始化B,三级缓存中B也不存在,于是初始化B并放入三级缓存,再进行属性注入,此时三级缓存中有A,拿到A进行属性注入。
为什么要有三级缓存?两级不行吗?
Spring 的循环依赖:真的必须非要三级缓存吗?_Java知音_的博客-CSDN博客
- 第一级缓存存的是对外暴露的对象,也就是我们应用需要用到的
- 第二级缓存的作用是为了处理循环依赖的对象创建问题,里面存的是半成品对象或半成品对象的代理对象
- 第三级缓存的作用处理存在 AOP + 循环依赖的对象创建问题,能将代理对象提前创建
根据@ComponentScan配置的扫描路径,扫描这个路径下的注解,比如@Controller@Service@Repository@Component等,然后用反射的方式实例化被注解的类,并放入容器中。
定义注解就用@interface自定义一个注解,上边再加上一些元注解,比如@Target、@Retention、@Documented、@Inherited
元注解:
- @Target表示注解的使用范围,包括类、方法、属性;
- @Retention表示被它注解的注解类注解到别的类上时,可以保留到何时,包括源文件,编译器,运行时;
- @Documented表示生成文档时是否要保留注解信息;
- @Inherited注解表示被@Inherited注解的注解被注解到其他类上时,其子类自动可以拥有该注解。
有两种方式,一种是用切点的方式,一种是注解的方式。
切点的方式就是在@PointCut后边配置类路径,这个类路径下的所有方法都会被增强。
注解的方式就是在@Around@Before这种注解后边配置一个注解,所有被注解的类都会被增强。
方式一:切点方式
用@Aspect注解的类就是一个切面,@Pointcut是一个切点,切点后边配置的是类路径,这个路径中所有方法都会被增强,@Around就是增强,joinPoint可以拿到所有切点中的方法,然后在切点前后做一些操作
方式二:注解的方式
这里表示被@EnableTimerLog注解的所有类都会走到这个@Around注解的增强里,然后就可以在joinPoint.proceed()前后做处理。
Mybatis:轻量级框架,学习成本低,适合需求频繁变动的项目,需求变动只需改sql语句
Hibernate:重量级框架,需要学习HQL,适合需求不怎么变动的项目,需求变动需要改java代码
MyBatis是如何把sql执行结果映射成对象的?
通过
标签,里边映射 属性 和 列名
#{} 和 ${} 都可以传入变量值,如#{userName}。
区别是变量替换后,#{} 会给变量自动加上' '单引号,但${} 不会。因此#{} 可以防止sql注入,${}不行。
#{status}
Mapper.xml文件中的namespace即是mapper接口的类路径,xml中sql语句的id和接口中的方法名一致。
讲解:MyBatis 一级缓存、二级缓存_chy1984的博客-CSDN博客
一级缓存是sqlSession缓存,二级缓存是sqlSessionFactory缓存。
Mybatis的缓存作用是:如果要查询的内容在缓存中存在,则直接从缓存中取,否则查询数据库。
一级缓存默认开启,二级缓存默认关闭,因为缓存时间长,容易出现脏读问题,所以一般不用
##一级缓存的生命周期在sqlSession的生命周期之内,即在mapper方法调用的生命周期之内。
//一个sqlSession,open-> close,方法调用结束时一级缓存会被清空
userMapper.findUserByName();
//一个新的sqlSession
userMapper.findUserByName();
get和load都会先从一级缓存和二级缓存中查找,区别是load是懒加载,需要的时候才去数据库查询。