Java 开发工程师 面试题(一)

1. 注解@Transactional事务的实现


在这里插入图片描述
就是通过反射 + 动态代理实现!

2. Spring事务的 4个隔离级别 + 7个传播行为


在这里插入图片描述
记住它们会出现什么情况(脏读,虚读,不可重复读)。

在这里插入图片描述
大多数使用required,记住required的理念。

3. IOC的三种注入方式


最常用的set注入。

构造器注入。

命名空间p或者c注入。

见:https://blog.csdn.net/IT_Holmes/article/details/121818148

4. aop的5个通知类型


aop配置文件的两种形式:

<?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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       ">

	<bean id="serviceTest" class="com.itholmes.service.UserserviceImpl"></bean>
	
	<bean id="abc" class="com.itholmes.abc"></bean>
	
	<aop:config>
		<aop:aspect ref="abc">
			<aop:pointcut id="aa" expression="execution(* com.itholmes.service.*.*(..))"/>
			<!--下面的method就是上面ref引用类的方法名。-->
			<aop:after method="after" pointcut-ref="aa"/>
			<aop:before method="before" pointcut-ref="aa"/>
			<aop:after-throwing method="afterThrowing"  pointcut-ref="aa" throwing="e"/> <!--throwing 表示异常处理的方法的参数名 (可以不再异常通知中声明异常对象)-->
			<aop:after-returning method="afterReturning" pointcut-ref="aa"/>
			<aop:around method="around" pointcut-ref="aa"/>
		</aop:aspect>
	</aop:config>
	
	
</beans>

aop注解形式:
在这里插入图片描述

package com.itholmes.config;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AdviceTest {
    
    

    @Pointcut("execution(* com.itholmes.service.*.*(..))")
    //这里的test()方法必须有,就像是一个名字一样的标识。
    public void pointcut(){
    
    

    }

    @Before("pointcut()")
    public void doBefore(JoinPoint joinPoint){
    
    
        System.out.println(joinPoint.getSignature().getName() + "前置通知---");
    }

    //2. 正常返回
    @AfterReturning("pointcut()")
    public void doAfterSuccess(JoinPoint joinPoint){
    
    
        System.out.println(joinPoint.getSignature().getName() + "正常返回通知---");
    }

    //3. 异常返回(与正常返回是互斥关系)
    @AfterThrowing("pointcut()")
    public void doAfterError(JoinPoint joinPoint){
    
    
        System.out.println(joinPoint.getSignature().getName() + "异常通知---");
    }

    //4. 环绕
    @Around(value = "pointcut()", argNames = "pjp")
    public Object doAround(ProceedingJoinPoint pjp) {
    
    
        Object[] args = pjp.getArgs();
        Object result;
        try {
    
    
            // Before
            System.out.println(pjp.getSignature().getName() + "环绕前置通知---");
            result = pjp.proceed(args);
            // AfterReturning
            System.out.println(pjp.getSignature().getName() + "环绕返回通知---");
        }catch (Throwable e){
    
    
            // AfterThrowing
            // System.out.println(pjp.getSignature().getName() + "环绕异常通知---");
            throw new RuntimeException(e);
        }finally {
    
    
            // After
            //  System.out.println(pjp.getSignature().getName() + "环绕最终通知---");
        }
        return result;
    }

    //5. 后置通知(最终通知)
    @After("pointcut()")
    public void doAfter(JoinPoint joinPoint){
    
    
        System.out.println(joinPoint.getSignature().getName() + "后置,也就是最终通知---");
    }


}

不要忘记添加配置文件信息:

<bean id="annotationPointCut" class="com.itholmes.config.AdviceTest"></bean>
<aop:aspectj-autoproxy proxy-target-class="false"/>

明白正常返回 和 异常返回是互斥的。

后置(最终)通知,不管 有没有异常都会执行。

5. 分布式锁的作用


分布式锁:https://www.modb.pro/db/246339

分布式锁:https://blog.csdn.net/zhaisharap/article/details/122471322

多个用户操作同一个数据的时候,例如:快递员取货,多个快递员,去取都一件货物,这个时候就需要分布式锁解决。因为分布式它们不在一个系统中,因此就可以通过redis,zookeeper等完成分布式锁的效果。

