tiny spring 笔记

tiny spring ioc

看到这个项目的第一反应仅仅是好玩,所以看看它到底能不能让我搞懂 spring …

该项目中共包含以下 10 个标签。

1
2
3
4
5
6
7
8
9
10
step-1-container-register-and-get
step-2-abstract-beanfactory-and-do-bean-initilizing-in-it
step-3-inject-bean-with-property
step-4-config-beanfactory-with-xml
step-5-inject-bean-to-bean
step-6-invite-application-context
step-7-method-interceptor-by-jdk-dynamic-proxy
step-8-invite-pointcut-and-aspectj
step-9-auto-create-aop-proxy
step-10-invite-cglib-and-aopproxy-factory

step-1-container-register-and-get

从名字知道大概是说容器、注册机,从 Bean 开始,我们创建一个初始的 Bean 对象 ( BeanDefinition ):

1
2
3
4
5
6
7
8
9
10
11
public class BeanDefinition {
private Object bean;

public BeanDefinition(Object bean) {
this.bean = bean;
}

public Object getBean() {
return bean;
}
}

在 spring 中,我们需要一个 IoC 容器,我们创建一个工厂来保存 Bean ,这里命名 BeanFactory :

1
2
3
4
5
6
7
8
9
10
11
public class BeanFactory {
private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap();

public Object getBean(String name) {
return beanDefinitionMap.get(name).getBean();
}

public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
beanDefinitionMap.put(name, beanDefinition);
}
}

这是一个比较普通的工厂方法模式,我比较关注的反而是 ConcurrentHashMap ,这个对象在原子性上是线程安全的,但是如果是复合操作的话,可能导致线程不安全,当我们简单对方法加上 synchronized 关键字,这也会出现问题。

因为 synchronized 关键字其本质都是锁定某一个对象,修饰方法的时候,锁上的是调用这个方法的对象,即 this ;修饰代码块的时候,锁上的是代码块里的对象。

但是如果我们对 Map 对象加上锁的话, ConcurrentHashMap 对象的作用就大了。

PS: 最后特别补充的是, synchronized 关键字判断对象是否是它属于锁定的对象,本质上是通过 == 运算符来判断的。换句话说,上面的代码中,可以采用任何一个常量,或者每个线程都共享的变量,或者类的静态变量,来代替 Map 。只要该变量与 synchronized 锁定的目标变量相同(==),就可以使 synchronized 生效。

值得注意的是,这里的 BeanDefinition 的构造器中使用的是 Object 对象,这方便我们创建真正的 Bean 对象的时候不用在意它的类型,这里我们创建一个需要使用的 Service 对象:

1
2
3
4
5
public class HelloWorldService {
public void helloWorld(){
System.out.println("Hello World!");
}
}

在具体测试这个 Service 的时候我们创建一个响应的 Test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class BeanFactoryTest {
@Test
public void test() {
// 1.初始化beanfactory
BeanFactory beanFactory = new BeanFactory();

// 2.注入bean
BeanDefinition beanDefinition = new BeanDefinition(new HelloWorldService());
beanFactory.registerBeanDefinition("helloWorldService", beanDefinition);

// 3.获取bean
HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");
helloWorldService.helloWorld();
}
}

运行这个测试程序发生了什么呢?

首先初始化一个 Bean 工厂;初始化一个具体的 Bean ,这里面包装一个需要工作的具体 Service ;把这个 Service 放到工厂里,比如用一个 Map 来存放,使用的使用,可以直接通过 key 取出这个具体的 Bean ,取出具体的 Service ,然后执行具体的 Service 方法。

step-2-abstract-beanfactory-and-do-bean-initilizing-in-it

题目取名叫做抽象工厂和 Bean 的初始化,回忆一下,工厂方法模式是为了创造一个系列,而抽象工厂模式是为了创造多个系列,这也是这里分层出一个具体 Factory 原因。

