面试题目补充

1.Spring 的 AOP 关于拦截 private 方法一些问题

用 java 反射机制可以获取 private 修饰的方法,进行拦截。注意,私有构造函数需要设置使用权限conInt.setAccessible(true);否则报错


2.项目中数据字典怎么做的缓存,如何做的通信,有没有用什么模块。


3. spring 事务传播行为的配置方法:

(1)spring 对事务传播行为和隔离级别的二次封装。因为不同项目可能在一个 mysql 的不同数据库上,所以可以在项目中配置数据库的传播行为和隔离级别

<property name="transactionAttributes"> 
<props> 
<prop key="save*">PROPAGATION_REQUIRED</prop> 
<prop key="update*">PROPAGATION_REQUIRED</prop> 
<prop key="delete*">PROPAGATION_REQUIRED</prop> 
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop> 
<prop key="find*">PROPAGATION_REQUIRED,ISOLATION_READ_UNCOMMITTED</prop>
</props>

(2)另一种方式:

事务的传播性:@Transactional (propagation=Propagation.REQUIRED)

事务的隔离级别:@Transactional (isolation = Isolation.READ_UNCOMMITTED)

(3)spring+mybatis 事务配置

        <!-- 定义事务管理器 -->
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>
	<!--使用注释事务 -->
	<tx:annotation-driven  transaction-manager="transactionManager" />

4.slf4j 的原理,和 log4j 的对比

SLF4J 不同于其他日志类库,与其它有很大的不同。SLF4J (Simple logging Facade for Java) 不是一个真正的日志实现,而是一个抽象层( abstraction layer),它允许你在后台使用任意一个日志类库。

如果一个项目已经使用了 log4j,而你加载了一个类库,比方说 Apache Active MQ—— 它依赖于于另外一个日志类库 logback,那么你就需要把它也加载进去。但如果 Apache Active MQ 使用了 SLF4J,你可以继续使用你的日志类库而加载和维护一个新的日志框架。

总的来说,SLF4J 使你的代码独立于任意一个特定的日志 API,这是一个对于开发 API 的开发者很好的思想。虽然抽象日志类库的思想已经不是新鲜的事物而且 Apache commons logging 也已经在使用这种思想了,但现在 SLF4J 正迅速成为 Java 世界的日志标准。

  • 在你的开源或内部类库中使用 SLF4J 会使得它独立于任何一个特定的日志实现,这意味着不需要管理多个日志配置或者多个日志类库。

  • SLF4J 提供了基于占位符的日志方法,不需要检查 isDebugEnabled (), isInfoEnabled () 等等,提高了代码可读性。

  • 通过使用 SLF4J 的日志方法,你可以延迟构建日志信息(Srting)的开销,直到你真正需要,这对于内存和 CPU 都是高效的。


5.CMS产生的浮动垃圾

初始标记:标记 GC Roots 能直接到的对象。速度很快但是仍存在 Stop The World 问题。
并发标记:进行 GC Roots Tracing 的过程,找出存活对象且用户线程可并发执行。
重新标记:为了修正并发标记期间因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录。仍然存在 Stop The World 问题。
并发清除:对标记的对象进行清除回收。

重新标记(Remark) 的作用在于:
之前在并发标记时,因为是 GC 和用户程序是并发执行的,可能导致一部分已经标记为 从 GC Roots 不可达 的对象,因为用户程序的(并发)运行,又可达 了,Remark 的作用就是将这部分对象又标记为 可达对象。

至于 “浮动垃圾”,因为 CMS 在 并发标记 时是并发的,GC 线程和用户线程并发执行,这个过程当然可能会因为线程的交替执行而导致新产生的垃圾(即浮动垃圾)没有被标记到;而 重新标记 的作用只是修改之前 并发标记 所获得的不可达对象,所以是没有办法处理 “浮动垃圾” 的。


6.tomcat的非双亲委派加载

在这里插入图片描述

双亲委派模型要求除了顶层的启动类加载器之外,其余的类加载器都应当由自己的父类加载器加载。

【违背双亲委派】: tomcat 为了实现隔离性,没有遵守这个约定,每个 webappClassLoader 加载自己的目录下的 class 文件,不会传递给父类加载器。例如:如果 tomcat 的 Common ClassLoader 想加载 WebApp ClassLoader 中的类,该怎么办?我们可以使用线程上下文类加载器实现,使用线程上下文加载器,可以让父类加载器请求子类加载器去完成类加载的动作。