6. 浏览器发起一个请求的过程


  1. 浏览器发送http协议请求。
  2. 先根据URL域名,去本地hosts文件查找是否有映射IP,没有就去dns域名解析,得到ip地址。
  3. 之后,客户端根据解析的IP地址,会进行tcp三次握手与服务器建立连接。
  4. 建立连接后,就开始向服务器发送请求。
  5. 服务器响应给浏览器。
  6. 最后,tcp的四次挥手断开连接。
    在这里插入图片描述

7. http协议


http协议是无状态的,就是对于事务处理没有记忆能力。就是向服务器发起两次请求,服务器就不知道这两次http请求都来自同一个浏览器发出的。

cookie就是来解决http无状态的问题。


长连接,短连接,无连接:

无连接:限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。

短连接:短连接是指一次请求和响应后,连接一会就关闭,这种方式可以节省资源。

长连接:从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加入这行代码:

Connection:keep-alive

HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。


常见的几个请求头:

  • Referer : 是 HTTP 请求header 的一部分,当浏览器(或者模拟浏览器行为)向web 服务器发送请求的时候,头信息里有包含 Referer 。比如我在www.google.com 里有一个www.baidu.com 链接,那么点击这个www.baidu.com ,它的header 信息里就有:
 Referer=http://www.google.com
  • content-type :请求参数类型。
  • content-length : 请求参数的长度。
  • user-agent : 记录一些本地信息,提供你所使用的浏览器类型及版本.操作系统及版本.浏览器内核.等信息的标识.。
  • host : 域名地址 (或者IP + 端口号)

8. 有状态bean 和 无状态bean


bean5种作用域:分别是:singleton、prototype、request、session、gloabal session

有状态会话bean :每个用户有自己特有的一个实例,在用户的生存期内,bean保持了用户的信息,即“有状态”;

一旦用户灭亡(调用结束或实例结束),bean的生命期也告结束。即每个用户最初都会得到一个初始的bean。

无状态会话bean :bean一旦实例化就被加进会话池中,各个用户都可以共用。即使用户已经消亡,bean 的生命期也不一定结束,它可能依然存在于会话池中,供其他用户调用。

由于没有特定的用户,那么也就不能保持某一用户的状态,所以叫无状态bean。
但无状态会话bean 并非没有状态,如果它有自己的属性(变量),那么这些变量就会受到所有调用它的用户的影响,这是在实际应用中必须注意的。

每次通过Spring容器获取prototype定义的bean时,容器都将创建一个新的Bean实例,每个Bean实例都有自己的属性和状态,而singleton全局只有一个对象。

根据经验,对有状态的bean使用prototype作用域,而对无状态的bean使用singleton作用域。

9. options请求(跨域预检)


HTTP 的 OPTIONS 方法 用于获取目的资源所支持的通信选项。客户端可以对特定的 URL 使用 OPTIONS 方法,也可以对整站(通过将 URL 设置为"*")使用该方法。(简而言之,就是可以用 options 请求去嗅探某个请求在对应的服务器中都支持哪种请求方法)。

这是因为在跨域的情况下,在浏览器发起"复杂请求"时主动发起的。跨域共享标准规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。

10. http的9种 常见的请求方式

HTTP1.0定义了三种请求方法:GET、POST、HEAD

HTTP1.1定义了六种请求方法:PUT、DELETE、PATCH、OPTIONS、CONNECT、TRACE

  1. get    请求指定页面的信息,并返回实体主体(幂等)
  2. post    向指定资源提交数据进行处理请求,数据存在请求体(非幂等)
  3. head   类似get,但不返回具体内容,用于获取报头(幂等)
  4. put    完整替换更新指定资源数据,没有就新增(幂等)
  5. delete   删除指定资源的数据(幂等)
  6. patch   部分更新指定资源的数据(非幂等)
  7. options  允许客户端查看服务器的支持的http请求方法
  8. connect  预留给能将连接改为管道的代理服务器
  9. trace   追踪服务器收到的请求,用于测试或诊断

11. 如何证明当前对象是单例的


打印一下this,判断一些地址是否相同。

12. 多线程下,如何解决成员变量


举个例子:我像设计一个小功能,知道当前接口已经被访问了多少次了,在controller层设计一个成员变量,通过这个成员变量达到一个计数效果。

