目录
一、什么是 Spring IOC?
Spring 的核心之一是 IOC,全称 Inversion Of Control ,控制反转,用来统一管理 Bean
二、IOC 的作用
IOC 的作用就是帮程序员创建 Bean 对象
1. IOC 怎么知道要创建哪些对象呢?
在 xml 配置文件中指定要创建哪些对象,或者使用注解的方式
如果使用注解的方式,需要自定义注解,自定义注解说白了就是告诉 JVM 这个 Bean 不同于其他普通的 Bean ,它有其他的用途,标记一下。
@Component、@Controller、@Service 可以用于创建 Bean 的注解
2. 创建出来的对象放在哪儿?
先记录需要被创建的 Bean 对象的信息,存到 HashMap 中,然后根据 HashMap 中存储的Bean 的信息创建对象,存到IOC容器中
3. 创建出来的对象如果有属性,如何给属性赋值?
使用注解 @Autowired
三、实现步骤
1. 创建自定义注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
String value() default "";
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
String value() default "";
}
2. 创建 IOC 容器
扫描包,判断类上是否有注解,如果有,存储需要被创建的对象的id,也就是全类名。
定义一个类用于存储这些信息,这个类就是 BeanDefinition 叫做 Bean 定义类,Bean 定义类创建对象后称为 Bean 定义对象,这个对象存储了 Bean 的信息
然后把 Bean 定义对象存放到 HashMap 中,这个 Map 叫做 Bean 定义Map
1. 创建 Bean 定义类
package com.shao.IOC;
public class BeanDefinition {
private String id;
private String className;
public BeanDefinition() {
}
public BeanDefinition(String id, String className) {
this.id = id;
this.className = className;
}
/**
* 获取
*
* @return id
*/
public String getId() {
return id;
}
/**
* 设置
*
* @param id
*/
public void setId(String id) {
this.id = id;
}
/**
* 获取
*
* @return className
*/
public String getClassName() {
return className;
}
/**
* 设置
*
* @param className
*/
public void setClassName(String className) {
this.className = className;
}
public String toString() {
return "BeanDefinition{id = " + id + ", className = " + className + "}";
}
}
2. 创建 IOC 容器
3. 扫描包
扫描包需要先知道路径是什么,从哪开始
这里扫描的是编译后的 class 文件,并不是类文件,因为程序运行后使用的是编译后的文件
那如何从这里开始呢?
使用类加载器获取路径
package com.shao.IOC;
import com.shao.Annotation.Controller;
import com.shao.Annotation.Service;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
/**
* ApplicationContext 类. 当作 IOC 容器
*
* @author shao.
*/
public class ApplicationContext {
/**
* Bean 定义Map 存储Bean 定义对象
*/
private HashMap<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
/**
* Bean 实例Map 存储Bean 实例对象
*/
private HashMap<String, Object> BeanMap = new HashMap<>();
public ApplicationContext(String basePackage) throws UnsupportedEncodingException {
scanPackage(basePackage);
}
/**
* 1. 扫描包,扫描需要被创建的类,创建 Bean 定义对象,并放入 Bean 定义Map中
*/
public void scanPackage(String basePackage) throws UnsupportedEncodingException {
// String basePackage = "com.shao";
// 获取类加载器
ClassLoader classLoader = this.getClass().getClassLoader();
// 获取包路径
String path = classLoader.getResource(basePackage.replace(".", "/")).getPath();
// 路径解码,如果路径有空格或者中文,会出现 16 进制的字符
String packagePath = URLDecoder.decode(path, "UTF-8");
// 创建文件对象
File fileDir = new File(packagePath);
// 获取包下的文件列表
File[] files = fileDir.listFiles();
for (File file : files) {
if (file.isFile()) {
// 判断是否是class文件
if (file.getName().endsWith(".class")) {
// 包路径 + 文件名 构成全类名
String className = basePackage + "." + file.getName().replace(".class", "");
try {
// 动态加载了名为 className 的类,获取该类的 Class 对象
Class<?> aClass = Class.forName(className);
// 判断该类是否有 &#