tomcat 为了实现隔离性和热替换,没有使用默认的类加载器,而是自己实现了类加载器: 一个 web 容器可能要部署两个或者多个应用程序,不同的应用程序,可能会依赖同一个第三方类库的不同版本,因此要保证每一个应用程序的类库都是独立、相互隔离的。

【违背双亲委派三个方面】:(1)向前兼容;(2)加载 SPI 接口实现类;(3)热部署

【Tomcat 类加载过程】:

tomcat 的类加载机制是违反了双亲委托原则的,对于一些未加载的非基础类 (Object,String 等),各个 web 应用自己的类加载器 (WebAppClassLoader) 会优先加载,加载不到时再交给 commonClassLoader 走双亲委托。具体的加载逻辑位于 WebAppClassLoaderBase.loadClass() 方法中,这里以文字描述加载一个类过程:

先在本地缓存中查找是否已经加载过该类 (对于一些已经加载了的类,会被缓存在 resourceEntries 这个数据结构中),如果已经加载即返回,否则 继续下一步。
让系统类加载器 (AppClassLoader) 尝试加载该类,主要是为了防止一些基础类会被 web 中的类覆盖,如果加载到即返回,返回继续。
前两步均没加载到目标类,那么 web 应用的类加载器将自行加载,如果加载到则返回,否则继续下一步。
最后还是加载不到的话,则委托父类加载器 (Common ClassLoader) 去加载。


7.线程上下文类加载器

Java 提供了很多服务提供者接口(Service Provider Interface,SPI),允许第三方为这些接口提供实现。常见的 SPI 有 JDBC、JCE、JNDI、JAXP 和 JBI 等。而问题在于,SPI 的接口是 Java 核心库的一部分,是由引导类加载器来加载的;SPI 实现的 Java 类一般是由系统类加载器来加载的。引导类加载器是无法找到 SPI 的实现类的,因为它只加载 Java 的核心库。它也不能代理给系统类加载器,因为它是系统类加载器的祖先类加载器。也就是说,类加载器的代理模式无法解决这个问题。

线程上下文类加载器正好解决了这个问题。如果不做任何的设置,Java 应用的线程的上下文类加载器默认就是系统上下文类加载器。在 SPI 接口的代码中使用线程上下文类加载器,就可以成功的加载到 SPI 实现的类。线程上下文类加载器在很多 SPI 的实现中都会用到。

使用线程上下文类加载器,可以在执行线程中抛弃双亲委派加载链模式,使用线程上下文里的类加载器加载类。典型的例子有:通过线程上下文来加载第三方库 jndi 实现,而不依赖于双亲委派。大部分 java application 服务器 (jboss, tomcat…) 也是采用 contextClassLoader 来处理 web 服务。还有一些采用 hot swap 特性的框架,也使用了线程上下文类加载器,比如 seasar (full stack framework in japenese)。线程上下文从根本解决了一般应用不能违背双亲委派模式的问题。


8.数据库的MVVC是什么?

MVCC 的全称是 “多版本并发控制”。这项技术使得 InnoDB 的事务隔离级别下执行一致性读操作有了保证,换言之,就是为了查询一些正在被另一个事务更新的行,并且可以看到它们被更新之前的值。这是一个可以用来增强并发性的强大的技术,因为这样的一来的话查询就不用等待另一个事务释放锁。MVVC依靠的是数据库的回滚日志。

mysql 的 innodb 采用的是行锁,而且采用了多版本并发控制来提高读操作的性能。MVVC其实就是在每一行记录的后面增加两个隐藏列,记录创建版本号和删除版本号,而每一个事务在启动的时候,都有一个唯一的递增的版本号。 在 InnoDB 中,给每行增加两个隐藏字段来实现 MVCC,两个列都用来存储事务的版本号,每开启一个新事务,事务的版本号就会递增。

读取创建版本小于或等于当前事务版本号,并且删除版本为空或大于当前事务版本号的记录。这样可以保证在读取之前记录是存在的。

一致性非锁定读

consistent read (一致性读),InnoDB 用多版本来提供查询数据库在某个时间点的快照。如果隔离级别是 REPEATABLE READ,那么在同一个事务中的所有一致性读都读的是事务中第一个这样的读读到的快照;如果是 READ COMMITTED,那么一个事务中的每一个一致性读都会读到它自己刷新的快照版本。Consistent read(一致性读)是 READ COMMITTED 和 REPEATABLE READ 隔离级别下普通 SELECT 语句默认的模式。一致性读不会给它所访问的表加任何形式的锁,因此其它事务可以同时并发的修改它们。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章