对于多线程,上面的代码逻辑肯定会出现问题,如何解决?

  • 加同步锁synchronized,但是效率低。
  • AtomicInteger ageAtic = new AtomicInteger(0); 调用getAndIncrement方法或者decrementAndGet。 本质上atomicInteger使用的乐观锁来实现的。
AtomicInteger integer = new AtomicInteger(0);
int i = integer.getAndIncrement(); // +1 操作
int i1 = integer.decrementAndGet(); // -1 操作

在这里插入图片描述

  • 对于不是计数的同样可以使用乐观锁来解决这类问题。

乐观锁:数据库里面有一个字段version,开始业务执行前先查询version,业务执行后根据version来进行update操作(乐观锁:sql语句层次version + 1 where version = #{version}。)

sql语句的修改丢失,也可以用悲观锁(select … for update)处理。


对于这种业务有增有减,就容易产生ABA问题。ABA问题:由A变成B,再由B编程了A。这种ABA问题。

13. transient 关键字作用


transient关键字标记的成员变量不参与序列化过程,transient关键字只能修饰变量,而不能修饰方法和类。
在这里插入图片描述

14. servlet的 / 和 /* 的区别


见:https://www.jb51.net/article/216853.htm

15. 代码里面的 / 一般指的那些地方


代码里面 / 都是指的如下地方:
在这里插入图片描述

将页面放到web-inf下面,就可以通过走servlet来安全访问。

16. jsp九大内置对象


在这里插入图片描述

17. SpringMVC容器和Spring容器


springmvc容器 与 spring容器是子父容器。 开始先扫描springmvc容器,因此一般springmvc.xml文件里面,最好不要扫描service的路径。

当然,Spring.xml文件就要扫描service层下的实现类,进而放到spring容器里面,是为了配置mybatis的增强事务。

上面不是绝对,如果把事务整合什么的也都放到springmvc,也是可以行得通的。

18. Spring拦截器 + 统一异常处理


见:https://blog.csdn.net/IT_Holmes/article/details/123089091?spm=1001.2014.3001.5502

19. 单例设计模式的 懒汉式 和 饿汉式


单例模式:

  • 构造方法私有,属性私有。
  • 写一个专门获取当前对象的方法,无论获取多少次始终都是一个对象。
package com.itholmes.config;

public class Singleton {
    
    

    private static Singleton singleton = new Singleton();

    private Singleton(){
    
    
    }

    //饿汉式
    public static Singleton getSingleton(){
    
    
        return singleton;
    }

}

package com.itholmes.config;

public class Singleton {
    
    

    private static Singleton singleton = null;

    private Singleton(){
    
    
    }

    //懒汉式
    public static Singleton getSingleton(){
    
    
        if (singleton == null){
    
    
            singleton = new Singleton();
        }
        return singleton;
    }

}

20. 工厂模式


见:https://www.runoob.com/design-pattern/factory-pattern.html

21. Java的 assert 断言


1、assert condition;
这里condition是一个必须为真(true)的表达式。如果表达式的结果为true,那么断言为真,并且无任何行动
如果表达式为false,则断言失败,则会抛出一个AssertionError对象。这个AssertionError继承于Error对象,
而Error继承于Throwable,Error是和Exception并列的一个错误对象,通常用于表达系统级运行错误。

2、asser condition:expr;
这里condition是和上面一样的,这个冒号后跟的是一个表达式,通常用于断言失败后的提示信息,说白了,它是一个传到AssertionError构造函数的值,如果断言失败,该值被转化为它对应的字符串,并显示出来。

public class Test {
    
    
    public static void main(String[] args) {
    
    
        System.out.println("start");
        assert true;
        System.out.println("go on");
        assert false:"stop";
        System.out.println("end");
    }
}

需要观察断言的运行情况,就需要打开系统类的assertion功能 ,我们可使用-esa参数打开,使用 -dsa参数关闭。 -esa和-dsa的全名为-enablesystemassertions和 -disenablesystemassertions,全名和缩写名有同样的功能。
在这里插入图片描述

22. Spring的Assert断言工具类


Spring的Assert断言工具类,通常用于数据合法性检查。位于 org.springframework.util.Assert包下,使用Assert可以使复杂的判断变得更加简单。

在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/IT_Holmes/article/details/125613082