在Spring容器中找出实现了BeanDefinitionRegistryPostProcessor以及BeanFactoryPostProcessor接口的processor并执行。Spring容器会委托给PostProcessorRegistrationDelegate的invokeBeanFactoryProcessors方法执行。
Spring启动过程分析2(prepareBeanFactory)
prepareBeanFactory
方法在AbstractApplicationContext.refresh
流程中。对前面获取到的beanFactory(ConfigurationListableBeanFactory)进行相关的设置,包括ClassLoader, post-processors,为后续的使用做准备。
Spring启动过程分析1(overview)
1 | public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) { |
SpringBoot如何优雅的将静态资源配置注入到工具类中
资源注入类:
1 | @Configuration |
工具类:
1 | @Component |
Spring Scheduler
Cron
想了解Cron最好的方法是看Quartz的官方文档。
Cron表达式由6~7项组成,中间用空格分开。从左到右依次是:秒、分、时、日、月、周几、年(可忽略)。值可以是数字,也可以是以下符号:
*
:所有值都匹配?
:无所谓,不关心,通常放在”周几”里,
:或者/
:增量值-
:区间
下面举几个例子:
0 * * * * *
:每分钟(当秒为0的时候)0 0 * * * *
:每小时(当秒和分都为0的时候)*/10 * * * * *
:每10秒0 5/15 * * * *
:每小时的5分、20分、35分、50分0 0 9,13 * * *
:每天的9点和13点0 0 8-10 * * *
:每天的8点、9点、10点0 0/30 8-10 * * *
:每天的8点、8点半、9点、9点半、10点0 0 9-17 * * MON-FRI
:每周一到周五的9点、10点…直到17点(含)0 0 0 25 12 ?
:每年12约25日圣诞节的0点0分0秒(午夜)0 30 10 * * ? 2016
:2016年每天的10点半
其中的?
在用法上其实和*
是相同的。但是*
语义上表示全匹配,而?
并不代表全匹配,而是不关心。比如对于0 0 0 5 8 ? 2016
来说,2016年8月5日是周五,?
表示我不关心它是周几。而0 0 0 5 8 * 2016
中的*
表示周一也行,周二也行…语义上和2016年8月5日冲突了。
不记得也没关系,记住Cron Maker也可以,它可以在线生成cron表达式。
nginx整理
内置预定义变量
$args
:这个变量等于GET请求中的参数。例如foo=123&bar=456,这个变量只能被修改$host
:请求中的主机头(HOST)字段,如果请求中的主机头不可用或者空,则为处理请求的server名称(处理请求的server的server_name指令的值)。值为小写,不包含端口$http_host
: 原始请求的host$http_port
: 原始请求的port$remote_addr
:客户端的IP地址$remote_port
:客户端的端口$request_uri
:这个变量等于包含一些客户端请求参数的原始URI,它无法修改,请查看$uri更改或重写URI$scheme
:所用的协议,比如http或者是https,比如rewrite ^(.+)$ $scheme://example.com$1 redirect;
$server_addr
:服务器地址,在完成一次系统调用后可以确定这个值,如果要绕开系统调用,则必须在listen中指定地址并且使用bind参数$server_name
:服务器名称$server_port
:请求到达服务器的端口号$server_protocol
:请求使用的协议,通常是HTTP/1.0或HTTP/1.1$uri
:请求中的当前URI(不带请求参数,参数位于$args
),不同于浏览器传递的$request_uri
的值,它可以通过内部重定向,或者使用index指令进行修改。不包含协议和主机名,例如/foo/bar.html
Spring事务
Spring @Transactionl的传播行为和隔离级别
事务注解方式 @Transactional
- 标注在类前:标示类中所有方法都进行事务处理
- 标注在接口、实现类的方法前:标示方法进行事务处理
事务传播行为介绍
事务 | 说明 |
---|---|
@Transactional(propagation=Propagation.REQUIRED | 如果有事务,那么加入事务,没有的话新建一个(默认情况) |
@Transactional(propagation=Propagation.NOT_SUPPORTED | 容器不为这个方法开启事务 |
@Transactional(propagation=Propagation.REQUIRES_NEW | 不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务 |
@Transactional(propagation=Propagation.MANDATORY | 必须在一个已有的事务中执行,否则抛出异常 |
@Transactional(propagation=Propagation.NEVER | 必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反) |
@Transactional(propagation=Propagation.SUPPORTS | 如果其他bean调用这个方法,在其他bean中声明事务,那就用事务。如果其他bean没有声明事务,那就不用事务 |
UML类图中的六大关系:关联、聚合、组合、依赖、继承、实现
简介
在UML类图中,类之间的关系可以分成:关联(association)、聚合(aggregation)、组合(composition)、依赖(dependency)、泛化(generalization)/继承(inheritance)、实现(realization)。
上面的关系可以解读如下:
- (关联)Association:A类和B类有逻辑上的连接
- (聚合)Aggregation:A类有一个B类
- (组合)Composition:A类拥有一个B类
- (依赖)Dependency:A类使用了B类
- (继承)Inheritance:B类是一个A类(或者B类扩展A类)
- (实现)Realization:B类实现了接口A
设计模式6大设计原则
单一职责原则SRP(Single Responsibility Priciple)
所谓单一职责原则,指的是,一个类应该仅有一个引起它变化的原因。
这里变化的原因就是所说的“职责”,如果一个类有多个引起它变化的原因,那么也就意味着这个类有多个职责,再进一步说,就是把多个职责耦合在一起了。这会造成职责的相互影响,可能一个职责的变化,会影响到其他职责的实现,甚至引起其他职责随着变化。
里氏替换原则LSP(Liskov Substitution Principle)
所有引用基类的地方必须能透明地使用其子类的对象。通俗点讲,只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。但是,反过来就不行了,有子类出现的地方,父类未必就能适应。
里氏替换原则为良好的继承定义了一个规范,一句简单的定义包含4层含义:
子类必须完全实现父类的方法。
- 在类中调用其他类时务必要使用父类或接口,如果不能使用父类或接口,则说明类的设计已经违背了LSP原则
- 如果子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生了”畸变”,则建议断开父子继承关系,采用依赖、聚集、组合等关系代替继承
子类可以有自己的个性
- 覆盖或实现父类的方法时输入参数可以被放大
- 覆写或实现父类的方法时输出结果可以被缩小
里式替换原则有一下两种含义:
- 里式替换原则是针对继承而言的,如果继承是为了实现代码重用,也就是为了共享方法,那么共享的父类方法就应该保持不变,不能被子类重新定义。子类只能通过新添加方法来扩展功能,父类和子类都可以实例化,而子类继承的方法和父类是一样的,父类调用方法的地方,子类也可以调用同一个继承得来的,逻辑和父类一致的方法,这时用子类对象将父类对象替换掉时,当然逻辑一致,相安无事。
- 如果继承的目的是为了多态,而多态的前提就是子类覆盖并重新定义父类的方法,为了符合LSP,我们应该将父类定义为抽象类,并定义抽象方法,让子类重新定义这些方法,当父类是抽象类时,父类就是不能实例化,所以也不存在可实例化的父类对象在程序里。也就不存在子类替换父类实例时逻辑不一致的可能。
不符合LSP的最常见的情况是,父类和子类都是可实例化的非抽象类,且父类的方法被子类重新定义,这一类的实现继承会造成父类和子类间的强耦合,也就是实际上并不相关的属性和方法牵强附会在一起,不利于程序扩展和维护。
总结一句话——就是尽量不要从可实例化的父类中继承,而是要使用基于抽象类和接口的继承。
MySQL加锁
MySQL加锁处理分析
MySQL InnoDB存储引擎,实现的是基于多版本的并发控制协议——MVCC(Multi-Version Concurrency Control)(注:与MVCC相对的,是基于锁的并发控制,Lock-Based Concurrency Control)。MVCC最大的好处:读不加锁,读写不冲突。在读多写少的OLTP应用中,读写不冲突是非常重要的,极大的增加了系统的并发性能。
在MVCC并发控制中,读操作可以分为两类:快照读(snapshot read)与当前读(current read)。快照读,读取的是记录的可见版本(有可能是历史版本),不用加锁。当前读,读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。