IoC是Spring框架的核心内容,IoC(Inversion of Control)控制反转,是一种设计思想,DI(依赖注入)是实现IoC的一种方法。其实spring就是一个容器,一个bean容器。主要是完成了完成对象的创建和依赖的管理注入。

Spring

  所谓控制反转,就是把原先我们代码里面需要实现的对象(bean)创建、依赖的代码,反转给ioc容器来帮忙实现,也就是 ioc 容器帮我们做了原本应该我门自己实现的对象创建和依赖的内容。

  我们有一个业务逻辑模块 UserService 和一个实体类 User 还有一个持久层模块 UserDAO 和它的实现 UserDAOImpl。
他们之间 UserService 调用(依赖)UserDAO 来操作数据库。我们在test 中运行的时候呢,要创建 UserService 和 UserDAO 并将 UserDAO set 到 UserService 中,这是我门正常的逻辑。

好了、现在我们要用自己编写的简单的ioc 来处理这些关系。

一、项目结构

image

二、导入Maven依赖的jar包(pom.xml)

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

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.study</groupId>
<artifactId>simple-springioc</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>jdom</groupId>
<artifactId>jdom</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

三、编写bean.xml

1
2
3
4
5
6
7
8
9

<beans>
<bean id="u" class="com.study.dao.impl.UserDAOImpl" />
<!--依赖注入,自动装配-->
<bean id="userService" class="com.study.service.UserService" >
<property name="userDAO" bean="u"/>
</bean>

</beans>

四、创建BeanFactory接口

创建一个BeanFactory接口用来创建bean (模拟spring)

1
2
3
4
5
6
7
8
9

package com.study.spring;

/**
* @author Howe Hsiang
*/
public interface BeanFactory {
Object getBean(String name);
}

五、创建ClassPathXmlApplicationContext实现类

创建一个用来处理xml的类ClassPathXmlApplicationContext (也是模拟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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

package com.study.spring;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* @author Howe Hsiang
*/
public class ClassPathXmlApplicationContext implements BeanFactory {
private Map<String, Object> beans = new HashMap<String, Object>();

public ClassPathXmlApplicationContext() throws Exception {
//解析xml 利用反射生成 bean
SAXBuilder sb = new SAXBuilder();
Document doc = sb.build("src/main/resources/bean.xml"); //构造文档对象
Element root = doc.getRootElement(); //获取根元素
List list = root.getChildren("bean");//取名字为disk的所有元素
for (int i = 0; i < list.size(); i++) {
Element element = (Element) list.get(i);
String id = element.getAttributeValue("id");
String className = element.getAttributeValue("class");//取disk子元素capacity的内容
System.out.println("id : " + id + " className : " + className);
Object o = Class.forName(className).newInstance();
beans.put(id, o);

//依赖注入,自动装配 xml 的第二层
for (Element propertyElement : (List<Element>) element.getChildren("property")) {
String name = propertyElement.getAttributeValue("name"); //userDAO
String bean = propertyElement.getAttributeValue("bean"); //u
Object beanObj = beans.get(bean);//UserDAOImpl instance

//拼出setUserDAO方法名字
String methodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
System.out.println("methodName : " + methodName);

// methodName 为方法名 beanObj.getClass().getInterfaces()[0] 为方法的参数 反射取出方法
// beanObj.getClass().getInterfaces()[0] 为 beanObj 实现的第一个接口 也就是 UserDao 为方法的参数
// beanObj 为 UserDAOImpl.class 因为xml 中 bean u 配置的 class 为 UserDAOImpl
Method m = o.getClass().getMethod(methodName, beanObj.getClass().getInterfaces()[0]);

// 进行注入
// 代理执行 m 方法, 也就是用 o 这个对象 调用 m 方法 参数 为 beanObj
// o.m(beanObj) 等价于 userService.setUserDao(userDao)
m.invoke(o, beanObj);
}
}
}


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

六、测试类UserServiceTest

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

package com.study.service;

import com.study.aop.LogInterceptor;
import com.study.dao.UserDAO;
import com.study.dao.impl.UserDAOImpl;
import com.study.model.User;
import com.study.spring.BeanFactory;
import com.study.spring.ClassPathXmlApplicationContext;
import org.junit.Test;

import java.lang.reflect.Proxy;

/**
* @author Howe Hsiang
*/
public class UserServiceTest {

@Test
public void testAdd() throws Exception {

BeanFactory factory = new ClassPathXmlApplicationContext();
// 自动创建 bean
// UserDAO userDAO = (UserDAO)factory.getBean("u");
// UserService userService = new UserService(userDAO);

//依赖注入,自动装配
UserService userService = (UserService) factory.getBean("userService");
userService.add(new User());
}


//通过jdk 的动态代理实现
@Test
public void testProxy() {
//被代理对象
UserDAO userDAO = new UserDAOImpl();
LogInterceptor li = new LogInterceptor();
li.setTarget(userDAO);
//newProxyInstance 产生一个代理对象 ,三个参数
//1.classloader 代理对象和被代理对象应该处于同一个 classloader
//2.接口 产生的代理对象应该实现那些接口
//3.handel 执行代理对象方法时,应用那个handel 处理。
//(接口中有什么方法,代理中就有什么方法 代理中的每个方法在调用的时候都会把 方法自身传给 handel, 并把 代理对象和参数都传递过去 )

//UserDAO userDAOProxy = (UserDAO) Proxy.newProxyInstance(userDAO.getClass().getClassLoader(), userDAO.getClass().getInterfaces(), li);
Class[] cl = new Class[1];
cl[0] = UserDAO.class;
UserDAO userDAOProxy = (UserDAO) Proxy.newProxyInstance(userDAO.getClass().getClassLoader(), cl, li);
System.out.println(userDAOProxy.getClass());
userDAOProxy.detele();
userDAOProxy.save(new User());

/**
* 代理对象 实现 UserDAO 接口, 实现了 UserDAO 的所有方法。
* 执行的时候,
* class $Proxy4 implements UserDAO
* {
* save(User u) {
* //得到当前的 save 方法
* Method m = UserDAO.getclass.getmethod
* 使用代理对象调用invoke 传递代理自身 this ,传递得到的 method 和 参数
* li.invoke(this, m, u)
* }
* }
*/
}
}

注: 简单的Spring-IOC

本文标题: Spring系列-简单实现IOC-实战篇

本文作者: 狂欢马克思

发布时间: 2020年06月02日 00:00

最后更新: 2021年04月15日 16:08

原始链接: https://www.hosiang.cn/24ddb72/

版权声明: 本文著作权归作者所有,均采用CC BY-NC-SA 4.0许可协议,转载请注明出处!

× 喜欢就赞赏一下呗!
打赏二维码