Reentrantlock源码学习

前言

在上文 AbstractQueuedSyncchronizer学习 中,对AQS进行了相应的学习,知道AQS是Java并发包的一个同步基础机制。该接口有几个常用的子类,本文章主要对其中最常用的子类ReentrantLock类进行学习,其他子类后续再讲。

ReentrantLock源码学习

内部数据结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//可重入独占锁,实现了Lock接口
public class ReentrantLock implements Lock, java.io.Serializable {

private final Sync sync;

//锁的同步控制基础。子类分为公平锁和非公平锁,使用AQS中的state代表持有的锁数
abstract static class Sync extends AbstractQueuedSynchronizer {}

//非公平锁实现
static final class NonfairSync extends Sync {}

//公平锁实现
static final class FairSync extends Sync {}
}

由类实现可知,该类持有一个Sync对象,提供所有的同步机制。

Read More

AbstractQueuedSyncchronizer源码学习

前言

在日常编程中,我们经常使用到的锁:ReentrantLockCountDownLatchReentrantReadWriteLock等,他们的内部都一个名为Sync的静态抽象内部类,该类都实现了同一个名为AbstractQueuedSyncchronizer的接口。该接口为Java并发包提供的一个同步基础机制。

1
2
3
abstract static class Sync extends AbstractQueuedSynchronizer{
....
}

AbstractQueuedSynchronizer在JDK1.8中还有如下图所示的众多子类:

为了方便,通常使用AQS代替AbstractQueuedSynchronizer。

AQS源码解析

Read More

JdbcTemplate学习

JdbcTemplate是spring对jdbc的封装,提供了操作数据库的模板。

类图

JdbcTemplate类图
类图分析:

  • JdbcOperations接口:定义了JdbcTemplate可以使用的JDBC操作集合。从查询到更新都进行了声明。
  • JdbcAccessor抽象类:主要为子类提供了一些公用属性声明。
    • DataSource:Spring数据访问层对数据库资源的访问,全都建立在javax.sql.DataSource标准接口之上。DataSource可以看做JDBC的连接工厂。
    • SQLExceptionTranslator:负责Spring对SQLException的转译。实现了SQLException到其统一的数据访问异常体系的转换。

Read More

Mysql修改表主键

原来有一个字段id,为自增,主键,索引。现在要新增一个字段s_id为自增,主键,索引.同时把原来的主字段改成普通字段,默认值为0.

1
2
3
4
5
6
7
8
Alter table xxx change s_id s_id int(10) NOT NULL DEFAULT 0;  //去除原来字段的自增属性,不然无法删除这个主键
Alter table xxx drop primary key; //删除主键
drop index s_id on xxx; //删除索引,注意这个表原来就只有一个索引

Alter table xxx add column id int(10) NOT NULL DEFAULT 0 FIRST; //新建一个字段,无法直接新建自增字段,因为不是主键
Alter table xxx add primary key(id); //改为主键,然后才能用自增字段
Alter table xxx change id id int(10) NOT NULL AUTO_INCREMENT; //改成自增字段
Alter table xxx add UNIQUE INDEX `id` (`id`) USING BTREE ; //把这个字段改成索引

Spring AOP源码学习

AOP基础知识

AOP(Aspect-Oriented Programming):面向切面编程。OOP(Object-Oriented Programming)面向对象的编程。其实AOP是对OOP的一种补充。OOP面向的是纵向编程,继承,封装,多态是其三大特性,而AOP是面向横向编程。在OOP中,模块化的关键是类(class),而在AOP中,模块化的关键是切面(aspect)

AOP概念术语
  • 切面(Aspect):一个关注点的模块化,这个关注点可能会横切多个对象。
  • 连接点(Joinpoint):在程序执行过程中某个特定的点。在Spring AOP中,一个连接点总是表示一个方法的执行
  • 通知(Advice):在切面的某个特定的连接点上执行的动作。包括:around, before, after等不同类型的通知。
  • 切入点(Pointcut):匹配连接点的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行。
  • 引入(Introduction):用来给一个类型说明额外的方法或者属性。
  • 目标对象(Target Object):被一个或者多个切面所通知的对象。既然Spring AOP是通过运行时代理实现的,这个对象永远是一个被代理(proxied)对象。
  • AOP代理(AOP Proxy):AOP框架创建的对象,用来实现切面契约(例如通知方法执行等等)。在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理
  • 织入(Weaving):把切面连接到其他的应用程序类型或者对象上,并创建一个被通知的对象。