首先我们还是先创造一个 Bean 的外壳:

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
29
30
31
32
33
34
35
36
37
38
39
40
public class BeanDefinition {
private Object bean;

private Class beanClass;

private String beanClassName;

public BeanDefinition() {
}

public void setBean(Object bean) {
this.bean = bean;
}

public Class getBeanClass() {
return beanClass;
}

public void setBeanClass(Class beanClass) {
this.beanClass = beanClass;
}

public String getBeanClassName() {
return beanClassName;
}

public void setBeanClassName(String beanClassName) {
this.beanClassName = beanClassName;
try {
this.beanClass = Class.forName(beanClassName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}

public Object getBean() {
return bean;
}

}

和之前的区别在于,这里增加了对内部 Bean 的实例化。

最外层是一个工厂接口 BeanFactory

1
2
3
4
5
public interface BeanFactory {
Object getBean(String name);

void registerBeanDefinition(String name, BeanDefinition beanDefinition);
}

然后是一个基础的实现 AbstractBeanFactory ,这里是基本方法的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public abstract class AbstractBeanFactory implements BeanFactory {
private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();

@Override
public Object getBean(String name) {
return beanDefinitionMap.get(name).getBean();
}

@Override
public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
Object bean = doCreateBean(beanDefinition);
beanDefinition.setBean(bean);
beanDefinitionMap.put(name, beanDefinition);
}

/**
* 初始化bean
* @param beanDefinition
* @return
*/
protected abstract Object doCreateBean(BeanDefinition beanDefinition);

}

这就是之前的工厂,它增加一个未实行的方法,用来具体产生 Bean ,最外层我们再包装一层:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class AutowireCapableBeanFactory extends AbstractBeanFactory {
@Override
protected Object doCreateBean(BeanDefinition beanDefinition) {
try {
Object bean = beanDefinition.getBeanClass().newInstance();
return bean;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}

测试的时候,创建一个具体的 Service

1
2
3
4
5
public class HelloWorldService {
public void helloWorld(){
System.out.println("Hello World!");
}
}

在具体测试的时候:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class BeanFactoryTest {
@Test
public void test() {
// 1.初始化beanfactory
BeanFactory beanFactory = new AutowireCapableBeanFactory();

// 2.注入bean
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setBeanClassName("cool.koon.step2.HelloWorldService");
beanFactory.registerBeanDefinition("helloWorldService", beanDefinition);

// 3.获取bean
HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");
helloWorldService.helloWorld();

}
}

和之前的差别在于,不再是我们手动创建具体的 Bean 对象,而是在外层对象中根据反射实例化对象。

step-3-inject-bean-with-property

这一章中是将属性注入到 Bean 中,此前我们仅仅是创建一个 Bean ,现在我们可以将具体的属性也实例化。

从属性对象开始创建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class PropertyValue {
private final String name;

private final Object value;

public PropertyValue(String name, Object value) {
this.name = name;
this.value = value;
}

public String getName() {
return name;
}

public Object getValue() {
return value;
}
}

以及属性对象的集合:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class PropertyValues {
private final List<PropertyValue> propertyValueList = new ArrayList();

public PropertyValues() {}

public void addPropertyValue(PropertyValue pv) {
//TODO:这里可以对于重复propertyName进行判断,直接用list没法做到
this.propertyValueList.add(pv);
}

public List<PropertyValue> getPropertyValues() {
return this.propertyValueList;
}

}

现在我们的 Bean 需要包含属性对象的集合:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class BeanDefinition {
private Object bean;

private Class beanClass;

private String beanClassName;

private PropertyValues propertyValues;

public BeanDefinition() {
}

public void setBean(Object bean) {
this.bean = bean;
}

public Class getBeanClass() {
return beanClass;
}

public void setBeanClass(Class beanClass) {
this.beanClass = beanClass;
}

public String getBeanClassName() {
return beanClassName;
}

public void setBeanClassName(String beanClassName) {
this.beanClassName = beanClassName;
try {
this.beanClass = Class.forName(beanClassName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}

public Object getBean() {
return bean;
}

public PropertyValues getPropertyValues() {
return propertyValues;
}

public void setPropertyValues(PropertyValues propertyValues) {
this.propertyValues = propertyValues;
}
}

Bean 工厂还是使用抽象工厂模式创建,首先是最外层的工厂接口:

1
2
3
4
5
public interface BeanFactory {
Object getBean(String name);

void registerBeanDefinition(String name, BeanDefinition beanDefinition) throws Exception;
}

然后是创建抽象类,完成一部分的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public abstract class AbstractBeanFactory implements BeanFactory {
private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();

@Override
public Object getBean(String name) {
return beanDefinitionMap.get(name).getBean();
}

@Override
public void registerBeanDefinition(String name, BeanDefinition beanDefinition) throws Exception {
Object bean = doCreateBean(beanDefinition);
beanDefinition.setBean(bean);
beanDefinitionMap.put(name, beanDefinition);
}

/**
* 初始化bean
* @param beanDefinition
* @return
*/
protected abstract Object doCreateBean(BeanDefinition beanDefinition) throws Exception;

}

最后是具体的工厂类,除了实现上面我们定义的 doCreateBean 方法,我们还需要指定属性对象的创建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class AutowireCapableBeanFactory extends AbstractBeanFactory {
@Override
protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception {
// 先创建一个对象
Object bean = createBeanInstance(beanDefinition);
// 然后加入其中的属性
applyPropertyValues(bean, beanDefinition);
return bean;
}

protected Object createBeanInstance(BeanDefinition beanDefinition) throws Exception {
// 之前这是直接写进 doCreateBean 里的
// 没有差别,只是写成了一个方法
return beanDefinition.getBeanClass().newInstance();
}

protected void applyPropertyValues(Object bean, BeanDefinition mbd) throws Exception {
for (PropertyValue propertyValue : mbd.getPropertyValues().getPropertyValues()) {
Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName());
declaredField.setAccessible(true);
declaredField.set(bean, propertyValue.getValue());
}
}
}

测试的时候先指定确定的 Service 对象:

1
2
3
4
5
6
7
8
9
10
11
public class HelloWorldService {
private String text;

public void helloWorld(){
System.out.println(text);
}

public void setText(String text) {
this.text = text;
}
}

然后我们开始测试我们现在的抽象工厂,这里我们还需要创建属性的集合:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class BeanFactoryTest {
@Test
public void test() throws Exception {
// 1.初始化beanfactory
BeanFactory beanFactory = new AutowireCapableBeanFactory();

// 2.bean定义
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setBeanClassName("cool.koon.step3.HelloWorldService");

// 3.设置属性
PropertyValues propertyValues = new PropertyValues();
propertyValues.addPropertyValue(new PropertyValue("text", "Hello World!"));
beanDefinition.setPropertyValues(propertyValues);

// 4.生成bean
beanFactory.registerBeanDefinition("helloWorldService", beanDefinition);

// 5.获取bean
HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");
helloWorldService.helloWorld();

}
}

总体基调还是一个抽象工厂。

这里使用 Field 来设置属性,实际中我们都会使用 setter 等方法。

Field 对象就代替了属性的地位,直接对它设置值就可以进行属性赋值。

step-4-config-beanfactory-with-xml

根据题目的意思我们开始使用 xml 来配置工厂,来看一看吧。

首先老样子,我们创建一个 Bean 的包装:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class BeanDefinition {
private Object bean;

private Class beanClass;

private String beanClassName;

private PropertyValues propertyValues = new PropertyValues();

public BeanDefinition() {
}

public void setBean(Object bean) {
this.bean = bean;
}

public Class getBeanClass() {
return beanClass;
}

public void setBeanClass(Class beanClass) {
this.beanClass = beanClass;
}

public String getBeanClassName() {
return beanClassName;
}

public void setBeanClassName(String beanClassName) {
this.beanClassName = beanClassName;
try {
this.beanClass = Class.forName(beanClassName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}

public Object getBean() {
return bean;
}

public PropertyValues getPropertyValues() {
return propertyValues;
}

public void setPropertyValues(PropertyValues propertyValues) {
this.propertyValues = propertyValues;
}
}

同时还需要创建属性类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class PropertyValue {
private final String name;

private final Object value;

public PropertyValue(String name, Object value) {
this.name = name;
this.value = value;
}

public String getName() {
return name;
}

public Object getValue() {
return value;
}
}

还有属性列表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class PropertyValues {
private final List<PropertyValue> propertyValueList = new ArrayList<PropertyValue>();

public PropertyValues() {
}

public void addPropertyValue(PropertyValue pv) {
//TODO:这里可以对于重复propertyName进行判断,直接用list没法做到
this.propertyValueList.add(pv);
}

public List<PropertyValue> getPropertyValues() {
return this.propertyValueList;
}

}

现在我们来到 io 包,首先创建一个 Resource 接口:

1
2
3
public interface Resource {
InputStream getInputStream() throws IOException;
}

对它继承:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class UrlResource implements Resource {
private final URL url;

public UrlResource(URL url) {
this.url = url;
}

@Override
public InputStream getInputStream() throws IOException {
URLConnection urlConnection = url.openConnection();
urlConnection.connect();
return urlConnection.getInputStream();
}
}

比较直接,开启一个 url ,连接后获得一个字节流。

再来一个类来获得这个 UrlResource

1
2
3
4
5
6
public class ResourceLoader {
public Resource getResource(String location){
URL resource = this.getClass().getClassLoader().getResource(location);
return new UrlResource(resource);
}
}

现在使用抽象工厂的形式,我们创建一个接口,以及一个部分实现的阅读器,最后是一个 xml 的读取器。首先是一个 Bean 接口:

1
2
3
public interface BeanDefinitionReader {
void loadBeanDefinitions(String location) throws Exception;
}

然后是一个抽象类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader {
private Map<String,BeanDefinition> registry;

private ResourceLoader resourceLoader;

protected AbstractBeanDefinitionReader(ResourceLoader resourceLoader) {
this.registry = new HashMap<String, BeanDefinition>();
this.resourceLoader = resourceLoader;
}

public Map<String, BeanDefinition> getRegistry() {
return registry;
}

public ResourceLoader getResourceLoader() {
return resourceLoader;
}
}

最后 xml 包里实现一个 XmlBeanDefinitionReader

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
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
public XmlBeanDefinitionReader(ResourceLoader resourceLoader) {
super(resourceLoader);
}

@Override
public void loadBeanDefinitions(String location) throws Exception {
InputStream inputStream = getResourceLoader().getResource(location).getInputStream();
doLoadBeanDefinitions(inputStream);
}

protected void doLoadBeanDefinitions(InputStream inputStream) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Document doc = docBuilder.parse(inputStream);
// 解析bean
registerBeanDefinitions(doc);
inputStream.close();
}

public void registerBeanDefinitions(Document doc) {
// 从根节点开始解析
Element root = doc.getDocumentElement();
parseBeanDefinitions(root);
}
}

我们不需要太了解它是怎么解析这个 xml 的,只要知道它达到的效果是从中取出属性并赋值。

下面是工厂的搭建,从工厂的接口开始:

1
2
3
4
5
public interface BeanFactory {
Object getBean(String name);

void registerBeanDefinition(String name, BeanDefinition beanDefinition) throws Exception;
}

我们创建一个抽象类来部分实现这个工厂:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public abstract class AbstractBeanFactory implements BeanFactory {
private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();

@Override
public Object getBean(String name) {
return beanDefinitionMap.get(name).getBean();
}

@Override
public void registerBeanDefinition(String name, BeanDefinition beanDefinition) throws Exception {
Object bean = doCreateBean(beanDefinition);
beanDefinition.setBean(bean);
beanDefinitionMap.put(name, beanDefinition);
}

/**
* 初始化bean
* @param beanDefinition
* @return
*/
protected abstract Object doCreateBean(BeanDefinition beanDefinition) throws Exception;

}

老样子,最后创建一个具体的工厂类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class AutowireCapableBeanFactory extends AbstractBeanFactory {
@Override
protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception {
Object bean = createBeanInstance(beanDefinition);
applyPropertyValues(bean, beanDefinition);
return bean;
}

protected Object createBeanInstance(BeanDefinition beanDefinition) throws Exception {
return beanDefinition.getBeanClass().newInstance();
}

protected void applyPropertyValues(Object bean, BeanDefinition mbd) throws Exception {
for (PropertyValue propertyValue : mbd.getPropertyValues().getPropertyValues()) {
Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName());
declaredField.setAccessible(true);
declaredField.set(bean, propertyValue.getValue());
}
}
}

下面开始实现测试类。

老样子创建一个 Service

1
2
3
4
5
6
7
8
9
10
11
public class HelloWorldService {
private String text;

public void helloWorld(){
System.out.println(text);
}

public void setText(String text) {
this.text = text;
}
}

现在我们创建一个测试方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class BeanFactoryTest {
@Test
public void test() throws Exception {
// 1.读取配置
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());
xmlBeanDefinitionReader.loadBeanDefinitions("tinyioc.xml");

// 2.初始化BeanFactory并注册bean
BeanFactory beanFactory = new AutowireCapableBeanFactory();
for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {
beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
}

// 3.获取bean
HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");
helloWorldService.helloWorld();

}
}

不要以为这里用了两个抽象工厂,这个方式就变复杂了,仅仅看似复杂,实际上非常普通,仅仅是从手动输入各个属性到现在从 xml 中读取属性。

step-5-inject-bean-to-bean

这一章节使用的是指在 Bean 中注入 Bean ,我们来看看它的实现。

这里,我们连接上一个项目,在其上直接进行修改。

首先,我们需要定义一个类作为 Bean 的注入:

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
public class BeanReference {
private String name;

private Object bean;

public BeanReference(String name) {
this.name = name;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Object getBean() {
return bean;
}

public void setBean(Object bean) {
this.bean = bean;
}
}

它作为另外一个 Bean 被注入到一个 Bean 中,具体操作在 XmlBeanDefinitionReader 中:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
public XmlBeanDefinitionReader(ResourceLoader resourceLoader) {
super(resourceLoader);
}

@Override
public void loadBeanDefinitions(String location) throws Exception {
InputStream inputStream = getResourceLoader().getResource(location).getInputStream();
doLoadBeanDefinitions(inputStream);
}

protected void doLoadBeanDefinitions(InputStream inputStream) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Document doc = docBuilder.parse(inputStream);
// 解析bean
registerBeanDefinitions(doc);
inputStream.close();
}

public void registerBeanDefinitions(Document doc) {
// 从根节点开始解析
Element root = doc.getDocumentElement();
parseBeanDefinitions(root);
}

protected void parseBeanDefinitions(Element root) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
processBeanDefinition(ele);
}
}
}

