在java中,动态代理有两种主要的实现方式,分别为:JDK 动态代理和 CGLIB 动态代理.
JDK 动态代理就是基于 JDK 实现的代理模式,主要运用了其拦截器和反射机制,其代理对象是由 JDK 动态生成的,而不像静态代理方式写死代理对象和被代理类。JDK 代理是不需要第三方库支持的,只需要 JDK 环境就可以进行代理,使用条件:
1.被代理的对象必须要实现接口;(可以直接说这一句,)
2.使用Proxy.newProxyInstance产生代理对象;
3.必须实现InvocationHandler接口;
是CGLIB 动态代理利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
1.被代理的对象不用实现接口;(可以直接说这一句,)
2.CGLIB 必须依赖于 CGLIB 的类库,其为需要被代理的类生成一个子类,覆盖其中的方法,实际上是一种继承
主要区别:
JDK 动态代理只能对实现了接口的类生成代理,而不能针对类;
CGLIB 是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,并覆盖其中方法实现增强,但是因为采用的是继承,所以该类或方法最好不要声明成final
,对于final
类或方法,是无法继承的.
我们在加载一个类的时候,它并不会第一时间自己先去加载,而是去委托给父类的加载器去执行,一旦如果父类加载器还存在其父类加载器,依次递归询问,直到到达最顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,如果不能,那子加载器才会尝试自己去加载,这就是所谓的双亲委派模式.
那么这样做的好处是因为 :
1.类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次
2.因为我们在加载类的时候,有很多核心库已经是自带的,如果是自己能加载,那么会导致核心API库被随意篡改,这样是不安全的,所以使用双亲委托模式将传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的.
事务传播行为就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行.
目前Spring支持7中事务传播行为
propagation_required(需要传播):当前没有事务则新建事务,有则加入当前事务
propagation_supports(支持传播):支持当前事务,如果当前没有事务则以非事务方式执行
propagation_mandatory(强制传播):使用当前事务,如果没有则抛出异常
propagation_nested(嵌套传播):如果当前存在事务,则在嵌套事务内执行,如果当前没有事务,则执行需要传播行为。
propagation_never(绝不传播):以非事务的方式执行,如果当前有事务则抛出异常
propagation_requires_new(传播需要新的):新建事务,如果当前有事务则把当前事务挂起
propagation_not_supported(不支持传播):以非事务的方式执行,如果当前有事务则把当前事务挂起
RDB(半持久化方式):按照配置不定期的通过异步的方式、快照的形式直接把内存中的数据持久化到磁盘的一个dump.rdb文件(二进制的临时文件)中,redis默认的持久化方式,它在配置文件(redis.conf)中。
优点:只包含一个文件,将一个单独的文件转移到其他存储媒介上,对于文件备份、灾难恢复而言,比较实用。
缺点:系统一旦在持久化策略之前出现宕机现象,此前没有来得及持久化的数据将会产生丢失
AOF(全持久化的方式):把每一次数据变化都通过write()函数将你所执行的命令追加到一个appendonly.aof文件里面,Redis默认是不支持这种全持久化方式的,需要在配置文件(redis.conf)中将appendonly no改成appendonly yes
优点:数据安全性高,对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机问题,也不会破坏日志文件中已经存在的内容;
缺点:对于数量相同的数据集来说,aof文件通常要比rdb文件大,因此rdb在恢复大数据集时的速度大于AOF;
加分项(面试官要是感兴趣可以在说下面这些)
在Redis的配置文件中存在三种同步方式,它们分别是:
1. appendfsync always 每次有数据修改发生时都会都调用fsync刷新到aof文件,非常慢,但是安全;
2. appendfsync everysec 每秒钟都调用fsync刷新到aof文件中,很快,但是可能丢失一秒内的数据,推荐使用,兼顾了速度和 安全;
3. appendfsync no 不会自动同步到磁盘上,需要依靠OS(操作系统)进行刷新,效率快,但是安全性就比较差;
二种持久化方式区别:
1.AOF在运行效率上往往慢于RDB,每秒同步策略的效率是比较高的,同步禁用策略的效率和RDB一样高效;
2.如果缓存数据安全性要求比较高的话,用aof这种持久化方式(比如项目中的购物车);
3.如果对于大数据集要求效率高的话,就可以使用默认的。而且这两种持久化方式可以同时使用。
缓存穿透:
一般的当我们通过键去查询对应的值,如果缓存中没有 ,就会去数据库,一旦数据库中也没有,并且这个通过键去查询并发请求很大,就会对数据库产生很大的压力,这就叫缓存穿透.
缓存雪崩:
当缓存服务器重启或者大量缓存集中在一段时间内失效,发生大量的缓存穿透,这样在失效的瞬间对数据库的访问压力就比较大,所有的查询都落在数据库上,造成了缓存雪崩。
1.对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃。
2.将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存 储系统的查询压力。
3.如果一个查询返回的数据为空(不管是数 据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会 很短,最长不超过五分钟。
1.在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其 他线程等待。
2.可以通过缓存reload机制,预先去更新缓存,再即将发生大并发访问前手动触发加载缓存
3.不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀
4.做二级缓存,或者双缓存策略。A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2 设置为长期。
Cookie
Cookies是服务器在本地机器上存储的小段文本并随每一个请求发送至同一个服务器,是一种在客户端保持状态的方案。
Session
Session是存在服务器的一种用来存放用户数据的类HashTable结构。
区别:
Cookie存在客户端所以用户可以看见,所以也可以编辑伪造,不是十分安全。
Session存在服务端过多的时候会消耗服务器资源,所以大型网站会有专门的Session服务器
分布式环境怎么保存用户状态:
第一种: 粘性Session( 常用Nginx锁定Session)
原理:粘性Session是指将用户锁定到某一个服务器上,比如上面说的例子,用户第一次请求时,负载均衡器将用户的请求转发到了A服务器上,如果负载均衡器设置了粘性Session的话,那么用户以后的每次请求都会转发到A服务器上,相当于把用户和A服务器粘到了一块,这就是粘性Session机制。
优点:简单,不需要对session做任何处理。
缺点:缺乏容错性,如果当前访问的服务器发生故障,用户被转移到第二个服务器上时,他的session信息都将失效。
适用场景:发生故障对客户产生的影响较小;服务器发生故障是低概率事件。
第二种:session持久化到数据库
原理:就不用多说了吧,拿出一个数据库,专门用来存储session信息。保证session的持久化。
优点:服务器出现问题,session不会丢失
缺点:如果网站的访问量很大,把session存储到数据库中,会对数据库造成很大压力,还需要增加额外的开销维护数据库。
未完待续.....