04 | 增强IoC容器:如何让我们的Spring支持注解?
大家好,我是郭屹。
在上一节课中,我们通过一系列操作使XML配置文件生效,并实现了Spring中的Bean构造器注入与setter注入。我们还引入了“早期毛胚Bean”的概念来解决循环依赖问题,并为容器增加了Spring中的核心方法refresh()
,作为整个容器启动的入口。现在我们的容器已经有了基本的模型,接下来我们将让它变得更强大,从种子成长为一株幼苗。
在这节课中,我们将实现一个增强版的IoC容器,支持通过注解的方式进行依赖注入。注解是编程中常用的技术,它可以减少配置文件的内容,便于管理,同时提高开发效率。因此,我们将实现@Autowired
注解,并使用这种方式进行依赖注入。
目录结构
我们手写MiniSpring的目的是为了更好地学习Spring。因此,我们会时不时地回头整理整个项目的目录结构,使其与Spring保持一致。
现在,我们参考Spring框架的结构,调整我们的项目结构,在beans
目录下新增factory
目录,factory
目录中则新增xml
、support
、config
与annotation
四个目录。
1
2
3
4
5
6
|
├── beans
│ └── factory
│ ├── xml
│ └── support
│ └── config
│ └── annotation
|
接下来将之前所写的类文件移动至新增目录下,你可以看一下移动后的结构。
1
2
3
4
5
6
7
8
9
10
|
factory —— BeanFactory.java
factory.xml —— XmlBeanDefinitionReader.java
factory.support —— DefaultSingletonBeanRegistry.java、
BeanDefinitionRegistry.java、SimpleBeanFactory.java
factory.config —— SingletonBeanRegistry.java、ConstructorArgumentValues.java、
ConstructorArgumentValue.java、BeanDefinition.java
// 注:
// ConstructorArgumentValues由ArgumentValues改名而来
// ConstructorArgumentValue由ArgumentValue改名而来
|
项目结构与Spring框架对比
在熟悉了本项目的结构之后,你可能会注意到它与Spring框架的结构非常相似。这种相似性不仅体现在目录结构上,还包括文件名、类中的主要方法名和属性名。这样的设计旨在帮助你在未来的学习过程中更加轻松地掌握Spring框架。
依赖注入与Autowired注解
如果你有使用Spring框架的经验,那么对@Autowired
注解应该不会陌生。这是一种常用的依赖注入方式,通过在需要注入的对象上添加@Autowired
注解来实现。以下是一个简单的示例,展示了如何使用@Autowired
注解进行依赖注入。
1
2
3
4
|
public class Test {
@Autowired
private TestAutowired testAutowired;
}
|
在Spring框架中,注解提供了一种更为简洁的依赖注入方式,避免了在XML配置文件中显式使用ref属性指定依赖对象。然而,注解本身并不能自我解释,需要一个程序去解释它。以下是解释注解的步骤和时机:
1. 注解解释时机
注解是作用在实例变量上的,因此必须在对象创建后才能解释注解。在Spring框架中,Bean的创建过程被封装在refresh()方法中。Bean实例化之后,需要进行初始化工作,而refresh()方法中预留了三个阶段用于Bean的初始化处理:
2. BeanPostProcessor的作用
为了在这些阶段解释注解,我们可以使用BeanPostProcessor。BeanPostProcessor有两个方法,分别用于处理Bean初始化之前和之后:
1
2
3
4
|
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws
BeansException;
}
|
- Bean初始化之后
1
2
3
4
|
public interface BeanPostProcessor {
Object postProcessAfterInitialization(Object bean, String beanName) throws
BeansException;
}
|
接下来我们定义Autowired注解,很简单,你可以参考一下。
1
2
3
4
|
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
}
|
在Spring框架中,@Autowired
注解用于自动装配依赖。当我们想要实现@Autowired
这个功能时,可以考虑通过反射机制来获取所有标记了@Autowired
注解的成员变量,并将这些成员变量初始化为相应的Bean对象,随后进行属性注入。
为了达到这样的目的,我们可以结合之前提到的BeanPostProcessor
接口来创建一个处理类AutowiredAnnotationBeanPostProcessor
。该处理类将在Bean实例化之后但在初始化方法调用之前运行,从而确保在合适的时候执行自动装配逻辑。
以下是使用BeanPostProcessor
接口定义AutowiredAnnotationBeanPostProcessor
的一个概览:
- 实现
BeanPostProcessor
接口。
- 在
postProcessBeforeInitialization
或postProcessAfterInitialization
方法中(根据需要选择),利用反射技术扫描被创建的Bean对象的所有字段。
- 检查每个字段是否带有
@Autowired
注解。
- 对于带有
@Autowired
注解的字段,找到合适的Bean并将其注入到当前字段中。
- 返回处理后的Bean对象。
这样,我们就可以通过自定义的
BeanPostProcessor
实现类似于Spring框架内部对@Autowired
注解的支持了。
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
|
public class AutowiredAnnotationBeanPostProcessor implements BeanPostProcessor {
private AutowireCapableBeanFactory beanFactory;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
Object result = bean;
Class<?> clazz = bean.getClass();
Field[] fields = clazz.getDeclaredFields();
if(fields!=null){
//对每一个属性进行判断,如果带有@Autowired注解则进行处理
for(Field field : fields){
boolean isAutowired =
field.isAnnotationPresent(Autowired.class);
if(isAutowired){
//根据属性名查找同名的bean
String fieldName = field.getName();
Object autowiredObj =
this.getBeanFactory().getBean(fieldName);
//设置属性值,完成注入
try {
field.setAccessible(true);
field.set(bean, autowiredObj);
System.out.println("autowire " + fieldName + " for bean
" + beanName);
}
}
}
}
return result;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
return null;
}
public AutowireCapableBeanFactory getBeanFactory() {
return beanFactory;
}
public void setBeanFactory(AutowireCapableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
}
|
其实,核心代码就只有几行。
1
2
3
4
5
6
|
boolean isAutowired = field.isAnnotationPresent(Autowired.class);
if(isAutowired){
String fieldName = field.getName();
Object autowiredObj = this.getBeanFactory().getBean(fieldName);
field.setAccessible(true);
field.set(bean, autowiredObj);
|
判断类里面的每一个属性是不是带有Autowired注解,如果有,就根据属性名获取Bean。从这里我们可以看出,属性名字很关键,我们就是靠它来获取和创建的Bean。有了Bean之后,我们通过反射设置属性值,完成依赖注入。
新的BeanFactory
在这里我们引入了AutowireCapableBeanFactory,这个BeanFactory就是专为Autowired注入的Bean准备的。
在此之前我们已经定义了BeanFactory接口,以及一个SimpleBeanFactory的实现类。现在我们又需要引入另外一个BeanFactory—— AutowireCapableBeanFactory。基于代码复用、解耦的原则,我们可以对通用部分代码进行抽象,抽象出一个AbstractBeanFactory类。
目前,我们可以把refresh()、getBean()、registerBeanDefinition()等方法提取到抽象类,因为我们提供了默认实现,确保这些方法即使不再被其他BeanFactory实现也能正常生效。改动比较大,所以这里我贴出完整的类代码,下面就是AbstractBeanFactory的完整实现。
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
|
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry
implements BeanFactory, BeanDefinitionRegistry {
private Map<String, BeanDefinition> beanDefinitionMap = new
ConcurrentHashMap<>(256);
private List<String> beanDefinitionNames = new ArrayList<>();
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
public AbstractBeanFactory() {
}
public void refresh() {
for (String beanName : beanDefinitionNames) {
try {
getBean(beanName);
}
}
}
@Override
public Object getBean(String beanName) throws BeansException {
//先尝试直接从容器中获取bean实例
Object singleton = this.getSingleton(beanName);
if (singleton == null) {
//如果没有实例,则尝试从毛胚实例中获取
singleton = this.earlySingletonObjects.get(beanName);
if (singleton == null) {
//如果连毛胚都没有,则创建bean实例并注册
System.out.println("get bean null -------------- " + beanName);
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
singleton = createBean(beanDefinition);
this.registerBean(beanName, singleton);
// 进行beanpostprocessor处理
// step 1: postProcessBeforeInitialization
applyBeanPostProcessorBeforeInitialization(singleton, beanName);
// step 2: init-method
if (beanDefinition.getInitMethodName() != null &&
!beanDefinition.equals("")) {
invokeInitMethod(beanDefinition, singleton);
}
// step 3: postProcessAfterInitialization
applyBeanPostProcessorAfterInitialization(singleton, beanName);
}
}
return singleton;
}
private void invokeInitMethod(BeanDefinition beanDefinition, Object obj) {
Class<?> clz = beanDefinition.getClass();
Method method = null;
try {
method = clz.getMethod(beanDefinition.getInitMethodName());
}
try {
method.invoke(obj);
}
}
@Override
public Boolean containsBean(String name) {
return containsSingleton(name);
}
public void registerBean(String beanName, Object obj) {
this.registerSingleton(beanName, obj);
}
@Override
public void registerBeanDefinition(String name, BeanDefinition
beanDefinition) {
this.beanDefinitionMap.put(name, beanDefinition);
this.beanDefinitionNames.add(name);
if (!beanDefinition.isLazyInit()) {
try {
getBean(name);
}
}
}
@Override
public void removeBeanDefinition(String name) {
this.beanDefinitionMap.remove(name);
this.beanDefinitionNames.remove(name);
this.removeSingleton(name);
}
@Override
public BeanDefinition getBeanDefinition(String name) {
return this.beanDefinitionMap.get(name);
}
@Override
public boolean containsBeanDefinition(String name) {
return this.beanDefinitionMap.containsKey(name);
}
@Override
public boolean isSingleton(String name) {
return this.beanDefinitionMap.get(name).isSingleton();
}
@Override
public boolean isPrototype(String name) {
return this.beanDefinitionMap.get(name).isPrototype();
}
@Override
public Class<?> getType(String name) {
return this.beanDefinitionMap.get(name).getClass();
}
private Object createBean(BeanDefinition beanDefinition) {
Class<?> clz = null;
//创建毛胚bean实例
Object obj = doCreateBean(beanDefinition);
//存放到毛胚实例缓存中
this.earlySingletonObjects.put(beanDefinition.getId(), obj);
try {
clz = Class.forName(beanDefinition.getClassName());
}
//完善bean,主要是处理属性
populateBean(beanDefinition, clz, obj);
return obj;
}
//doCreateBean创建毛胚实例,仅仅调用构造方法,没有进行属性处理
private Object doCreateBean(BeanDefinition beanDefinition) {
Class<?> clz = null;
Object obj = null;
Constructor<?> con = null;
try {
clz = Class.forName(beanDefinition.getClassName());
// handle constructor
ConstructorArgumentValues constructorArgumentValues =
beanDefinition.getConstructorArgumentValues();
if (!constructorArgumentValues.isEmpty()) {
Class<?>[] paramTypes = new Class<?>
[constructorArgumentValues.getArgumentCount()];
Object[] paramValues = new
Object[constructorArgumentValues.getArgumentCount()];
for (int i = 0; i <
constructorArgumentValues.getArgumentCount(); i++) {
ConstructorArgumentValue constructorArgumentValue =
constructorArgumentValues.getIndexedArgumentValue(i);
if ("String".equals(constructorArgumentValue.getType()) ||
"java.lang.String".equals(constructorArgumentValue.getType())) {
paramTypes[i] = String.class;
paramValues[i] = constructorArgumentValue.getValue();
} else if
("Integer".equals(constructorArgumentValue.getType()) ||
"java.lang.Integer".equals(constructorArgumentValue.getType())) {
paramTypes[i] = Integer.class;
paramValues[i] = Integer.valueOf((String)
constructorArgumentValue.getValue());
} else if ("int".equals(constructorArgumentValue.getType()))
{
paramTypes[i] = int.class;
paramValues[i] = Integer.valueOf((String)
constructorArgumentValue.getValue());
} else {
paramTypes[i] = String.class;
paramValues[i] = constructorArgumentValue.getValue();
}
}
try {
con = clz.getConstructor(paramTypes);
obj = con.newInstance(paramValues);
}
}
}
System.out.println(beanDefinition.getId() + " bean created. " +
beanDefinition.getClassName() + " : " + obj.toString());
return obj;
}
private void populateBean(BeanDefinition beanDefinition, Class<?> clz,
Object obj) {
handleProperties(beanDefinition, clz, obj);
}
private void handleProperties(BeanDefinition beanDefinition, Class<?> clz,
Object obj) {
// handle properties
System.out.println("handle properties for bean : " +
beanDefinition.getId());
PropertyValues propertyValues = beanDefinition.getPropertyValues();
//如果有属性
if (!propertyValues.isEmpty()) {
for (int i = 0; i < propertyValues.size(); i++) {
PropertyValue propertyValue =
propertyValues.getPropertyValueList().get(i);
String pType = propertyValue.getType();
String pName = propertyValue.getName();
Object pValue = propertyValue.getValue();
boolean isRef = propertyValue.getIsRef();
Class<?>[] paramTypes = new Class<?>[1];
Object[] paramValues = new Object[1];
if (!isRef) { //如果不是ref,只是普通属性
//对每一个属性,分数据类型分别处理
if ("String".equals(pType) ||
"java.lang.String".equals(pType)) {
paramTypes[0] = String.class;
} else if ("Integer".equals(pType) ||
"java.lang.Integer".equals(pType)) {
paramTypes[i] = Integer.class;
} else if ("int".equals(pType)) {
paramTypes[i] = int.class;
} else {
paramTypes[i] = String.class;
}
paramValues[0] = pValue;
} else {//is ref, create the dependent beans
try {
paramTypes[0] = Class.forName(pType);
}
try {//再次调用getBean创建ref的bean实例
paramValues[0] = getBean((String) pValue);
}
}
//按照setXxxx规范查找setter方法,调用setter方法设置属性
String methodName = "set" + pName.substring(0, 1).toUpperCase()
+ pName.substring(1);
Method method = null;
try {
method = clz.getMethod(methodName, paramTypes);
}
try {
method.invoke(obj, paramValues);
}
}
}
}
abstract public Object applyBeanPostProcessorBeforeInitialization(Object
existingBean, String beanName) throws BeansException;
abstract public Object applyBeanPostProcessorAfterInitialization(Object
existingBean, String beanName) throws BeansException;
}
|
上面的代码较长,但仔细一看可以发现绝大多数是我们原本已经实现的方法,只是移动到了AbstractBeanFactory这个抽象类之中。最关键的代码是getBean()中的这一段。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
singleton = createBean(beanDefinition);
this.registerBean(beanName, singleton);
// beanpostprocessor
// step 1: postProcessBeforeInitialization
applyBeanPostProcessorBeforeInitialization(singleton, beanName);
// step 2: init-method
if (beanDefinition.getInitMethodName() != null &&
!beanDefinition.equals("")) {
invokeInitMethod(beanDefinition, singleton);
}
// step 3: postProcessAfterInitialization
applyBeanPostProcessorAfterInitialization(singleton, beanName);
|
在Spring框架中,Bean的生命周期包括获取Bean的定义、创建Bean实例以及进行Bean的后处理和初始化。在这个抽象类里,我们关注两个核心改动:
-
定义了抽象方法applyBeanPostProcessorBeforeInitialization与applyBeanPostProcessorAfterInitialization:这两个方法分别在Bean处理类初始化之前和之后执行。具体的实现由继承该抽象类的子类来完成。
-
在getBean()方法中实现了对Bean初始化前、初始化和初始化后的处理:
- 在Bean初始化前调用applyBeanPostProcessorBeforeInitialization方法。
- 完成Bean的初始化。
- 在Bean初始化后调用applyBeanPostProcessorAfterInitialization方法。
通过这些改动,我们可以灵活地在Bean的整个生命周期中插入自定义的处理逻辑,从而满足不同的业务需求。
1
2
3
4
5
6
7
8
|
// step 1: postProcessBeforeInitialization
applyBeanPostProcessorBeforeInitialization(singleton, beanName);
// step 2: init-method
if (beanDefinition.getInitMethodName() != null && !beanDefinition.equals("")) {
invokeInitMethod(beanDefinition, singleton);
}
// step 3: postProcessAfterInitialization
applyBeanPostProcessorAfterInitialization(singleton, beanName);
|
现在已经抽象出了一个AbstractBeanFactory,接下来我们看看具体的AutowireCapableBeanFactory是如何实现的。
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
|
public class AutowireCapableBeanFactory extends AbstractBeanFactory{
private final List<AutowiredAnnotationBeanPostProcessor> beanPostProcessors =
new ArrayList<>();
public void addBeanPostProcessor(AutowiredAnnotationBeanPostProcessor
beanPostProcessor) {
this.beanPostProcessors.remove(beanPostProcessor);
this.beanPostProcessors.add(beanPostProcessor);
}
public int getBeanPostProcessorCount() {
return this.beanPostProcessors.size();
}
public List<AutowiredAnnotationBeanPostProcessor> getBeanPostProcessors() {
return this.beanPostProcessors;
}
public Object applyBeanPostProcessorsBeforeInitialization(Object
existingBean, String beanName) throws BeansException {
Object result = existingBean;
for (AutowiredAnnotationBeanPostProcessor beanProcessor :
getBeanPostProcessors()) {
beanProcessor.setBeanFactory(this);
result = beanProcessor.postProcessBeforeInitialization(result,
beanName);
if (result == null) {
return result;
}
}
return result;
}
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean,
String beanName) throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessAfterInitialization(result,
beanName);
if (result == null) {
return result;
}
}
return result;
}
}
|
从代码里也可以看出,它实现起来并不复杂,用一个列表beanPostProcessors记录所有的Bean处理器,这样可以按照需求注册若干个不同用途的处理器,然后调用处理器。
1
2
3
4
5
6
|
for (AutowiredAnnotationBeanPostProcessor beanProcessor :
getBeanPostProcessors()) {
beanProcessor.setBeanFactory(this);
result = beanProcessor.postProcessBeforeInitialization(result,
beanName);
}
|
代码一目了然,就是对每个Bean处理器,调用方法postProcessBeforeInitialization。
最后则是调整ClassPathXmlApplicationContext,引入的成员变量由SimpleBeanFactory改为新建的AutowireCapableBeanFactory,并在构造函数里增加上下文刷新逻辑。
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
|
public ClassPathXmlApplicationContext(String fileName, boolean isRefresh) {
Resource resource = new ClassPathXmlResource(fileName);
AutowireCapableBeanFactory beanFactory = new
AutowireCapableBeanFactory();
XmlBeanDefinitionReader reader = new
XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(resource);
this.beanFactory = beanFactory;
if (isRefresh) {
try {
refresh();
}
}
}
public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
return this.beanFactoryPostProcessors;
}
public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor
postProcessor) {
this.beanFactoryPostProcessors.add(postProcessor);
}
public void refresh() throws BeansException, IllegalStateException {
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(this.beanFactory);
// Initialize other special beans in specific context subclasses.
onRefresh();
}
private void registerBeanPostProcessors(AutowireCapableBeanFactory
beanFactory) {
beanFactory.addBeanPostProcessor(new
AutowiredAnnotationBeanPostProcessor());
}
private void onRefresh() {
this.beanFactory.refresh();
}
|
在Spring框架中,ClassPathXmlApplicationContext
容器的启动过程涉及到了Bean的初始化和依赖注入。以下是该过程的一个有条理且结构化的描述:
- 启动容器
- 注册BeanPostProcessor
- 执行onRefresh()
- 获取Bean定义与创建Bean实例
-
AbstractBeanFactory
中的refresh()
方法会被调用,以确保所有的bean定义已经被正确加载。
-
随后,通过getBean()
方法根据需要创建bean实例。
-
getBean()
不仅创建bean对象,还会解决bean之间的依赖关系。
- 应用BeanPostProcessor进行初始化
此流程展示了Spring如何通过一系列精心设计的方法链来保证应用程序上下文能够被正确地构建,并准备好供应用程序使用。
1
2
3
|
applyBeanPostProcessorBeforeInitialization(singleton, beanName);
invokeInitMethod(beanDefinition, singleton);
applyBeanPostProcessorAfterInitialization(singleton, beanName);
|
- applyBeanPostProcessorBeforeInitialization由具体的BeanFactory,如AutowireCapableBeanFactory,来实现,这个实现也很简单,就是对BeanFactory里已经注册好的所有Bean处理器调用相关方法。
1
2
|
beanProcessor.postProcessBeforeInitialization(result, beanName);
beanProcessor.postProcessAfterInitialization(result, beanName);
|
- 我们事先准备好的AutowiredAnnotationBeanPostProcessor方法里面会解释Bean中的Autowired注解。
测试注解
到这里,支持注解的工作就完成了,接下来就是测试Autowired注解了。在这里我们做两个改动。
- 在测试类中增加Autowired注解。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
package com.minis.test;
import com.minis.beans.factory.annotation.Autowired;
public class BaseService {
@Autowired
private BaseBaseService bbs;
public BaseBaseService getBbs() {
return bbs;
}
public void setBbs(BaseBaseService bbs) {
this.bbs = bbs;
}
public BaseService() {
}
public void sayHello() {
System.out.println("Base Service says Hello");
bbs.sayHello();
}
}
|
- 注释XML配置文件中关于循环依赖的配置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<?xml version="1.0" encoding="UTF-8" ?>
<beans>
<bean id="bbs" class="com.minis.test.BaseBaseService">
<property type="com.minis.test.AServiceImpl" name="as" ref="aservice" />
</bean>
<bean id="aservice" class="com.minis.test.AServiceImpl">
<constructor-arg type="String" name="name" value="abc"/>
<constructor-arg type="int" name="level" value="3"/>
<property type="String" name="property1" value="Someone says"/>
<property type="String" name="property2" value="Hello World!"/>
<property type="com.minis.test.BaseService" name="ref1"
ref="baseservice"/>
</bean>
<bean id="baseservice" class="com.minis.test.BaseService">
<!-- <property type="com.minis.test.BaseBaseService" name="bbs"
ref="basebaseservice" />-->
</bean>
</beans>
|
这节课我们丰富了原来的框架,支持了注解,让它更有模有样了。
注解是现代最受程序员欢迎的特性,我们通过Autowired这个注解实现了Bean的注入,这样程序员不用再在XML配置文件中手动配置property,而是在类中声明property的时候直接加上注解即可,框架使用的机制是名称匹配,这也是Spring所支持的一种匹配方式。
接着我们提取了BeanFactory接口,定义了一个抽象的AbstractBeanFactory。通过这个抽象类,将Bean工厂需要做的事情的框架搭建出来,然后在具体实现类中完善细节。这种程序结构称为interface-abstract class-class(接口抽象类),是一种做框架时常用的设计模式。
MiniSpring 自学项目
目标
通过手写 MiniSpring,我们不仅学习功能实现,还要学习大师的编码风格,模仿他们的代码和设计。通过大量练习,我们能够像专业程序员一样编写代码。
源代码
完整源代码可以在以下链接找到:MiniSpring GitHub
功能概览
以下是 MiniSpring 的一些核心功能:
资源探索
支持开源开发者的平台。
阅读材料
- The ReadME Project: GitHub 社区文章。
企业平台
- Enterprise platform: AI 驱动的开发者平台。
定价
功能特性
课后思考题
学完这节课后,我留给你一个思考题:在现有框架中,我们实现了 Autowired 注解,能否支持多个注解?欢迎在留言区与我交流讨论,也欢迎你把这节课分享给需要的朋友。我们下节课见!