protected void processBeanDefinition(Element ele) {
String name = ele.getAttribute("name");
String className = ele.getAttribute("class");
BeanDefinition beanDefinition = new BeanDefinition();
processProperty(ele,beanDefinition);
beanDefinition.setBeanClassName(className);
getRegistry().put(name, beanDefinition);
}

private void processProperty(Element ele,BeanDefinition beanDefinition) {
NodeList propertyNode = ele.getElementsByTagName("property");
for (int i = 0; i < propertyNode.getLength(); i++) {
Node node = propertyNode.item(i);
if (node instanceof Element) {
Element propertyEle = (Element) node;
String name = propertyEle.getAttribute("name");
String value = propertyEle.getAttribute("value");
// step5 add
if (value != null && value.length() > 0) {
beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, value));
} else {
String ref = propertyEle.getAttribute("ref");
if (ref == null || ref.length() == 0) {
throw new IllegalArgumentException("Configuration problem: <property> element for property '" + name + "' must specify a ref or value");
}
BeanReference beanReference = new BeanReference(ref);
beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, beanReference));
}
// step5 add end
}
}
}

}

这里是将 xml 的内容读取,在 Bean 工厂中,我们具体使用:

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
public class AutowireCapableBeanFactory extends AbstractBeanFactory {
@Override
protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception {
Object bean = createBeanInstance(beanDefinition);
applyPropertyValues(bean, beanDefinition);
return bean;
}

protected Object createBeanInstance(BeanDefinition beanDefinition) throws Exception {
return beanDefinition.getBeanClass().newInstance();
}

protected void applyPropertyValues(Object bean, BeanDefinition mbd) throws Exception {
for (PropertyValue propertyValue : mbd.getPropertyValues().getPropertyValues()) {
Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName());
declaredField.setAccessible(true);
// step5 add
Object value = propertyValue.getValue();
if (value instanceof BeanReference) {
BeanReference beanReference = (BeanReference) value;
value = getBean(beanReference.getName());
}
// step5 add end
declaredField.set(bean, value);
}
}
}

