Java开发面经(一)
Nignx用来干嘛的,转发策略?
静态HTTP服务器,代理静态资源(主流静态资源服务器),转发动态请求,负载均衡等,相对于tomcat等动态资源解析服务器效率更高
转发策略
1.默认轮询
upstream backserver{
server 192.168.1.1:8080
server 192.168.1.2:8080
}
2.按比重Weight(学的时候时候讲加权随机记成随机了)
upstream backserver {
server 192.168.1.1:8080 weight=3;
server 192.168.1.2:8080 weight=7;
}
3.IP_hash 每个请求按访问ip的hash结果分配,可以解决session登入信息问题
upstream backserver {
ip_hash;
server 192.168.0.14:88;
server 192.168.0.15:80;
}
(其他还有第三方的)
4.fair按响应时间
upstream backserver {
server server1;
server server2;
fair;
}
5.url_hash 按访问url的hash结果来分配请求,每个url定向到同一台服务器
upstream backserver {
server squid1:3128;
server squid2:3128;
hash $request_uri;
hash_method crc32;
}
使用
upstream
:每个设备的状态:down
:表示当前的server
暂时不参与负载weight
:默认为 1weight
越大,负载的权重就越大。max_fails
:允许请求失败的次数默认为 1 当超过最大次数时,返回proxy_next_upstream
模块定义的错误fail_timeout
:max_fails
次失败后,暂停的时间。backup
:其它所有的非backup
机器down
或者忙的时候,请求backup
机器。所以这台机器压力会最轻
proxy_pass http://backserver/;
upstream backserver{
ip_hash;
server 127.0.0.1:9090 down;
#(down 表示单前的server暂时不参与负载)
server 127.0.0.1:8080 weight=2;
#(weight 默认为1.weight越大,负载的权重就越大)
server 127.0.0.1:6060;
server 127.0.0.1:7070 backup;
#(其它所有的非backup机器down或者忙的时候,请求backup机器)
}
worker_processes 4;
events {
# 最大并发数
worker_connections 1024;
}
http{
# 待选服务器列表
upstream myproject{
# ip_hash指令,将同一用户引入同一服务器。
ip_hash;
server 125.219.42.4 fail_timeout=60s;
# fail_timeout:max_fails次失败后,暂停的时间
server 172.31.2.183;
}
server{
# 监听端口
listen 80;
# 根目录下
location / {
# 选择哪个服务器列表
proxy_pass http://myproject;
}
}
}
ActiveMQ使用场景?
消息队列引入主要是为了,异步,解耦,削峰。可以理解成两个应用程序间(生产者消费者间)的通信。
请求发给队列后立即返回,费者进程从消息队列中获取数据,异步写入数据库,延迟可得到有效改善
需要使用消息机制的地方,比如:发布,订阅,发送点对点消息;
需要使用队列的地方,比如:秒杀,抢票,订单处理,短信发送模块。(前后端速度不一致)
Spring MVC 工作流程,常用注解
常用注解
@Controller:标识这个类是一个控制器
@RequestMapping:给控制器方法绑定一个uri
@ResponseBody:将java对象转成json,并且发送给客户端
@RequestBody:将客户端请求过来的json转成java对象
@RequestParam:当表单参数和方法形参名字不一致时,做一个名字映射
@PathVarible:用于获取uri中的参数,比如user/1中1的值
Rest风格的新api
@RestController相当于@Controller+ @ResponseBody
@GetMapping@DeleteMapping@PostMapping@PutMapping
其他注解
@SessionAttribute:声明将什么模型数据存入session
@CookieValue:获取cookie值
@ModelAttribute:将方法返回值存入model中
@HeaderValue:获取请求头中的值
工作原理
请求DispatcherServlet—>映射处理器返回控制器—>处理适配器执行控制器返回ModelAndView—>解析视图—>渲染视图—>返回响应
具体:
1、用户发送请求至前端控制器DispatcherServlet。
2、DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3、处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、 DispatcherServlet调用HandlerAdapter处理器适配器。
5、HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
6、Controller执行完成返回ModelAndView。
7、HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
8、DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
9、ViewReslover解析后返回具体View.
10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
11、DispatcherServlet响应用户。
关于Spring 中IOC和AOP的理解,以及常用到注解
IOC
控制反转,将对象的创建权交由Spring容器来完成,然后注入对象(DI依赖注入)
实现注入主要是通过bean后置处理器BeanPostProcessor接口的实现类
-
基于构造函数的依赖注入
-
基于设置函数的依赖注入
-
基于自动装配的依赖注入
自动装配有三种模式:byType(类型模式),byName(名称模式)、constructor(构造函数模式)
-
基于注解的依赖注入
@Autowired byType,多个实例配合@Qulifier指定名字,如果要允许null值,可以设置它的required属性为false
@Resource 默认ByName,可指定
AOP
面向切面编程,纵向重复,横向抽取
应用:日志,权限,调试,事务
Aspect,Join Point,Advice(Before,After,After-returning,After-throwing,Around,Pointcut)Introduction,Target Object,AOP Proxy,Wearving
本质是Java的动态代理和CGLIB字节码增强
JDK动态代理
利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制生成一个实现代理接口的匿名类,
在调用具体方法前调用InvokeHandler来处理。
CGLiB动态代理
利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
实现CGLIB动态代理必须实现MethodInterceptor(方法拦截器)接口
区别
jdk只能针对接口不能针对类实现代理。
CGLib通过继承方式实现代理。所以类或方法最好不要声明成final,对于final类或方法,是无法继承的。
选择
1)当Bean实现接口时,Spring就会用JDK的动态代理。
2)当Bean没有实现接口时,Spring使用CGlib是实现。
3)可以强制使用CGlib(在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)。
@Aspect
@Component//配置bean
public class WebLogAspect {
private Logger logger = Logger.getLogger(getClass());
@Pointcut("execution(public * com.jibny.boot.projects.web.controller..*.*(..))")
public void webLog() {}
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 记录下请求内容
logger.info("---------------request----------------");
logger.info("URL : " + request.getRequestURL().toString());
logger.info("HTTP_METHOD : " + request.getMethod());
logger.info("IP : " + request.getRemoteAddr());
Enumeration<String> enu = request.getParameterNames();
while (enu.hasMoreElements()) {
String name = (String) enu.nextElement();
logger.info("name:" + name + " - value:" + request.getParameter(name));
}
}
@AfterReturning(returning = "ret", pointcut = "webLog()")
public void doAfterReturning(Object ret) throws Throwable {
logger.info("---------------response----------------");
// 处理完请求,返回内容
logger.info("RESPONSE : " + ret);
}
}
聊一聊Mybatis
1.读取配置文件,包含数据库连接信息和Mapper映射文件或者Mapper包路径,
2.通过SqlSessionFactoryBuilder创建SqlSessionFactory,
3.SqlSessionFactory建立SqlSession(方法结束后关闭),目的执行sql语句
4.解析sql动态标签为对应sql,并将其封装进MapperStatement对象,通过executor执行返回结果
注解绑定Sql:@Select@Update@Delete@Insert
XML绑定Sql
需要注意的地方namespace指定类的全类名
parameterType查询参数
resultType属性应该和表字段对应
if-test实现动态Sql
<mapper namespace="top.shmly.mapper.UserMapper">
<select id="findUserByIds" parameterType="list" resultType="user">
<!-- SELECT * FROM user WHERE id in (1,2,3) -->
SELECT * FROM user
<where>
<if test="list != null and list.size > 0">
<foreach collection="list" item="id" open="id in(" close=")" separator=",">
${id}
</foreach>
</if>
</where>
</select>
</mapper>
resultMap属性名和对应数据库表中的字段名不同时可以指定字段,可以实现延迟加载(不需要立即返回关联查询结果,查询订单,不一定需要及时返回订单对应的产品信息),实现比较麻烦,用于多表模型中嵌套模型(多表也可以封装成VO用resultType)
assocication可以指定联合的对象
<resultMap id="userResultMap" type="user">
<id property="id" column="id_"></id>
<result property="username" column="username_"></result>
<result property="sex" column="sex_"></result>
<result property="birthday" column="birthday_"></result>
<result property="address" column="address_"></result>
</resultMap>
<select id="findUserByIdResultMap" parameterType="int" resultMap="userResultMap">
SELECT
id id_,
username username_,
sex sex_,
birthday birthday_,
address address_
FROM user WHERE id = #{id}
</select>
mapper逆向工程以及继承tk.mapper
逆向生成通过mybatis-generator对数据库表自动生成单表查询的model,modelExample,mapper接口,mapper.xml,通过Example.Criteria进行条件筛选。
缺点:数据库表字段变动,配置文件就要修改,批量操作要重写,不支持分页,可移植性差
通用mapper,引入依赖继承Mapper接口,通用 Mapper 中已经写好了一些常用的内置接口,全局Example类,属性加了 (持久化)注解,支持批量和分页等操作
@Id标记主键,@Column(name = "真实名称"),@Tranisent忽略字段
Spring Boot自动装配
@SpringBootApplication组合注解
- @SpringBootConfiguration
- @EnableAutoConfiguration
- @ComponentScan
通过其中@EnableAutoConfiguration开启自动装配
@EnableAutoConfiguration开启自动装配-->@Import({EnableAutoConfigurationImportSelector})导入配置-->SpringFactoriesLoader.loadFactoryNames扫描META-INF/spring.factories文件-->AutoConfiguration依赖包下的类@Conditional条件注解
@ConditionalOnBean
@ConditionalOnClass
@ConditionalOnMissingBean
......
mysql索引
索引可以优化查询和检索速度,避免全表扫描,创建索引条件一般为where子句后字段
mysql索引采用B+树数据结构,类似平衡二叉树变种,非叶子节点存指针指向子节点的地址,只有叶子节点存数据,从左到右有序非递减。
索引是在存储引擎层实现的,而不是在服务器层实现的,所以不同存储引擎具有不同的索引类型和实现。InnoDB 的 B+Tree 索引分为主索引和辅助索引。
主索引的叶子节点 data 域记录着完整的数据记录,这种索引方式被称为聚簇索引。因为无法把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引。
辅助索引的叶子节点的 data 域记录着主键的值,因此在使用辅助索引进行查找时,需要先查找到主键值,然后再到主索引中进行查找。
索引的使用原则和注意事项
- 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
- 除了数据表占数据空间之外,每一个索引还要占一定的物理空间。如果要建立聚簇索引,那么需要的空间就会更大。
- 当对表中的数据进行增加、删除和修改的时候,索引也要动态地维护,这样就降低了数据的维护速度。
建索引遵循原则:
- 在经常需要搜索的列上建立索引,可以加快搜索的速度。
- 在作为主键的列上创建索引,强制该列的唯一性,并组织表中数据的排列结构。
- 在经常使用表连接的列上创建索引,这些列主要是一些外键,可以加快表连接的速度。
- 在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,所以其指定的范围是连续的。
- 在经常需要排序的列上创建索引,因为索引已经排序,所以查询时可以利用索引的排序,加快排序查询。
- 在经常使用 WHERE 子句的列上创建索引,加快条件的判断速度。
总体回答的一般漏了挺多,准备了很多(Java基础集合,多线程,事务和锁)都没讲