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:默认为 1 weight 越大,负载的权重就越大。
  • 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响应用户。

img

关于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基础集合,多线程,事务和锁)都没讲

posted @ 2020-03-16 00:32  Jibny  阅读(138)  评论(0编辑  收藏  举报