这是主要修改的地方,另外因为现在我们的 Bean 包装中不止一种类了,所以还有一些小细节需要修改,比如每次手动确认 Bean 里的内容,如果 Bean 没有创建,我们需要再创建。

我们现在在 AbstractBeanFactory 中创建一个方法 getBean 用来实例化 Bean

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
29
30
31
32
33
34
35
36
37
38
39
40
public abstract class AbstractBeanFactory implements BeanFactory {
private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();

private final List<String> beanDefinitionNames = new ArrayList<String>();

@Override
public Object getBean(String name) throws Exception {
// 现在我们的 BeanFactory 不仅仅包装一个 Service 可以包装多种
BeanDefinition beanDefinition = beanDefinitionMap.get(name);
if (beanDefinition == null) {
throw new IllegalArgumentException("No bean named " + name + " is defined");
}
Object bean = beanDefinition.getBean();
if (bean == null) {
bean = doCreateBean(beanDefinition);
}
return bean;
}

@Override
public void registerBeanDefinition(String name, BeanDefinition beanDefinition) throws Exception {
beanDefinitionMap.put(name, beanDefinition);
beanDefinitionNames.add(name);
}

public void preInstantiateSingletons() throws Exception {
for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext();) {
String beanName = (String) it.next();
getBean(beanName);
}
}

