整理-中邮消费金融面经
1.介绍一个实习中项目,有什么收获,主要工作是什么,项目中遇到问题如何解决,如何处理协作问题?
2.问了遇到的最大难题,当前offer情况?
3.java中用了哪些技术?
- 面向对象技术 - java是一门纯面向对象的语言,支持封装、继承和多态等面向对象特性。
- JVM技术 - java代码运行在JVM上,JVM负责内存管理、垃圾回收等,支持跨平台运行。
- 多线程技术 - java提供了线程机制,可以通过继承Thread类或实现Runnable接口来创建线程,还提供了线程同步、线程通信等功能。
- 集合框架 - java提供了丰富的集合类,如List、Set、Map等,大大简化了集合操作。
- 泛型技术 - 泛型提供了编译时的类型安全检测机制,可以在编译时发现问题。
- 反射技术 - 反射机制允许程序在运行时动态获取类的信息,创建对象等。
4.提高反射的性能 setAccessable?
- 使用setAccessible(true)
通过setAccessible方法可以关闭Java语言访问检查,提高反射的效率。这个方法可以提高直接访问私有属性和方法的效率。
- 缓存反射对象
可以缓存反射调用的Method和Field对象,避免重复获取,因为获取反射对象的过程比较消耗性能。
5.静态代理与动态代理的区别?
- 实现时机不同
静态代理在编译时就已经实现了代理类,而动态代理是在运行时动态生成代理类。
- 实现方式不同
静态代理在编译时生成的代理类需要实现与目标对象相同的接口,然后在代理类中进行功能增强。动态代理是利用JDK的Proxy类或第三方库在运行时动态生成目标类的代理对象。
- 灵活性不同
静态代理的代理类只能为一个目标对象服务,如果要为多个目标对象服务需要定义不同的代理类。动态代理可以通过参数不同,为不同的目标对象生成代理实例,灵活性更高。
- 易用性不同
静态代理需要额外定义许多代理类,工作量大,不易管理。动态代理可以直接使用JDK的Proxy类或第三方框架,使用更加方便。
- 接口要求不同
静态代理要求目标对象必须实现接口,否则无法使用接口进行编程。动态代理的目标对象可以是类或者接口。
静态代理
- 定义接口:
java
Copy code
public interface IHello {
void sayHello();
}
2.实现类:
java
Copy code
public class HelloImpl implements IHello {
@Override
public void sayHello() {
System.out.println("Hello World!");
}
}
3.代理类:
java
Copy code
public class HelloProxy implements IHello {
private HelloImpl helloImpl;
public HelloProxy() {
helloImpl = new HelloImpl();
}
@Override
public void sayHello() {
//额外功能
System.out.println("开始代理");
helloImpl.sayHello();
//额外功能
System.out.println("结束代理");
}
}
4.测试:
java
Copy code
public class ProxyTest {
public static void main(String[] args) {
IHello helloProxy = new HelloProxy();
helloProxy.sayHello();
}
}
输出:
开始代理
Hello World!
结束代理
动态代理
- 定义与静态代理相同的接口IHello和实现类HelloImpl
- 代理处理器类:
java
Copy code
public class DynamicProxy implements InvocationHandler {
private Object target;
public DynamicProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开始代理");
Object result = method.invoke(target, args);
System.out.println("结束代理");
return result;
}
}
3.获取代理对象:
java
Copy code
IHello hello = (IHello) Proxy.newProxyInstance(
HelloImpl.class.getClassLoader(),
new Class[]{IHello.class},
new DynamicProxy(new HelloImpl()));
4.测试:
java
Copy code
public class ProxyTest {
public static void main(String[] args) {
IHello hello = getProxy();
hello.sayHello();
}
private static IHello getProxy() {
// 步骤3代码
}
}
输出与静态代理相同。
6.是否会dubbo?
- Dubbo是什么
Dubbo是阿里巴巴开源的一个高性能、轻量级的Java RPC框架。其架构图主要包含:服务提供者、服务消费者、注册中心和监控中心四部分。利用Dubbo可以很方便地实现服务化,以及SOA服务治理架构。
- Dubbo的工作原理
Dubbo的工作原理主要是基于RPC远程调用。服务提供者启动时会将自己提供的服务注册到注册中心,同时开启RPC服务器监听服务请求。服务消费者启动时会向注册中心订阅自己需要的服务,REGISTER中心会返回服务提供者的地址列表。然后服务消费者会基于RPC协议向提供者发送服务调用请求,提供者收到请求后执行服务并返回结果给消费者。
- Dubbo的优点
Dubbo最大的优点是透明化、易用性强。采用全Spring配置方式,可以和Spring程序无缝集成。另外Dubbo实现了软负载均衡及故障容错机制,服务淘汰及自我保护机制,在大并发下保证系统可用性。
- Dubbo的典型应用
Dubbo最典型的应用场景是跨系统的分布式服务调用。如电商系统中订单服务要调用用户服务获取用户信息,调用商品服务获取商品信息。Dubbo可以提供透明的跨系统调用,实现SOA服务治理。
7.排查full gc?
- 观察GC日志,注意full gc的次数、耗时以及再次full gc的间隔时间,如果过于频繁可能是内存溢出导致。
- 使用jstat -gc utilization工具观察老年代占用率,如果接近100%时就会引发full gc。可以适当提高老年代比例避免memory exhaustion。
- 生成heap dump进行脱机分析,查看对象存活数量及大小,找出是否存在存活时间过长的对象引发内存泄漏。
8.提高数据库查询性能?
- 优化查询语句,使用Explain查看执行计划,避免全表扫描,使用索引进行查询。使用合理的条件过滤,避免返回大量无用数据。
- 索引
- redis
9.大学中印象最深的课程?
操作系统
10.最熟悉的算法?
二分查找
11.平时学习技术的途径和方法?
网站、自学
12.对哪种数据结构印象深刻?Java里怎么用的??
HashMap
13.校园实践的收获?遇到过哪些问题?
大一志愿服务
14.密码学:常见的对称加密和非对称加密算法?RSA为什么比DES效率高?
常见的对称加密算法有DES、AES等,特点是加密和解密使用同一密钥。
常见的非对称加密算法有RSA、ECC等,特点是加密和解密使用不同的密钥。
RSA之所以效率高于DES:
RSA可以选择密钥长度,典型取1024或2048位,密钥越大加密强度越高。DES密钥仅56位。
15.为什么想来广州?
16.项目是基于微服务架构,怎么分割不同的架构的?
- 按业务领域来拆分,不同业务领域的服务可以拆分出来,比如用户服务、订单服务、支付服务等。
- 按团队结构来拆分,不同的服务可以由不同的团队来负责。
- 将对外提供的开放API拆分为独立服务。
- 将一些通用能力如日志、配置、监控等拆分出基础服务。
17.spring框架,AOP
- AOP的概念 - 在程序运行期间,动态地将代码切入到方法或者函数的调用点上的这种编程方式,可以不修改源代码实现对程序功能的增强。
- AOP的实现原理 - Spring AOP使用了动态代理,在运行时通过生成代理对象,实现对目标对象方法的拦截从而实现增强功能。
- AOP的重要组件 - aspect、pointcut、advice等,分别用于声明切面、确定joinpoint、执行增强代码。
- AOP的主要作用 - 日志记录、性能监控、安全控制、事务处理等方面对程序进行增强。
- AOP和OOP的区别 - OOP是静态的代码封装和重用,而AOP是动态地通过代理方式实现运行期间的代码增强。
- Spring AOP与 AspectJ AOP的区别 - Spring只支持方法级别的切入,而AspectJ通过修改字节码支持类和方法级别的切入。
- AOP的典型应用 - Spring事务管理就是通过AOP实现的,转译了业务方法的调用过程,减少了重复代码。
- 如何优化AOP的性能 - 采用AspectJ编译时织入提高性能,只为Really需要的Joinpoint生成代理等。
1、定义一个接口及其实现类:
java
Copy code
public interface UserService {
void addUser();
}
public class UserServiceImpl implements UserService {
public void addUser() {
// 方法实现
}
}
2、定义一个切面类:
java
Copy code
@Aspect
public class LoggingAspect {
@Before("execution(* com.example.UserServiceImpl.addUser(..))")
public void logBefore(JoinPoint joinPoint) {
// 前置通知实现
}
@AfterReturning("execution(* com.example.UserServiceImpl.addUser(..))")
public void logAfter(JoinPoint joinPoint) {
// 后置通知实现
}
}
这里通过@Before和@AfterReturning注解定义了前置通知和后置通知。
3、配置Spring AOP扫描该切面类:
java
Copy code
@EnableAspectJAutoProxy
@Configuration
public class AppConfig {
}
4、调用UserService的addUser方法将自动触发前置通知和后置通知的执行。
18.拦截器底层协议是什么?
- 拦截器的实现是基于Java的动态代理机制,Spring AOP与拦截器实现类似。
- Spring MVC中的拦截器通过HandlerInterceptor接口实现请求拦截,底层是基于Servlet过滤器链。
- 拦截器链中的拦截器实例是以单例模式管理的,线程不安全需要注意。
- 拦截器只能拦截Controller请求,对静态资源没有效果。Filter过滤器可以处理更底层的请求信息。
拦截器的根本规范就是JSR-250,这可以看作是它的底层协议。
19.怎么保证单点登录?
单点登录(Single Sign On,SSO)的核心理念是实现一次登录,处处可达。理解SSO的关键是:
- 单一认证系统
这是一个统一的认证系统(可基于服务或OAuth),所有其他应用依赖这个系统进行认证,不再各自实现认证机制。
- 认证信息共享
这个统一认证系统负责对用户进行认证,并提供认证信息(如授权令牌)给其他应用,以实现认证信息的共享。
- 认证信息有效性
认证信息需要在一定时间内保持有效,在有效期内访问其他应用都无需重新认证。
- 应用信任联盟
所有的应用都信任这个统一认证系统,并基于它提供的认证信息认可用户身份。
- 无缝切换
用户可以在一个应用进入另一个应用,没有认证界限,实现了真正的单点体验。
所以SSO的本质是:依赖统一认证,认证信息共享,实现一次登录多处受信,无需重复登录。
使用JWT(JSON Web Token)实现单点登录的流程如下:
- 用户使用用户名密码首次在认证服务器登录
- 认证服务器验证用户信息无误后,生成一个JWT,并将用户信息、权限等数据编码进JWT
- 客户端拿到JWT,保存到本地(比如浏览器localStorage)
- 访问其他需要权限验证的服务器时,客户端带上这个JWT
- 服务器通过校验JWT签名等信息,认证用户身份和权限
- 这样客户端在多个服务器之间就可以通过这个JWT实现统一的认证和鉴权
JWT自包含了用户认证信息,不同服务器可以共享解析,无需每个服务器单独认证,即实现了SSO(Single Sign On)。
JWT也可以设置过期时间,单点登录后一定时间内访问都无需重新登录,提升了用户体验。
当JWT过期时,需要重新获取新的JWT才能继续访问,以保证SSO的安全性。
所以基于JWT的单点登录,主要依赖于JWT作为用户身份令牌在多个系统中共享,省去重复认证的步骤,从而实现单点登录的效果。
20.项目用到了spring boot的什么API?
- 自动配置 - 说明使用了Spring Boot的自动配置功能。
- Starter - 说明使用了哪些Spring Boot Starter模块,如spring-boot-starter-web、spring-boot-starter-jdbc等,快速引入需要的依赖。
21.mybatis 一级缓存二级缓存,#和$的区别?
- 一级缓存是SqlSession级别的缓存,同一个SqlSession查询过的数据会被缓存,多次查询从缓存中直接获取,默认开启。
- 二级缓存是SqlSessionFactory级别,多个SqlSession可以共用二级缓存,需要手动配置开启和清空,效果更好。
- 主要区别是一级缓存仅在一个SqlSession内有效,二级缓存对整个MyBatis系统都有效。
- #表示一个占位符,它可以限制变量的类型。#{name} 会限制name必须为字符串类型。
- 可以接受任何类型的变量。
- 注意{},并且外面要用一个字符串引起来。
- 一般来说为了安全性,尽量使用#参数占位符。
22.有没有在linux部署过项目?
什么情况下打包为war包:
Java Web项目、不包含Tomcat依赖的项目
什么情况下打包为jar包:
SpringBoot项目、SpringCloud项目
打包, 将war包上传到云服务器的webapps目录
使用IDEA打包jar,直接将JAR 放入服务器 使用命令:
java -jar
使用后台运行进程
nohup java -jar
23.怎么想到用redis做限流的?
- 内存存储:Redis是一个内存数据库,它能够快速读取和写入数据,这使得它非常适合用于高速的限流决策。在Redis中执行限流操作比在传统数据库中更快速。
- 过期时间:Redis支持为存储的数据设置过期时间。这意味着你可以为每个令牌或限流规则设置一个超时时间,一旦时间到期,令牌将自动删除,从而不再占用内存。
- 数据结构:Redis提供了多种数据结构,如有序集合(sorted set)和列表,这些数据结构非常适合用于实现不同类型的限流算法,如令牌桶算法或漏桶算法。
24.怎么防sql注入?
PreparedStatement
来执行参数化查询。用户输入通过setString
方法绑定到查询的占位符位置,而不是直接将用户输入嵌入到SQL查询中。
使用ORM框架
25.JWT单点登陆,怎么理解单点?
26.在学校的经历?
27.最近读什么书?
28.了解Linux、Docker吗?
29.平时如何学习新的知识?
30.竞赛获奖?
31.Redis和MySQL数据一致性?
Cache Aside Pattern 是我们平时使用比较多的一个缓存读写模式,比较适合读请求比较多的场景。
写 :
- 先更新 DB
- 然后直接删除 cache 。
读 :
- 从 cache 中读取数据,读取到就直接返回
- cache中读取不到的话,就从 DB 中读取数据返回
- 再把数据放到 cache 中。
32.职业规划?
成为一名软件架构师:
我计划不断深入学习关键技术。密切关注新兴技术趋势,包括人工智能和大数据处理。积累更多的项目经验。提高我的团队协作和领导技能,以便有效地传达架构决策和理念。