华为外包
无笔试,两场,共6轮面试。
基础问题,基本和之前一致,在复试会问一些“应用题”,考察思维。我觉得自己答得都不是很好,但最后都过了,也许是归结为前一场面试下来后有总结。
- 数据库:B+ 索引、SQL 优化思路、是否有优化经验。
- 容器:一般都会问 HashMap
- Spring:谈 Spring 有什么用途,谈对 Spring 的理解、解决什么问题。
- Spring MVC:谈原理或者执行过程,谈对 Spring MVC 的理解、解决什么问题。
- 并发:线程实现的方法、线程池、是否在项目中使用过。
- 简介项目:谈负责哪些模块、用了哪些技术、其中有没有什么难点或者个人认为比较牛皮的地方。
- 运行时数据区域
以上为基本都会问到的问题,以下为一些其他的问题:
1、Spring 如何设置为多例?设置多例需要注意什么?
在以前项目中还真没设置过多例,都是单例完事。
使用 scope 设置 Spring Bean 的类型,可以在 xml 中使用 scope
属性、含有 @Component
注解的普通 Java 类中或者含有 @Bean
注解的配置类中使用 @Scope
注解,配置类的注解要放在工厂方法上。
@Scope annotations are only introspected on the concrete bean class (for annotated components) or the factory method (for @Bean methods). In contrast to XML bean definitions, there is no notion of bean definition inheritance, and inheritance hierarchies at the class level are irrelevant for metadata purposes.
说@Scope
注解只在具体的 bean 类(带注释的组件)或工厂方法(带@bean
注解方法)上进行内省(be introspected
这什么意思?省略的意思么?或者生效的意思?我觉得应该是生效),相比于 xml 定义的 bean,没有 bean 定义继承的概念(xml 中的 bean 使用 parent 属性,指定父类,父类配置、默认属性都会继承,那么父类是多例的,子类也会是多例的)。
配置:
<bean id="animal" class="com.xuxx.bean.Animal" scope="prototype"/>
<bean id="dog" class="com.xuxx.bean.Dog" parent="animal"/>
测试:
com.xuxx.bean.Animal@61009542
com.xuxx.bean.Animal@77e9807f
com.xuxx.bean.Animal@448ff1a8
com.xuxx.bean.Dog@1a38c59b
com.xuxx.bean.Dog@7f77e91b
com.xuxx.bean.Dog@44a664f2
那么,Spring 为啥默认是单例、什么情况需要设置多例以及设置多例需要注意啥呢?
默认单例,只创建依一次,不会产生额外的对象,提高性能,不会频繁的创建、销毁、回收对象。 单例模式应该保证无状态、幂等性。
单例的话,如果有非静态成员变量,如果可以共享、并发度低,就没问题;在业务上不应该共享、并发度高,就应该设置为多例。
Struts2默认的实现是Prototype模式。也就是每个请求都新生成一个Action实例,所以不存在线程安全问题。
Bean 创建方式
- 构造器(一般都用这个)
- 静态工厂方法
- 实例工厂方法(结合工厂类、实体类/产品类)
2、Spring 有哪几种注入方式?
从配置方式来讲有三种方式:注解、配置类、xml 配置。
从注入方式来讲分属性注入、构造器参数注入、配置类工厂方法注入。
- @Autowired 是 Spring 的注解,默认 byType,根据类全部加载出来,如果一个类有多个实现类,需要配合 @Qualifier 指定具体类的 bean name。
- @Inject 是 JSR330 规范,默认 byType,也可配合 @Qualifier 使用。
- @Resource 是 JSR250 规范,默认 byName,bean name 默认为属性名。如果相同 bean name 的类有多个,可以使用
type
指定具体类。
3、Spring 如何注入集合
从来没做过注入集合,没有遇到这样需求。
注入集合的需求,可能为把一个类所有的实现类注入过来,放入一个 List?或者注入一些配置文件中的字符串?
- xml xml 中的话会有各种标签,<list>、<set>、<map>,标签内部制定要注入的 <value>,map 内部为 <entry> 标签,需要制定 id 与 value。如果是注入 bean,则是 <ref> 标签, map 中 <entry> 标签使用
value-ref
属性。
注入普通属性:
<bean id="javaCollection" class="com.tutorialspoint.JavaCollection">
<!-- results in a setAddressList(java.util.List) call -->
<property name="addressList">
<list>
<value>INDIA</value>
<value>Pakistan</value>
<value>USA</value>
<value>USA</value>
</list>
</property>
<!-- results in a setAddressSet(java.util.Set) call -->
<property name="addressSet">
<set>
<value>INDIA</value>
<value>Pakistan</value>
<value>USA</value>
<value>USA</value>
</set>
</property>
<!-- results in a setAddressMap(java.util.Map) call -->
<property name="addressMap">
<map>
<entry key="1" value="INDIA"/>
<entry key="2" value="Pakistan"/>
<entry key="3" value="USA"/>
<entry key="4" value="USA"/>
</map>
</property>
</bean>
注入 bean:
<bean id="..." class="...">
<!-- Passing bean reference for java.util.List -->
<property name="addressList">
<list>
<ref bean="address1"/>
<ref bean="address2"/>
<value>Pakistan</value>
</list>
</property>
<!-- Passing bean reference for java.util.Set -->
<property name="addressSet">
<set>
<ref bean="address1"/>
<ref bean="address2"/>
<value>Pakistan</value>
</set>
</property>
<!-- Passing bean reference for java.util.Map -->
<property name="addressMap">
<map>
<entry key="one" value="INDIA"/>
<entry key ="two" value-ref="address1"/>
<entry key ="three" value-ref="address2"/>
</map>
</property>
</bean>
如果要注入一个 null,使用 <null/> 标签:
<property name="email"><null/></property>
如果使用注解,就采用第二个问题中的注解即可。比如,使用 @Autowired 把有用共同类的实现类都注入到集合,或者使用 @Resource 把具有相同 bean name 的类注入集合。
普通类型的属性可以使用 @value 注解从配置文件中读取。但是集合怎么操作呢?
4、Mybatis 动态标签
if,choose (when, otherwise),trim (where, set),foreach
一下子我懵了,完全想不起动态标签是这些。
动态标签
5、找出两个 List<Item> 内重复的元素放入一个新的 List 中
如果 Item 是同一地址,肯定同一元素,如果所有属性相同,也被判定为同一元素。
所以要重写 equals 和 hashCode 方法,使用一个 Set ,把第一个 List 装进去,遍历第二个 List,判断是否存在于 Set 中,存在则加入到新的 List 中。
当然做法不止这一个,当时我只想到这一个。
6、以下代码会有什么问题:
if(a == "1") {
// 第一次登录的逻辑
} else if(a == "2") {
// 第二次登录的逻辑
if(b == "3") {
// 一些提示信息
}
} else {
// 其他业务
}
不要管这个 a == "1" 是否会报错,这段代码约定不会报语法错误,能正常运行。
出这个题目考察什么呢?这里展示了一个逻辑控制,不要求去探究语法问题。还是没有思路啊。
可能是想表达第一次与第二次登录的逻辑只会执行一次,后续不会再执行了,而 else 中其他业务逻辑会经常执行,应该放在最前面?
7、应用题:任务调度
把一个15分钟调用一次的任务,改为15秒调用一次,需要注意哪些点?这个任务用于监控数据的获取。
这种题呢,只能根据自己的经验或者想法答了,如果有幸正好做好类似的,那肯定有得聊了。
- 15分钟变为 15秒,为啥要这么变?以前为啥要 15分钟获取一次?是数据量太大,还是实时性不需要太高?
- 那么15秒执行一次,获取数据的条件肯定得修改,不是调用端修改就是提供方修改了。如果能增量获取监控数据,也许不需要去重,为了保证监控数据的完整性,还是需要冗余获取比对去重。
- 考虑数据量的问题,15秒执行一次,如果数据量比较大,要做一些IO操作或者其他固化操作,得考虑使用缓存或者消息队列或者异步执行。
- 每次执行记录日志中。
- 熔断操作,多次请求获取不到数据,就得熔断报错提醒。这一点可以参考 Hystrix Dashboard,看它是怎么做的。
8、应用题:设计接口给别人使用,需要考虑什么?
明确是 http 接口,不是 程序接口。
- 提供文档。比如使用 Swagger,就会包含接口说明、字段说明、测试用例。swagger 多用于内部使用,外部使用的话,得专门写。
- 考虑可用性、并发性、限流、降级。得从系统架构上解决这个问题。
- 考虑恶意调用。比如做单位时间内调用次数限制,操作次数后禁止调用,一定时间内自动解除或者手动解除。
- 考虑安全性。比如使用 token 验证、https。
- 报错信息完善。接口返回内容包括错误代码、错误信息、错误详情解决办法链接等。
- 参考 RESTful 接口风格。
- 接口拆分。提供一个大而全的接口,要针对相应场景拆分为小而专一的接口。
- 考虑单一性。一个接口做一件事。
- 考虑扩展性。比如,预留字段。
- 是否使用缓存。使用缓存就要解决缓存穿透、缓存雪崩等问题。
想到啥就说啊,不管是自己之前有过的设计经验还是调用别人的接口的感受。
接口设计的16个原则