/**
* 初始化bean
*
* @param beanDefinition
* @return
*/
protected abstract Object doCreateBean(BeanDefinition beanDefinition) throws Exception;
}

最后我们进入测试:

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
29
30
31
32
33
34
35
36
37
38
39
public class BeanFactoryTest {
@Test
public void testLazy() throws Exception {
// 1.读取配置
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());
xmlBeanDefinitionReader.loadBeanDefinitions("tinyioc.xml");

// 2.初始化BeanFactory并注册bean
AbstractBeanFactory beanFactory = new AutowireCapableBeanFactory();
for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {
// 现在我们不在注册的地方进行实例化,而是在 getBean 方法里实例化,完成懒加载
beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
}

// 3.获取bean
HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");
helloWorldService.helloWorld();
}

@Test
public void testPreInstantiate() throws Exception {
// 1.读取配置
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());
xmlBeanDefinitionReader.loadBeanDefinitions("tinyioc.xml");

// 2.初始化BeanFactory并注册bean
AbstractBeanFactory beanFactory = new AutowireCapableBeanFactory();
for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {
beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
}

// 3.初始化bean
beanFactory.preInstantiateSingletons();

// 4.获取bean
HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");
helloWorldService.helloWorld();
}
}

这里的 OutputService 是另外一个 Bean 也是被注入的 Bean ,实现的时候需要注意哪个 Bean 属于哪个即可。

