场景引入
OCP开闭原则:对扩展开,对修改闭。只要你在扩展系统功能的时候,没有修改以前写好的代码,那么你就是符合OCP原则的。
DIP依赖倒置原则:面向接口编程,面向抽象编程,不面向具体编程。
上不依赖下,就是符合DIP。
程序违背了OCP原则 也违背了DIP原则,这时候 采用控制反转IoC(Inversion of Control)思想来解决。反转的是两件事:我不在程序中采用硬编码的方式来维护对象的关系了,也不用硬编码的方式来new对象了。
Spring框架
Spring框架实现了控制反转IoC这种思想,Spring框架来new对象和维护对象的关系。
实现方式:依赖注入(DI,Dependency Injection)
依赖:A对象和B对象的关系,注入:通过这种手段,让A和B产生关系。
分两种,set注入和构造方法注入
特点:1、轻量 非侵入式的框架(侵入式:不好做单元测试)2、控制反转 3、面向切面编程 4、容器Bean 5、框架
Spring底层Ioc如何实现的:XML解析+工厂模式+反射机制
Bean的生命周期
分五步:
1.实例化Bean(调用无参构造方法)
2.给Bean属性赋值(调用set方法)
3.初始化Bean(调用Bean的init方法,init方法要自己写自己配)
4.使用Bean
5.销毁Bean(调用Bean的destroy方法,destroy方法需要自己写自己配)
分七步:
1.实例化
2.Bean属性赋值
3.执行Bean后处理器的before方法
4.初始化Bean
5.执行Bean后处理器的after方法
6.使用Bean
7.销毁Bean
分十步:
1.实例化
2.Bean属性赋值
3.检查Bean是否实现了Aware的相关接口,并设置相关依赖
4.执行Bean后处理器的before方法
5.检查Bean是否实现了initializingBean接口,并调用接口方法
6.初始化Bean
7.执行Bean后处理器的after方法
8.使用Bean
9.检查Bean是否实现了DisposableBean接口,并调用接口方法
10.销毁Bean
Spring容器只对单例模式的Bean进行完整的生命周期管理,如果是prototype作用域的Bean,Spring容器只负责将Bean初始化完毕,等客户端程序一旦获取到Bean后,Spring容器就不再管理该对象的生命周期了。
singleton+setter模式下的循环依赖(A的属性需要B赋值,B的属性需要A赋值)是没有问题的。因为spring容器在加载的时候,实例化Bean对象,所有bean对象都会曝光。
在prototype+setter模型下循环依赖是存在问题的,因为是多例模式。如果其中一个是单例,那就没有问题。
三级缓存
三个缓存都是Map集合,Map集合的key存储的都是bean的name(bean id)
一级缓存(豆子):完整的单例Bean对象,这个缓存中的Bean对象的属性都已经赋值了,是一个完整的Bean对象。
二级缓存(青涩的豆子):早期的单例Bean对象,这个缓存中的Bean对象的属性没有赋值,只是一个早期的实例对象。
三级缓存(植株-长豆子的):单例工厂对象,这个里面存储了大量的工厂对象,每一个单例Bean对象都会对应一个单例工厂对象。这个集合中存储的是,创建该单例对象时对应的那个单例工厂对象。
SpringIoc注解式开发
简化XML的配置
声明Bean注解
常见的注解:
@Component 以下三种本质都是component 只是为了方便可读 所以分了三种
@Controller
@Service
@Repository
怎么使用:加入aop的依赖,在配置文件中添加context命名空间,在配置文件中指定扫描的包,在Bean类上使用注解。
负责注入的注解
@Value 注入简单类型
使用@Value注解注入 可以用在属性上 并且可以不写setter方法
也可以使用在set方法、构造方法上。
@Autowired 注入非简单类型 默认根据类型来装配
@Qualifier 和@Autowired联合使用 用名字来装配
用在属性、setter方法、构造方法、构造方法参数上
@Resource 也可以完成非简单类型注入 默认根据名称装配 如果找不到名称 就用类型装配
用在属性上和setter方法上
属于JDK扩展包,需要加依赖。jakarta.annotatiopn-api
JdbcTemplate(不用过多了解)
是对Jdbc的封装,简化JDBC代码。
GoF代理模式
在Java程序中的代理模式的作用
1.当一个对象需要受到保护的时候,可以考虑使用代理对象去完成某个行为。
2.需要给某个对象的功能进行功能增强的时候,可以考虑找一个代理进行增强。
3.A和B无法直接交互,可以用代理模式解决。
三大角色
目标对象,代理对象,公共接口(让客户端在使用代理的时候以为是在用目标对象)
静态代理
代理对象:将目标对象作为代理对象的一个属性,形成关联关系,比继承关系耦合度低。
代理对象含有目标对象的引用,关联关系,has a
创建代理对象的时候要传一个目标对象给代理对象。 (构造方法)
优点:解决OCP问题,采用代理模式的has a 可以减低耦合度
缺点: 类爆炸,假设系统有1000个接口,那每个接口都得有对应的代理类,这样类会急剧膨胀不好维护。
动态代理
字节码生成技术,可以在内存中为我们动态地生成Class字节码,这个字节码就是代理类。
常见技术:
JDK动态代理技术:只能代理接口。
CGLIB动态代理技术:开源代码生成库,可以代理接口也可以代理类。底层是用继承方式实现的,性能比JDK动态代理要好。
Javassist动态代理技术:通过使用javassist对字节码操作为JBoss实现动态aop框架。
面向切面编程AOP
AOP是对OOP的补充延伸。Spring的AOP使用的动态代理是JDK+CGLIB。
一般系统重都会有一些系统服务,比如日志、事务管理和安全等等,这被称为交叉业务。
交叉业务基本是通用的,将和核心业务无关的代码独立地抽取出来,形成一个独立的组件,然后以横向交叉的方式应用到业务流程当中的过程被称为AOP。
优点:代码复用性强,代码易维护,使开发者更关注业务逻辑。
AOP七大术语
连接点JoinPoint:在程序的整个执行流程中,可以织入切面的位置。方法的执行前后,异常抛出之后等位置。
切点Pointcut:在程序执行流程中,真正织入切面的方法。(一个切点对应多个连接点)
通知Advice:又叫增强,具体你要织入的代码。 通知包括 前置通知@Before,后置通知@AfterReturning,环绕通知@Around 最大的范围 在前置通知之前,后置通知、最终通知之后,异常通知@AfterThrowing 发生异常之后执行的通知,最终通知@After 放在finalliy语句块中的通知。
切面Aspect:切点+通知就是切面
织入Weaving:把通知应用到目标对象上的过程
代理对象Proxy:一个目标对象被织入通知后产生的新对象
目标对象Target:被织入通知的对象
两个切面之间谁先执行 用@Order(数字)数字越小 优先级越高
Spring对事务的支持
ACID 原子性 一致性 隔离性 持久性
基于面向切面编程aop的二次封装
声明式事务:基于注解方式(最多) 或者 基于XML配置方式
@Transactional
事务的7种传播行为
REQUIRED:支持当前事务,如果不存在就新建一个(没有就新建,有就加入)
SUPPORTS:支持当前事务,如果当前没有事务,就以非事务的方式执行(有就加入,没有就算了)
MANDATORY:必须运行在一个事务中,如果当前没有事务正在发生,将抛出一个异常(有就加入,没有就抛异常)
REQUIRES_NEW:开启一个新事务,如果一个事务已经存在,则将这个存在的事务挂起(不管有没有,直接开新的,开启的新的和之前的不存在嵌套关系,之前的事务被挂起)
NOT_SUPPORTED:以非事务的方式运行,如果有事务存在,挂起当前事务(不支持事务,存在就挂起)
NEVER:以非事务的方式运行,如果有,就抛出异常(不支持事务,存在就抛异常)
NESTED:如果当前有一个事务正在进行中,则该方法应当运行在一个嵌套式事务中。被嵌套的事务可以独立于外层事务进行提交或回滚。如果外层事务不存在,行为就像REQUIRED一样。(有事务的话,就在这个事务里再嵌套一个完全独立的事务,嵌套的事务可以独立的提交和回滚,没有事务就和REQUIRED一样。)
事务的隔离级别
数据库中读取数据存在的三大问题:
脏读:读取到数据库里没有的数据
不可重复读:在同一个事务中,第一次和第二次读到的数据不一样
幻读:读到的数据是假的。
DEFAULT
READ_UNCOMMITTED 读未提交 存在脏读 可以读到其他事务未提交的数据
READ_COMMITTED 读已提交 解决脏读问题 其他事务提交后才能读到,但是存在不可重复读
REPEATABLE_READ 可重复读 mysql默认级别 解决了不可重复读 只要当前事务不结束,读到的数据一直是一样的,但存在幻读问题
SERIALIZABLE 序列化 解决了幻读问题,事务排队执行,不支持并发。
事务超时
@Transactional(timeout = 10)
表示超过10s如果事务中的所有DML语句还没有执行完毕的话,最终结果会选择回滚
如果想让整个方法的所有代码都计入超时时间的话,可以在方法最后一行添加一行无关紧要的DML语句。
只读事务
@Transactional(readOnly=true)
将当前事务设置为只读事务,在该事务执行过程中只允许select语句执行。不能用增删改。
作用是:启动spring的优化策略,提高select语句的执行效率。
特定回滚
还可以设置哪些异常回滚事务,或者是设置哪些异常不回滚事务。
@Transactional(rollbackFor = RuntimeException.class)
@Transactional(noRollbackFor = NullPointerException.class)
八大设计模式
·简单工厂模式:BeanFactory的getBean方法,通过唯一标识来获取Bean对象。静态工厂模式
工厂方法模式:FactoryBean,在配置文件中通过factory-method属性来制定工厂方法,该方法是一个实例方法。
单例模式:Spring用的是双重判断加锁的单例模式 getSingleton
代理模式:AOP 用的动态代理实现的
装饰器模式:IO流
Spring根据每次请求的不同,将dataSource属性设置成不同的数据源,以达到切换数据源的目的。
Spring中类名里带Decorator和Wrapper的类 都是装饰器模式
观察者模式:Servlet中的ServletContextListener就是观察者模式,观察者ServletContextListener,被观察者:ServletContext 事件:ServletContext对象被创建,或者是被销毁。
Spring中的事件编程模型 ApplicationListener接口,用来监听Application的事件。 Application就是 ApplicationContext。
策略模式:行为性模式,调用不同的方法,适应行为的变化,强调父类的调用子类的特性。
getHandler是HandlerMapping接口中的唯一方法,用于根据请求找到匹配的处理器。
模板方法模式:JdbcTemplate类就是末班类。在模板类的模板方法execute中编写核心算法,具体实现步骤在子类中完成。