# 仿 Spring 实现简单的 IoC 和 AOP
仿照 tiny-spring 项目编写的的一个玩具级 Spring 项目,实现了简单的 IoC 和 AOP 功能。
本项目包含了两个不同版本的 IoC 和 AOP 实现,相关源码包结构如下:
* simple,包含了简单的 IoC 和 AOP 实现代码
* IoC,包含了较为复杂的 IoC 实现代码
* aop,包含了较为复杂的 AOP 实现代码
## 1. 背景
我在大四实习的时候开始接触 J2EE 方面的开发工作,也是在同时期接触并学习 Spring 框架,到现在也有快有两年的时间了。不过之前没有仿写过 Spring IoC 和 AOP,只是宏观上对 Spring IoC 和 AOP 原理有一定的认识。所以为了更进一步理解 Spring IoC 和 AOP 原理。在工作之余,参考了一些资料和代码,动手实现了一个简单的 IoC 和 AOP,并实现了如下功能:
- 根据 XML 配置文件加载相关 bean
- 对 BeanPostProcessor 类型的 bean 提供支持
- 对 BeanFactoryAware 类型的 bean 提供支持
- 实现了基于 JDK 动态代理的 AOP
- 整合了 IoC 和 AOP,使得二者可很好的协同工作
在实现自己的 IoC 和 AOP 前,我的想法比较简单,就是实现一个非常简单的 IoC 和 AOP,哪怕是几十行代码实现的都行。后来实现后,感觉还很有意思的。不过那个实现太过于简单,和 Spring IoC,AOP 相去甚远。后来想了一下,不能仅满足那个简单的实现,于是就有了这个仿写项目。相对来说仿写的代码要复杂了一些,功能也多了一点,看起来也有点样子的。尽管仿写出的项目仍然是玩具级,不过写仿写的过程中,还是学到了一些东西。总体上来说,收获还是很大的。在接下来文章中,我也将从易到难,实现不同版本的 IoC 和 AOP。好了,不多说了,开始干活。
## 2. 简单的 IoC 和 AOP 实现
### 2.1 简单的 IoC
先从简单的 IoC 容器实现开始,最简单的 IoC 容器只需 4 步即可实现,如下:
- 加载 XML 配置文件,遍历其中的 <bean> 标签
- 获取<bean>标签中的 id 和 class 属性,加载 class 属性对应的类,并创建 bean
- 遍历 <bean> 标签中的 <property> 标签,获取属性值,并将属性值填充到 bean 中
- 将 bean 注册到 bean 容器中
如上所示,仅需 4 步即可,是不是觉得很简单。好了,Talk is cheap, Show me the code. 接下来要上代码了。不过客官别急,上代码前,容我对代码结构做一下简单介绍:
```
SimpleIOC // IOC 的实现类,实现了上面所说的4个步骤
SimpleIOCTest // IOC 的测试类
Car // IOC 测试使用的 bean
Wheel // 同上
ioc.xml // bean 配置文件
```
容器实现类 SimpleIOC 的代码:
```
public class SimpleIOC {
private Map<String, Object> beanMap = new HashMap<>();
public SimpleIOC(String location) throws Exception {
loadBeans(location);
}
public Object getBean(String name) {
Object bean = beanMap.get(name);
if (bean == null) {
throw new IllegalArgumentException("there is no bean with name " + name);
}
return bean;
}
private void loadBeans(String location) throws Exception {
// 加载 xml 配置文件
InputStream inputStream = new FileInputStream(location);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Document doc = docBuilder.parse(inputStream);
Element root = doc.getDocumentElement();
NodeList nodes = root.getChildNodes();
// 遍历 <bean> 标签
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
String id = ele.getAttribute("id");
String className = ele.getAttribute("class");
// 加载 beanClass
Class beanClass = null;
try {
beanClass = Class.forName(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
return;
}
// 创建 bean
Object bean = beanClass.newInstance();
// 遍历 <property> 标签
NodeList propertyNodes = ele.getElementsByTagName("property");
for (int j = 0; j < propertyNodes.getLength(); j++) {
Node propertyNode = propertyNodes.item(j);
if (propertyNode instanceof Element) {
Element propertyElement = (Element) propertyNode;
String name = propertyElement.getAttribute("name");
String value = propertyElement.getAttribute("value");
// 利用反射将 bean 相关字段访问权限设为可访问
Field declaredField = bean.getClass().getDeclaredField(name);
declaredField.setAccessible(true);
if (value != null && value.length() > 0) {
// 将属性值填充到相关字段中
declaredField.set(bean, value);
} else {
String ref = propertyElement.getAttribute("ref");
if (ref == null || ref.length() == 0) {
throw new IllegalArgumentException("ref config error");
}
// 将引用填充到相关字段中
declaredField.set(bean, getBean(ref));
}
// 将 bean 注册到 bean 容器中
registerBean(id, bean);
}
}
}
}
}
private void registerBean(String id, Object bean) {
beanMap.put(id, bean);
}
}
```
容器测试使用的 bean 代码:
```
public class Car {
private String name;
private String length;
private String width;
private String height;
private Wheel wheel;
// 省略其他不重要代码
}
public class Wheel {
private String brand;
private String specification ;
// 省略其他不重要代码
}
```
bean 配置文件 ioc.xml 内容:
```
<beans>
<bean id="wheel" class="com.titizz.simulation.toyspring.Wheel">
<property name="brand" value="Michelin" />
<property name="specification" value="265/60 R18" />
</bean>
<bean id="car" class="com.titizz.simulation.toyspring.Car">
<property name="name" value="Mercedes Benz G 500"/>
<property name="length" value="4717mm"/>
<property name="width" value="1855mm"/>
<property name="height" value="1949mm"/>
<property name="wheel" ref="wheel"/>
</bean>
</beans>
```
IoC 测试类 SimpleIOCTest:
```
public class SimpleIOCTest {
@Test
public void getBean() throws Exception {
String location = SimpleIOC.class.getClassLoader().getResource("spring-test.xml").getFile();
SimpleIOC bf = new SimpleIOC(location);
Wheel wheel = (Wheel) bf.getBean("wheel");
System.out.println(wheel);
Car car = (Car) bf.getBean("car");
System.out.println(car);
}
}
```
测试结果:
[![](https://www.writebug.com/myres/static/uploads/2021/12/29/e4b515bf3e9c783f251d7ef20745f0ce.writebug)](https://link.segmentfault.com/?enc=hnYx9%2Fy3r%2BcdVXjo69R7wg%3D%3D.6YrUP3yidoHzDGvFuwvKeMNlIpt9%2BQ1894zjJ50owDU%3D)
以上是简单 IoC 实现的全部内容,难度不大,代码也不难看懂,这里不再多说了。下面说说简单 AOP 的实现。
### 2.2 简单的 AOP 实现
AOP 的实现是基于代理模式的,这一�
没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
本项目包含了两个不同版本的 IoC 和 AOP 实现,相关源码包结构如下: simple,包含了简单的 IoC 和 AOP 实现代码 IoC,包含了较为复杂的 IoC 实现代码 aop,包含了较为复杂的 AOP 实现代码
资源推荐
资源详情
资源评论
收起资源包目录
100012181-基于Java仿Spring实现简单的 IoC 和 AOP.zip (47个子文件)
toyspring
pom.xml 1KB
LICENSE.txt 10KB
src
test
resources
toy-spring.xml 1KB
toy-spring-ioc.xml 588B
java
com
titizz
simulation
toyspring
HelloService.java 145B
simple
SimpleIOCTest.java 611B
SimpleAOPTest.java 831B
HelloServiceImpl.java 241B
Wheel.java 692B
aop
AspectJExpressionPointcutTest.java 1KB
JdkDynamicAopProxyTest.java 1KB
LogInterceptor.java 567B
ioc
XmlBeanFactoryTest.java 971B
Car.java 1KB
main
java
com
titizz
simulation
toyspring
simple
BeforeAdvice.java 590B
SimpleAOP.java 335B
SimpleIOC.java 3KB
MethodInvocation.java 149B
Advice.java 190B
aop
Advisor.java 178B
MethodMatcher.java 212B
TargetSource.java 539B
ClassFilter.java 178B
AbstractAopProxy.java 283B
ReflectiveMethodInvocation.java 1018B
ProxyFactory.java 349B
AopProxy.java 142B
Pointcut.java 192B
PointcutAdvisor.java 171B
AdvisedSupport.java 922B
JdkDynamicAopProxy.java 2KB
AspectJExpressionPointcut.java 4KB
AspectJAwareAdvisorAutoProxyCreator.java 2KB
AspectJExpressionPointcutAdvisor.java 652B
ioc
PropertyValues.java 563B
BeanReference.java 504B
BeanPostProcessor.java 309B
PropertyValue.java 416B
factory
BeanFactory.java 180B
BeanFactoryAware.java 202B
BeanDefinitionReader.java 257B
xml
XmlBeanDefinitionReader.java 3KB
XmlBeanFactory.java 5KB
BeanDefinition.java 1KB
LICENSE 1KB
.gitignore 306B
README.md 12KB
共 47 条
- 1
资源评论
神仙别闹
- 粉丝: 2674
- 资源: 7640
下载权益
C知道特权
VIP文章
课程特权
开通VIP
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功