step-6-invite-application-context

终于来到了 IoC 实现的最后一章,这里 ApplicationContext 终于登场了。

我们把上面这些 xml 读取到属性插入的代码进行封装,这些组成代码现在是 Application 的部分,它也采用一个抽象工厂模式,分别是一个接口:

1
public interface ApplicationContext extends BeanFactory {}

这个接口继承自抽象工厂的接口,它这样写也是为了更好地传入参数,然后我们对它进行部分实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public abstract class AbstractApplicationContext implements ApplicationContext {
protected AbstractBeanFactory beanFactory;

public AbstractApplicationContext(AbstractBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}

@Override
public Object getBean(String name) throws Exception {
return beanFactory.getBean(name);
}

public void refresh() throws Exception {

}
}

然后是一个具体的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class ClassPathXmlApplicationContext extends AbstractApplicationContext {
private String configLocation;

public ClassPathXmlApplicationContext(String configLocation) throws Exception {
this(configLocation, new AutowireCapableBeanFactory());
}

public ClassPathXmlApplicationContext(String configLocation, AbstractBeanFactory beanFactory) throws Exception {
super(beanFactory);
this.configLocation = configLocation;
refresh();
}

@Override
public void refresh() throws Exception {
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());
xmlBeanDefinitionReader.loadBeanDefinitions(configLocation);
for (Map.Entry<String, BeanDefinition> beanDefinitionEntry: xmlBeanDefinitionReader.getRegistry().entrySet()) {
beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
}
}

}

我们在 refresh 方法中进行具体的实现,这里我们进行配置的读取,属性的注册等操作,等于在复现之前的测试方法。

现在测试方法就极端简单了:

