核心框架源码常见问题(上)

发布时间:2026/5/19 21:34:18

核心框架源码常见问题(上) 1、MyBatis中#与$的区别常识这个问题就是常识性问题会应该的。 不会回家。#预编译处理PreparedStatement#是基于占位符的方式将参数注入到SQL语句的指定位置。完成预编译的效果传入的参数不会被解析为关键字就是一个字符串可以预防SQL。$字符串的拼接Statement$就是字符串的拼接他不会做预编译So$$传参时无法预防SQL注入的问题。在一些特殊的情况下需要传入一些表名字段之类的内容这些就不能去做预编译的处理所以在传入字段表名之类的内容时一定要用$传参。select xxx from ${table} order by ${column}2、MyBatis中的一级缓存和二级缓存的区别区别蛮多的最好还是从源码的维度去和面试官沟通。1、本质的实现流程区别首先一级缓存是基于BaseExecutor去查询一个PerpetualCache中的HashMap得到的缓存结果。二级缓存是基于CachingExecutor去查询一个PerpetualCache中的HashMap得到的缓存结果。Ps虽然都是PerpetualCache但是不是一个对象2、查询Cache的区别一级缓存他只去查询PerpetualCache不涉及其他的Cache实例。二级缓存他会经历很多个Cache最后才会到PerpetualCache中查询数据。SynchronizedCache加锁确保线程安全SerializedCache对数据做序列化和反序列化的操作LoggingCache记录缓存命中率的日志。LruCache基于Lru删除最近最少使用的缓存对象Lru策略就是基于LinkedHashMap实现的最大长度默认为1024。…………3、作用域一级缓存的作用域是SqlSession级别。 线程二级缓存的作用域是SqlSessionFactory级别。 全局4、优先级别MyBatis中二级缓存的优先级高于一级缓存因为一级缓存的作用域原因他的缓存命中率约等于0因为咱们很少在一次事务中多次查询同一个数据所以二级缓存毕竟是全局共享所以使用他的缓存命中率更高不如直接查询二级缓存5、默认开关一级默认开启二级默认关闭需要在配置文件手动开启3、MyBatis中的ExecutorExecutor就是咱们在使用MyBatis和数据库交互时底层就是在Executor的位置去搞Statement之类的内容。可以直接找到Executor的接口查看他对应的实现类除了ClosedExecutor不需要关注之外其他的5个咱们需要了解。BaseExecutor基本的执行器除了CachingExecutor之外都是继承BaseExecutor实现的。CachingExecutor他就是二级缓存的执行器。SimpleExecutor一般默认使用的就是SimpleExecutor每次执行SQL语句都会创建一个Statement对象去和数据库完成交互。ReuseExecutor可复用的执行器复用的是Statement对象他会根据SQL语句来决定是否复用一些Statement他是将SQL作为KeyStatement作为Value扔到了一个HashMap里。BatchExecutor批处理执行器针对写操作但是不是你想的那种批处理他是将每次要执行的SQL语句扔到一个集合里等你commit之后再一个一个扔给数据库执行。选择Executor默认是在MyBatis的核心配置文件中修改settings指定defaultExecutorType。4、谈谈你对IOC的理解常识性解耦IOC就是帮你创建对象同时将对象地址扔到引用里。某个通过IOC各个模块之间的对象耦合性变的更低。比如远古时期一个Service层如果依赖DAO那会直接new一个DaoImpl的实例。使用了IOC之后基于接口的引用利用IOC将依赖通过Spring容器注入进来就可以扔Service和DAO之间的耦合更低。比如现在有一个CacheService可能之前使用的是MemCacheServiceImpl的实例利用Spring直接基于CacheService接口注入进去。如果后期要换成RedisSerivceImpl所有引用CacheService实例的对象不需要做任何变化。底层相关前面聊清楚自己的想法后可以再点一嘴Spring是怎么实现IOC的他的本质就是在程序启动时先加载xml以及注解的相关内容获取bean的一些元数据将这些元数据封装为BeanDefinition的实例扔到一个集合中当要创建bean时获取到每一个BeanDefinition基于反射的形式将对象构建出来并且扔到一级缓存中哪里需要注入就从一级缓存中拿5、Spring创建Bean的过程Bean的生命周期、Spring的拓展接口说白了就是Spring在构建好一个bean之后会再次执行一些拓展的接口方法都有哪些~当对象实例化完毕也初始化ok之后会按照这个流程走执行各种Aware接口。ApplicationContextAware也可以点一嘴实际的应用SpringUtil工具类BeanPostProcessor的Before方法。InitializingBean的afterPropertiesSet方法。init-method方法BeanPostProcessor的After方法。正常使用~~~DisposableBean的destory方法destory-method方法系统玩看这个课程https://www.mashibing.com/course/27326、聊聊AOP首先如果你的项目中涉及到了AOP的操作无论是你们自己封装的还是框架里面设计的都可以点一嘴你们项目中的应用。如果你的项目里没涉及或者你不了解那你也要说一些会用到AOP的场景比如认证的框架ShiroSpringSecurity在授权注解校验里都是基于AOP做的声明式事务底层也是AOP再比如记录一些日志啥的在不改变源代码要动态注入功能的点多说一说…………聊完这个理解和一些应用之后就是聊底层了底层也可以从两个维度来聊AOP底层实现AOP底层是基于动态代理实现的他有两种实现的方案jdk动态代理基于接口interface去构建代理对象。cglib动态代理基于继承extends去构建代理对象。如果被问到了那个代理效率好你要提一嘴虽然cglib底层是基于字节码增强实现的但是他俩效率其实大差不差。如果一个类没有实现接口并且被final修饰那这个类的对象就没法被代理。Spring创建代理对象的时机代理对象的创建是基于BeanPostProcessor的after后置处理创建的。从源码的纬度搂一眼。1、查看到BeanPostProcessor的实现类AspectJAwareAdvisorAutoProxyCreator代理对象创建的过程就是基于他完成的。 2、查看他的postProcessAfterInitialization方法在里面有创建的逻辑。 3、可以进入到wrapIfNecessary方法中的实现 4、再次看到一个核心方法核心方法叫createProxy明显就是创建代理对象。 5、在进去可以看到proxyFactory.getProxy方法必然是通过这个创建的代理对象 6、最后可以看到return createAopProxy().getProxy(classLoader);方法getProxy的实现方式就有前面说的两种方案一种JDK一种Cglib7、AOP的名词常识代理的最终目的是为了给某一个方法织入一些功能。比如方法执行之前干点啥方法执行之后干点啥方法出现异常干点啥。连接点可以被织入功能的方法就叫连接点。切入点真正要被织入功能的方法就叫切入点。切入点可以基于切入点表达式来指定增强要被注入的功能就要增强。织入将增强扔到切入点里的动作就是织入。 不用聊~~切面将增强织入到切入点的过程就是切面。8、Spring涉及到了哪些设计模式。Spring涉及到的设计模式太多了能说几个是几个但是一定要点到具体是哪里涉及到了。单例Spring默认维护的bean都是单例的工厂Spring内部提供了各种工厂顶级接口是BeanFactory代理AOP底层就是基于代理实现的原型Spring可以将bean的scope属性设置为prototype装饰者Spring在构建bean之后会将器包装为BeanWrapper构建者在构建BeanDefinition的时候属性贼多内部提供了BeanDefinitionBuilder责任链Interceptor拦截器多个拦截器就具备责任链的效果。模板RedisTemplateRabbitTemplate…………各种模板~策略ClassPathXMLApplicationContext以及对应的FileSystemXmlApplicationContext观察者各种Listener各种Event事件~~委托…………………………等等

相关新闻