Read More

Bean加载流程之配置文件占位符替换

在讲解properties文件中${…}替换之前,首先介绍一下BeanFactoryPostProcessor类。

BeanFactoryPostProcessor讲解

BeanFactoryPostProcessorBeanPostProcessor,这两个接口,都是spring初始化bean时对外暴露的扩展点。两个接口名称看起来很相似,但作用及使用场景却不同。

  • BeanFactoryPostProcessor 接口

    源码

    1
    2
    3
    public interface BeanFactoryPostProcessor {
    void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException;
    }

    此接口只有一个方法,接受ConfigurableListableBeanFactory参数。实现该接口,可以在spring的bean创建之前,修改bean的定义属性。即读取bean的配置元数据,并可以根据需要进行修改(直白点,就是修改bean的BeanDefinition中相应信息)。由Bean加载流程梳理之BeanDefinitions加载 可知,在获取BeanFactory时,即接口中唯一方法的参数,Spring框架会将加载的BeanDefinitions放进BeanFactory,因此该接口中的方法可以获取所有bean的BeanDefinition。然后进行相应修改。
    BeanFactoryPostProcessor是在spring容器加载了bean的定义文件之后,在bean实例化之前执行的

Read More

Bean加载流程之BeanWrapper构建

另一篇 Bean加载流程梳理之BeanDefinitions加载,分析了Spring上下文加载的代码入口及BeanDefinitions加载流程的梳理。在AbstractApplicationContext的refresh方法中,首先获取了ConfigurableListableBeanFactory类型的beanFactory,然后对beanFactory进行了一系列的设置及其他资源的设置。一切准备就绪后,使用了finishBeanFactoryInitialization方法完成了对于所有非懒加载的Bean的初始化。

finishBeanFactoryInitialization源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
//设置beanFactory
if(beanFactory.containsBean("conversionService") && beanFactory.isTypeMatch("conversionService", ConversionService.class)) {
beanFactory.setConversionService((ConversionService)beanFactory.getBean("conversionService", ConversionService.class));
}

if(!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
public String resolveStringValue(String strVal) {
return AbstractApplicationContext.this.getEnvironment().resolvePlaceholders(strVal);
}
});
}

String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
String[] var3 = weaverAwareNames;
int var4 = weaverAwareNames.length;

for(int var5 = 0; var5 < var4; ++var5) {
String weaverAwareName = var3[var5];
this.getBean(weaverAwareName);
}

beanFactory.setTempClassLoader((ClassLoader)null);
beanFactory.freezeConfiguration();
//调用了DefaultListableBeanFactory的preInstantiateSingletons方法
beanFactory.preInstantiateSingletons();
}

功能讲解:

Read More

Bean加载流程梳理之BeanDefinitions加载

BeanDefinitions加载是发生在容器获取BeanFactory时,具体是在刷新BeanFactory后进行BeanDefinitions的加载。BeanDefinitions成功加载后,可供后续获取bean对象做准备。

Bean加载源码入口

Spring的重要特征之一是IOC(Inversion of Control),即:控制反转。IOC技术促进了松耦合。Spring提供了两种IOC容器类型:BeanFactory和ApplicationContext,在类结构上,ApplicationContext是继承自BeanFactory的。下面讲解ApplicationContext容器。
下面有很简单的一段代码可以作为Spring中Bean加载的入口:

1
2
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
context.getBean("beanName");

ClassPathXmlApplicationContext用于加载CLASSPATH下的Spring配置文件。由示例可知,context.getBean("beanName");即可获取到Bean的实例,那么必然ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");就已经完成了对所有Bean实例的加载,因此可以通过ClassPathXmlApplicationContext作为Bean加载源码入口。

类图:

Read More

Fork me on GitHub