1
2
3
4
5
6
7
8
public class ApplicationContextTest {
@Test
public void test() throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("tinyioc.xml");
HelloWorldService helloWorldService = (HelloWorldService) applicationContext.getBean("helloWorldService");
helloWorldService.helloWorld();
}
}

一个简单的 IoC 通过几个简单的抽象工厂就完成了。

tiny spring aop

step-7-method-interceptor-by-jdk-dynamic-proxy

这么快我们 IoC 就看完了,非常有意思,下面开始了 AOP 的学习,我们知道在 AOP 中分为配置和织入两部分,当然还有一部分是将 AOP 整合到整个容器的生命周期中。

三个点,一个被代理对象,一个拦截器,一个代理者,被代理对象被包装成一个 AdvisedSupport 其中包含我们具体的拦截器:

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
// 包含拦截器的具体对象
public class AdvisedSupport {
private TargetSource targetSource;

// 对应拦截器
private MethodInterceptor methodInterceptor;

public TargetSource getTargetSource() {
return targetSource;
}

// 拦截器里包裹了具体的对象
public void setTargetSource(TargetSource targetSource) {
this.targetSource = targetSource;
}

public MethodInterceptor getMethodInterceptor() {
return methodInterceptor;
}

public void setMethodInterceptor(MethodInterceptor methodInterceptor) {
this.methodInterceptor = methodInterceptor;
}

}

然后我们实现一个具体拦截器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class TimerInterceptor implements MethodInterceptor {
// 拦截后调用方法
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
long time = System.nanoTime();
System.out.println("Invocation of Method " + methodInvocation.getMethod().getName() + " start!");

Object proceed = methodInvocation.proceed();

System.out.println("Invocation of Method " + methodInvocation.getMethod().getName() + " end! takes " + (System.nanoTime() - time) + " nanoseconds");

return proceed;
}
}

紧接着,是一个代理者:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
private AdvisedSupport advised;

public JdkDynamicAopProxy(AdvisedSupport advised) {
this.advised = advised;
}

@Override
public Object getProxy() {
return Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { advised.getTargetSource().getTargetClass() }, this);
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 拦截器进行拦截
MethodInterceptor methodInterceptor = advised.getMethodInterceptor();
// 调用器开始调用方法
// 从这里调用具体的拦截器方法
return methodInterceptor.invoke(new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(), method, args));
}
}

还是比较好理解的一个 AOP 小例子。

step-8-invite-pointcut-and-aspectj

来到第 8 章,我们开始考虑一个问题,那就是什么时候进行 AOP ?对于这个问题,我们叫做 Pointcut ,在 SpringPointcut 中包含两个角色: ClassFilterMethodMatcher ,分别是对类和方法做匹配,比较通用的方式是使用 AspectJ 表达式,但是为此我们需要学习一门语言又得不偿失,我们怎么做呢?

首先从两个接口开始,分别用来匹配类和方法,多实现在一个类中:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
public class AspectJExpressionPointcut implements Pointcut, ClassFilter, MethodMatcher {
private PointcutParser pointcutParser;

private String expression;

private PointcutExpression pointcutExpression;

private static final Set<PointcutPrimitive> DEFAULT_SUPPORTED_PRIMITIVES = new HashSet<PointcutPrimitive>();

static {
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.ARGS);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.REFERENCE);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.THIS);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.TARGET);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.WITHIN);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ANNOTATION);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_WITHIN);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ARGS);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_TARGET);
}

public AspectJExpressionPointcut() {
this(DEFAULT_SUPPORTED_PRIMITIVES);
}

public AspectJExpressionPointcut(Set<PointcutPrimitive> supportedPrimitives) {
pointcutParser = PointcutParser
.getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(supportedPrimitives);
}

protected void checkReadyToMatch() {
if (pointcutExpression == null) {
pointcutExpression = buildPointcutExpression();
}
}

private PointcutExpression buildPointcutExpression() {
return pointcutParser.parsePointcutExpression(expression);
}

public void setExpression(String expression) {
this.expression = expression;
}

@Override
public ClassFilter getClassFilter() {
return this;
}

@Override
public MethodMatcher getMethodMatcher() {
return this;
}

