Spring
- spring4 => springboot1
- spring5 => springboot2
SpringAOP顺序
Spring4
- 正常执行:@Before(前置通知) ===> @After(后置通知) ===> @AfterReturning(正常返回)
- 异常执行:@Before(前置通知) ===> @After(后置通知) ===> @AfterThrowing(方法异常)
Spring5
- 正常执行;@Before(前置通知) ===> @AfterReturning(正常返回) ===> @After(后置通知)
- 异常执行:@Before(前置通知) ===> @AfterThrowing(方法异常) ===> @After(后置通知)
Spring循环依赖
- 什么是循环依赖?
多个bean之间相互依赖,形成了一个闭环。比如:A依赖于B、B依赖于C、C依赖于A。
- 循环依赖两种情况?
- 构造器注入: 会抛出BeanCurrentlyInCreationException。即则可能会创建无法解决的循环依赖场景。
如此,我们会发现这样会无限套娃。@Component public class ServiceA { private ServiceB serviceB; public ServiceA(ServiceB serviceB) { this.serviceB = serviceB; } } @Component public class ServiceB { private ServiceA serviceA; public ServiceB(ServiceA serviceA) { this.serviceA = serviceA; } } public class ClientConstruct { public static void main(String[] args) { new ServiceB(new ServiceA(new ServiceB())); } }
- set注入:可以实现循环依赖
运行结果:@Component public class ServiceAA { private ServiceBB serviceBB; public void setServiceBB(ServiceBB serviceBB) { this.serviceBB = serviceBB; System.out.println("ServiceAA 里设置了 ServiceBB"); } } @Component public class ServiceBB { private ServiceAA serviceAA; public void setServiceAA(ServiceAA serviceAA) { this.serviceAA = serviceAA; System.out.println("ServiceBB 里设置了 ServiceAA"); } } public class ClientSet { public static void main(String[] args) { ServiceAA serviceAA = new ServiceAA(); ServiceBB serviceBB = new ServiceBB(); serviceAA.setServiceBB(serviceBB); serviceBB.setServiceAA(serviceAA); } }
- Spring循环依赖
- 默认的单例(Singleton)的场景是支持循环依赖的,不报错
- 原型(Prototype)的场景是不支持循环依赖的,会报错
- Spring内部通过3级缓存来解决循环依赖(DefaultSingletonBeanRegistry)
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { protected static final Object NULL_OBJECT = new Object(); protected final Log logger = LogFactory.getLog(this.getClass()); private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);// 一级缓存 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);// 三级缓存 private final Map<String, Object> earlySingletonObjects = new HashMap(16);// 二级缓存
- 第一级缓存(也叫单例池)singletonObjects: 存放已经经历了完整生命周期的Bean对象
- 第二级缓存 earlySingletonObjects: 存放早期暴露出来的Bean对象,Bean的生命周期未结束(属性还未填充完)
- 第三级缓存 singletonFactories: 存放可以生成Bean的工厂
- 实例化/初始化
- 实例化
- 内存中申请一块内存空间(租赁好房子,自己的家具东西还没有搬家进去)
- 初始化
- 完成属性的各种赋值(装修,家电家具进场)
- 实例化
- refresh()方法就是加载Spring容器初始化的方法
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); this.setConfigLocations(configLocations); if (refresh) { this.refresh();// 这个 } }
- 在Spring中那些以do开头的方法都是真正的业务逻辑方法(干实事的)
- 四大方法?
- getSingleton(): 获取单例
- doCreateBean(): 实例化Bean
- populateBean(): 初始化Bean
- addSingleton(): 将Bean添加到第一级缓存中,且从第三级缓存以及第二级缓存中删除。
Redis
- 什么是LRU算法?
LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的数据予以淘汰。 - LRU算法思想:哈希+链表(HashMap + DoubleLinkedList)
- 时间复杂度是O(1),哈希表+双向链表的结合体
- 巧用LinkedHashMap完成LRU算法
public class LRUCacheDemo extends LinkedHashMap { private int capacity; public LRUCacheDemo(int capacity) { // Params: // initialCapacity – the initial capacity // loadFactor – the load factor // accessOrder – the ordering mode - true for access-order, false for insertion-order super(capacity, 0.75F, true); this.capacity = capacity; } @Override protected boolean removeEldestEntry(Map.Entry eldest) { return super.size() > capacity; } public static void main(String[] args) { LRUCacheDemo lruCacheDemo = new LRUCacheDemo(3); lruCacheDemo.put(1, "a"); lruCacheDemo.put(2, "b"); lruCacheDemo.put(3, "c"); System.out.println(lruCacheDemo.keySet()); // [1, 2, 3] lruCacheDemo.put(4, "d"); System.out.println(lruCacheDemo.keySet()); // [2, 3, 4] lruCacheDemo.put(3, "c"); System.out.println(lruCacheDemo.keySet()); // [2, 4, 3] lruCacheDemo.put(3, "c"); System.out.println(lruCacheDemo.keySet()); // [2, 4, 3] lruCacheDemo.put(3, "c"); System.out.println(lruCacheDemo.keySet()); // [2, 4, 3] lruCacheDemo.put(5, "d"); System.out.println(lruCacheDemo.keySet()); // [4, 3, 5] } }