要领:基础要扎实、思维要灵活
学习方法-西蒙学习法
1.什么是西蒙学习法
西蒙学习法(Simon's Learning Method)由美国著名心理学家赫伯特·西蒙(Herbert A. Simon)提出,是一种通过分解学习任务、提高知识掌握效率的方法。西蒙提出,学习应当注重策略与方法,将复杂的知识点分解为简单的单元,然后通过不断反复练习和运用这些单元来实现有效学习。
2.核心理念
- 知识结构化:将复杂的知识分解成更小、更易掌握的单元,便于理解和记忆。这种方法注重知识的分层次学习,以建立清晰的知识框架。
- 反复练习:西蒙强调,学习不应仅仅停留在理解层面,更重要的是反复练习以巩固记忆。通过重复运用来逐步增强对知识的掌握。
- 反馈调整:学习过程中要及时获取反馈,以便调整学习方法,优化学习效果。通过反馈,可以发现自己的薄弱点,从而有针对性地改进学习方法。
- 动机管理:西蒙认为,学习者的学习动机在学习中起重要作用。保持学习动机不仅能够提升学习效率,也能帮助学习者更好地应对学习中的困难。
- 即时应用:学到的知识应当立即应用,以加深对知识的理解和掌握。通过应用知识,学习者可以获得成就感,从而保持对学习的兴趣。
设计模式
1.七大软件设计原则与实践
Simple Responsibility Principle 单一职责原则
一个对象只负责一项职责,只做一件事情,粒度往小了说方法,往大了说可以是一个服务,好处是有的,比如提高代码的内聚性,减少程序耦合度,但同时也会提高项目的复杂度。
Open-Closed Principle 开闭原则
对扩展开放对修改关闭,就是在已有的代码上做扩展,新增方法、接口,当然在现实中如果改动很少的代码就可以实现新的需求,那么也就不需要遵守这个规则了。
Liskov Subsitiution Principle 里氏替换原则
子类对象可以替换父类对象且功能不受影响,这就要保证子类不可以重写父类的方法,但可以扩展方法,
Interface Seqreqation Principle 接口隔离原则
接口不要设计的太臃肿,可以将接口设计的更小、更专用。
Dependence Inversion Principle 依赖倒置原则
面向接口编程,比如依赖注入时,注入的应该是接口,这样可以保证具体的实现逻辑易扩展、易维护。
Law of Demeter 迪米特法则
也称:最小知道原则,其实就是依赖接口,不要依赖实现类,类与类之间不要太过耦合。
Composite&Aqqregate Reuse Principle 合成复用原则
尽量避免减少采用直接继承的方式做代码复用,因为这会使类与类之间的耦合关系很高,可以采用聚合的方式比如依赖接口。
2.设计模式总结及工厂模式
设计模式的分类
- 创建型:处理对象的创建过程,工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
- 结构型:处理类或者对象的组合,适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
- 行为型:对类或对象怎样交互和怎样分配职责进行描述,策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介模式、解释器模式。
对应着一套逻辑:首先如果想要实现某个功能,肯定要创建对象,所以像是:工厂、单例、建造者、原型都属于如何更好的创建对象,将对象的创建和使用分离;其次:对象创建好了之后就要考虑对象之间的关系,如果更好的继承、依赖、组合,就有了结构性的设计模式,比如:门面、适配器、代理、装饰、组合、享元;最后:到了具体的实现,如何更好的达到目的,是行为更清晰效率更高就是行为型设计模式要做的事情,比如:策略、责任链、迭代器、方法模板。
工厂模式
创建对象的工厂,通过对象工厂去代替new Xxx(),虽然增加了代码量,但是给系统带来的更大的扩展性和尽可能少的代码修改量(低耦合)。
简单工厂模式
严格来说是一种编程习惯,不属于23种设计模式,将一些创建对象所需要的判断从业务代码中抽离出来,塞到工厂类中最终将想要的对象成产出来。
工厂方法模式
将对象的逻辑下沉到子类里面(创建多个子工厂来创建对象),是简单工厂模式的进一步抽象,运用了多态克服了工厂模式的缺点,优点:无须关心对象创建的具体过程,只需要添加对应的具体工具类无需对原工厂进行修改;缺点:每增加一个类就要添加一个对应的工厂。
抽象工厂模式
创建两个具体工厂类的接口,通过 工厂方法将它们与具体的厂商实现解耦。有助于实现松耦 合和易维护的代码结构
3.单例模式的详解
单例设计模式
在任何情况下,系统中一个类只有一个对象。
饿汉式
对象在类加载时就实例化了,缺:有可能造成资源浪费,优:假如说有OOM的问题,也可以提前及时的暴露出来。
懒汉式
等用到实例的时候再创建,有并发安全的问题,双重检查锁。
懒加载——静态内部类单例
利用了类的加载机制,只要应用中不 使用内部类,JVM就不会去加载这个单例类,也就不会创建单例对象,所以可以保证延迟加载以及线程安全。
饿汉式——枚举单例
枚举 是线程安全的,并且只会装载一次,枚举类是所有单例类 实 现中唯一不会被破坏的单例模式(解决了反射与序列化破坏)。
容器式单例
比如使用CurrentHashMap存储实例,IOC容器。
反射破坏单例
在私有构造函数中抛出异常,禁止反射创建
序列化破坏单例
添加readResolve()方法,返回现有的实例,避免新创建实例。
private Object readResolve() throws
ObjectStreamException {
// 返回现有实例,防止创建新实例
return instance;
}
4.深度分析代理模式
代理模式
为其他对象提供一种代理,用于控制这个对象的访问。在不修改目标目标对象的基础上对功能进行增强,代理分为静态代理和动态代理。
静态代理
通过使用代理类继承目标类的方式,对原方法进行增强,缺点:如果想为其他服务的接口也扩展功能:1.需要增加类的数量 2.不够灵活,在编译时代理的具体类型就已经确认了,无法再运行时选择代理 3.维护成本高,如果原始类接口发生了改变,代理类也需要维护。
动态代理
会制定一个规则,对符合规则的类进行代理,灵活度很高,基于反射实现性能上还是有一些损耗的,分为JDK代理、CGLIB代理。
JDK代理
CGLIB代理
两种动态代理的区别
- 实现方式
- 拦截被代理对象的方式
- 性能和效率
代理模式的优缺点
优点:将代理对象与目标对象分离,降低程序的耦合度,易于扩展,也起到了保护对象的作用。
缺点:增加了系统的复杂度,并且因为添加代理对象,请求速度会受到影响。
5.原型、建造者、适配、委派、策略、模板方法模式
建造者模式详解
原型模式和建造者模式作业解答
原型模式详解
基于一个已有的对象通过复制的方式复制出一个对象,减少了对象直接创建的成本。
适配器模式详解
适配器模式和桥接模式作业解答
委派模式详解
负责任务的调用和分配,是一种特殊的静态代理,可理解为全权代理(代理模式注重过程,委派模式注重结果),
模板方法模式详解
在父类中定义业务处理流程的框架,到子类种去做具体的实现。
委派模式和模板方法模式作业就解答
策略模式详解
根据业务的不同,选择不同的策略来处理。
Spring框架
一个轻量级的开源框架、为简化企业级应用开发复杂性而生,以IOC、AOP为核心的容器框架。
Spring架构基础概念及应用
IOC
IOC是什么?
控制反转,由Spring创建、管理对象,并提供了懒加载、作用域、生命周期方法、依赖属性等。
IOC解决了什么?
主要解决了对象创建和依赖管理的问题,
1. 解耦(依赖注入减少了new,使每个类职责更单一)
2.便于管理和扩展维护(修改依赖关系无需更改代码逻辑,可扩展性、灵活性)
3.增强可测试性(动态替换测试类的实现)
4.节省开发时间成本(专注于业务)
Bean装配细节、生命周期
Bean的生命周期
1. 实例化(Instantiation)
容器启动时,会根据解析XML/Annotation通过反射创建对象,但此时未进行依赖注入和初始化。
2. 属性赋值(Populate Properties)
根据XML/Annotation,讲Bean所依赖的属性注入到该Bean中。
3. BeanPostProcessor 前置处理(Post-Process Before Initialization)
如果有实现类实现了BeanPostProcessor接口并实现了此方法postProcessBeforeInitialization,可进行执行一些自定义的前置处理逻辑。
4. 初始化(Initialization)
实现InitializingBean接口,调用其afterPropertiesSet()
方法。此外,若在Bean中定义了 init-method方法,Bean生命周期中执行自定义初始化逻辑的阶段。
5. BeanPostProcessor 后置处理(Post-Process Before Initialization)
初始化后,如果有实现类实现了BeanPostProcessor接口并实现了方法postProcessAfterInitialization,用于在Bean完全初始化后执行额外处理(如代理增强等)。
6. Bean 就绪使用(Bean is Ready for Use)
Bean已经完全初始化,且已加载到IOC容器中,随时可以被其他Bean或应用程序使用。
7. 销毁(Destruction)
容器关闭时,会销毁容器中的对象。对象销毁前会调用实现了DisposableBean中的方法destroy(),然后调用在Bean定义中指定的destroy-method
。销毁方法可以用于清理资源等操作。
Spring注解
组件声明注解
@Controller、@Service、@Repository、@Component
配置和Bean定义注解
@Configuration、@Bean、@Scope、@Lazy、@Primary(多个Bean符合依赖注入条件时,指定默认优先注入的Bean)、@Value(为Bean的字段注入配置文件中的值)
生命周期管理注解
@PostConstruct(Bean初始化完成后执行)、@PreDestroy(容器销毁Bean之前执行)
依赖注入和装配注解
@Autowired、@Qualifier、@Resource
条件装配和管理注解
@Conditional(满足指定条件时,Bean才会被实例化)、@Profile(指定Bean适用的环境,如开发环境(dev)或生产环境(prod),可以根据不同环境加载不同配置)、@ConfigtionalOnMissBean(在容器中没有指定类型的Bean时才会装配该Bean)、@ConfigtionalOnProperty(根据属性文件中的属性值来决定是否创建Bean,通常用于条件化配置)
事务和异步管理注解
@Transactional、@EnableTransactionManagement(启用Spring的注解驱动事务管理)、@Async(用于标识异步执行的方法,结合@EnableAsync
一起使用)、@EnableAsync(启用Spring的异步支持,使得@Async
生效)
SpringAOP概念及常用的场景
Spring Aop是什么?
面向切面编程,在不改变核心业务代码的前提下,通过动态代理对核心业务功能进行增强。是代码更整洁、降低了代码的耦合度。
Spring Aop常用的场景
1. 日志记录(在方法执行的前后、异常抛出时记录日志,减少日志代码冗余,还可以更方便地统一管理日志输出)
2. 权限校验(进入方法前检查用户的角色是否有权限访问该资源,这种方式可以集中管理权限逻辑,而不必将校验代码分散在业务逻辑中)
3. 事务管理(通过AOP动态地为方法添加事务管理功能,确保方法在同一事务中执行,遇到异常时自动回滚,@Transactional注解)
4. 异常处理(AOP中集中管理异常,捕获异常并处理,对异常进行统一友好处理)
5. 性能监控(记录方法的执行时间,生成性能报告或报警)
6. 缓存管理(在方法调用前先检查缓存中是否有结果,若有则直接返回缓存结果,否则执行方法并将结果存入缓存,AOP切面使得缓存管理更加灵活,可以按需切换缓存策略)
7. 数据校验(在方法执行前对入参验证。可以减少冗余的校验代码,提高代码的清晰度和复用性)
8. 监控和审计(AOP记录操作日志,跟踪用户对系统的操作,便于后续审计和合规检查)
9. 限流和防刷(在方法调用前进行限流控制,防止高频请求导致系统过载,通过AOP切面,动态地添加限流逻辑,避免重复编写限流代码)
10. 动态代理和增强(使用AOP可以对某些方法动态生成代理并添加增强逻辑,比如在微服务调用中动态地添加重试机制或熔断逻辑)
Spring事务
Spring事务的本质
底层数据库的事务,调用的是数据库封装的Api
事务的隔离界别
读未提交、读已提交、可重复读、串行化
事务的传播行为
REQUIRED(当前方法必须在事务中执行,如果当前已经存在事务,则加入到该事务,否则创建一个事务去执行)
REQUIRES_NEW(当前方法总是启动一个新的事务,当前方法总会启动一个新的事务,如果已经存在事务则将事务挂起,直到新事务完成)
SUPPORTS(当前方法可以在事务中执行,也可以在非事务执行,如果存在事务则加入事务,如果没有事务也不会创建事务了)
NOT_SUPPORTED(当前方法不应该在事务中执行,如果存在事务则将其挂起,直到当前方法执行结束)
NEVER(当前方法不允许在事务中执行,如果已存在事务,则抛出异常)
MANDATORY( 当前事务必须在一个事务中运行,如果当前不存在事务则抛出异常)
NESTED(如果当前存在事务,则在当前事务内执行,嵌套一个新事务,不会影响到外部事务状态)
Spring框架IOC核心原理
IOC的设计思想及实现
获取beanFactory实例、读取解析XML生成BeanDefinition——obtainFreshBeanFactory()
1.创建Bean工厂DefaultListableBeanFactory。
2.设置DefaultListableBeanFactory是否支持Bean覆盖、循环依赖。
3.创建Spring自定义Xml读取器XmlBeanDefinitionReader并将DefaultListableBeanFactory注入。
4.通过XmlBeanDefinitionReader读取Xml配置loadBeanDefinitions(location)。
5.通过ThreadLocal中拿到Set<EncodedResource>所有的Xml配置源,并保持加载的资源在set中唯一。
6.创建DocumentBuilderFactory工厂类、DocumentBuilder建造者类解析InputSource得到Document对象。
7.创建BeanDefinitionDocumentReader读取器,将document解析并注册到容器中。
读取解析类中Annotation注解组件类
注册bean的后置处理器——registerBeanPostProcessors(beanFactory);
Spring循环依赖原理
什么是循环依赖?
ClassA在初始化时需要依赖注入B,那就要创建ClassB,在初始化ClassB时有需要ClassA,这样就陷入到了无限的循环中,Spring是不建议循环依赖的,默认检测到循环依赖会抛异常,但同时Spring也提供了解决循环依赖的解决方案,三级缓存,在初始化后将自身提前暴露出去。
循环依赖发生的时机?
组件类之间相互引用
循环依赖造成什么影响?
如何解决循环依赖?
三级缓存
1.一级缓存(singletonObjects):存储完全初始化完成的单例Bean,最终用户从Spring容器中获取Bean就是通过这个容器。
2.二级缓存(earlySingletonObjects):存储早期曝光的Bean,这些实例还未完成初始化过程,但同样也是提前暴露使用的,使用二级缓存为了允许对象应用AOP代理。
3.三级缓存(singletonFactories):存储的是ObjectFactory,在实例化后将对象存入三级缓存提前暴露,解决循环依赖问题。
Spring AOP原理分析
AOP设计思想
手写AOP的核心逻辑
整体流程(未支持多切面)
1.启动容器时,把切面织入的方法与方法链的关系做了绑定
2.在调用时,通过方法名可以获取到执行链
3.在启动Aop时,做好很多关系的映射
4.在AOP调用过程中,通过“索引+递归“完成方法的执行顺序逻辑
Spring Aop源码分析
源码分析五个问题
1.明确AOP动作在Spring源码中的位置
2.理解@EnableAspectJAutoProxy注解
3.明确AnnotationAwareJAutoProxyCreator执行时机
4.Spring AOP如何生成代理对象
5.Spring AOP代理对象的调用流程
Spring如何实现多层代理
深入理解Bean生命周期
前置问题
Bean的生命周期是什么?(从无、创建、初始化、使用、销毁一系列周期)
谁在控制Bean的生命周期?(Spring框架)
Bean生命期描述的对象是谁?(单例对象)
为Bean设定生命周期有什么意义?(钩子接口,扩展)
Bean生命周期主要节点
定义Bean(xml、Annotation)、注册Bean(BeanDefinition)、实例化Bean(createBeanInstance())、初始化Bean(initalizeBean())、调用Bean(getBean())、销毁Bean(close())
Bean生命周期中的钩子接口
Spring事务的原理分析
Spring事务原理分析
AOP
动态数据案例分析
再谈Spring事务失效场景
并发编程J.U.C
并发编程的发展以及价值
Java多线程基本原理
Java语言实际上没有创建线程的能力,通过native本地方法在JVM层面调用C++请求操作系统分配的线程。
OS调度算法
线程的状态
新建(初始状态,未调用start方法)
运行状态(Java中就绪和运行中统一称为运行状态)
阻塞(线程某种原因放弃了CPU使用权)
· 等待阻塞:运行的线程执行wait时,JVM会将当前线程置入等待队列
· 同步阻塞:在获取对象同步锁时,若锁已被占用,则放入到锁池中
· 其他阻塞:运行的线程执行Thread.sleep或者t.join方法,或者发出了I/O请求时,JVM会把 当前线程设置为阻塞状态,当sleep结束、join线程终止、io处理完毕则线程恢复
等待(等待状态)
超时等待(超时等待状态,超时后自动唤醒)
终止(当前线程执行完毕)
线程的终止
stop(强制停止)、interrupt(做标记,由线程自行决定)
Thread Dump日志分析
并发编程带来的挑战之同步锁
并发编程带来的安全性挑战
原子性:Synchronized, AtomicXXX、Lock
可见性:Synchronized, volatile
有序性:Synchronized,volatile
原子性问题原因及本质
一个CPU核心在同一时刻只能执行一个线程,如果线程的数量远远大于CPU核心数,就会发生线程切换的操作。
锁的实现模型理解——syncronized原理
通过加锁将线程间的并行变为串行,Java中每个对象都有一个监视器锁,锁标记存储在对象头。
Markword(对象头)
Hotspot虚拟机中,对象在内存中的存储布局分为三个区域,对象头(Header)、实例数据(Instance Data)、对齐填充(Padding)——解决伪共享。
synchronized锁升级机制
轻量级锁的获取及原理
偏向锁的获取及原理
重量级锁的获取及原理
CAS
并发编程带来的挑战之可见性
为什么实现单例的双重校验锁需要添加volatile关键字?
Instance instance=new Instance() 不是一个原子操作,存在指令重排序问题,分为三步:
- 为对象分配内存
- 初始化对象
- 把内存的地址复制到对象的引用
并发安全性之Lock锁及原理分析
线程阻塞唤醒wait,notify以及condition, 死锁等原理分析
为什么wait、notify的运行需要在Synchronized中?
1.互斥,防止多线程同时运行。
2.等待唤醒中,需要队列进行通信,利用Synchronized完成通信
Condition等价于wait、notify,为什么还要另外实现?
condition源码分析及基于condition实现阻塞队
J.U.C并发工具集场景及原理分析
ThreadLocal&ForkJoin
并发安全的集合ConcurrentHashMap
站在架构的角度思考线程池的设计和原理
Java8新的异步编程方式
Mybatis
ORM框架的发展历史与MyBatis的高级应用
传统JDBC太过复杂,加载驱动、获取链接、执行语句、处理结果集、释放资源。