@Override
public boolean matches(Class targetClass) {
checkReadyToMatch();
return pointcutExpression.couldMatchJoinPointsInType(targetClass);
}

@Override
public boolean matches(Method method, Class targetClass) {
checkReadyToMatch();
ShadowMatch shadowMatch = pointcutExpression.matchesMethodExecution(method);
if (shadowMatch.alwaysMatches()) {
return true;
} else if (shadowMatch.neverMatches()) {
return false;
}
// TODO:其他情况不判断了!见org.springframework.aop.aspectj.RuntimeTestWalker
return false;
}
}

在测试类中用匹配的方式来切:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class AspectJExpressPointcutTest {
// 类的切入
@Test
public void testClassFilter() throws Exception {
String expression = "execution(* cool.koon.step4to6.*.*(..))";
AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut();
aspectJExpressionPointcut.setExpression(expression);
boolean matches = aspectJExpressionPointcut.getClassFilter().matches(HelloWorldService.class);
Assert.assertTrue(matches);
}

// 方法的切入
@Test
public void testMethodInterceptor() throws Exception {
String expression = "execution(* cool.koon.step4to6.*.*(..))";
AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut();
aspectJExpressionPointcut.setExpression(expression);
boolean matches = aspectJExpressionPointcut.getMethodMatcher().matches(HelloWorldServiceImpl.class.getDeclaredMethod("helloWorld"),HelloWorldServiceImpl.class);
Assert.assertTrue(matches);
}
}

简单讲,这一章给我们一个便捷切面的方式,使用正则,指定类或者方法来进行 AOP

step-9-auto-create-aop-proxy

这里,我们已经拥有了 Pointcut 一个 AOP 已经完成,但是我们还没有结合到 Spring 中,现在我们给出一个答案 BeanPostProcessor ,它是 BeanFactory 提供的,在 Bean 继续初始化的过程中进行扩展。

核心点在于 AspectJAwareAdvisorAutoProxyCreator 这个类的 Spring 初始化的时候,会优先找到它们,并且在 Bean 初始化的过程中,调用这个接口,从而实现对 Spring 工厂的无侵入的扩展。

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
29
30
31
32
33
34
35
36
37
38
39
public class AspectJAwareAdvisorAutoProxyCreator implements BeanPostProcessor, BeanFactoryAware {

private AbstractBeanFactory beanFactory;

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception {
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
if (bean instanceof AspectJExpressionPointcutAdvisor) {
return bean;
}
if (bean instanceof MethodInterceptor) {
return bean;
}
List<AspectJExpressionPointcutAdvisor> advisors = beanFactory
.getBeansForType(AspectJExpressionPointcutAdvisor.class);
for (AspectJExpressionPointcutAdvisor advisor : advisors) {
if (advisor.getPointcut().getClassFilter().matches(bean.getClass())) {
AdvisedSupport advisedSupport = new AdvisedSupport();
advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());

TargetSource targetSource = new TargetSource(bean, bean.getClass().getInterfaces());
advisedSupport.setTargetSource(targetSource);

return new JdkDynamicAopProxy(advisedSupport).getProxy();
}
}
return bean;
}

@Override
public void setBeanFactory(BeanFactory beanFactory) throws Exception {
this.beanFactory = (AbstractBeanFactory) beanFactory;
}
}

有一种说法是 —— BeanPostProcessor :在 postProcessorAfterInitialization 方法中,使用动态代理的方式,返回一个对象的代理对象。解决了在 IoC 容器的何处植入 AOP 的问题。

BeanFactoryAware :这个接口提供了对 BeanFactory 的感知,这样,尽管它是容器中的一个 Bean ,却可以获取容器的引用,进而获取容器中所有的切点对象,决定对哪些对象的哪些方法进行代理。解决了为哪些对象提供 AOP 的植入的问题。

但是只能说有一定的道理。

step-10-invite-cglib-and-aopproxy-factory

最后了,我们现在只能对接口进行代理,对于类却无能为力,这里我们需要一些字节码的操作,使用 CGLib ,或者应该说是 jvm 动态擦除的历史遗留问题。


这个项目像是介绍性质地给我们看了看 IoCAOP 的部分妙用,果然受益良多,最后实在不想重复劳作了,把 step4 到 step10 写到了一起。