IOC是什么
IOC(Inversion Of Control)是一种设计思想,意思是控制反转,这个思想的目的是为了自动地管理类的生命周期以及所有类之间的依赖关系。传统Java SE程序中如果我们需要在一个实例中引用另一个对象,一般是直接用new关键字直接创建一个对象来构建这个依赖关系,这种依赖构建方式使程序之间具有很强的耦合关系,甚至程序不能独立编译,难以进行单元测试。IOC设计思想可以让我们实现程序之间的解耦,很大程度地提高程序的灵活性和可维护性。以前是对象控制其他对象,现在将所有对象的控制权都交给了IOC实现组件,所以称为控制反转。
那么怎么去实现IOC设计思想呢,IOC有两个比较重要的概念,一个是容器,一个是DI(Dependency Injection,依赖注入)。容器的任务是管理类的生命周期,DI的任务是创建容器中各个类之间的依赖关系。我们只需要实现这两个核心概念就可以实现一个简易的IOC组件。
配置约定
虽然IOC组件可以使我们不用手动地管理类和他们之间的依赖关系,但是我们还是需要通过配置的方式来使IOC组件根据我们的需要去管理所有的类,所以首先得约定好如何进行配置来使我们的需求被IOC组件识别,这里为了简单实现选择注解这个配置方式
- 把当前类加入容器的注解@Bean
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Bean {
}
- 为实例变量注入依赖的注解@Autowired
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
}
类扫描器
在实现容器之前,我们需要拿到项目中所有的类,为了后面创建容器时能从这些类中获取带有@Bean注解的类加入容器。我们首先用ClassLoader类的getResources()方法获取包的根文件夹下的资源,然后根据这些资源是文件还是Jar包对资源做对应的处理,如果是文件就是树状读取,使用递归的方式获取文件下所有类的全类名,如果使Jar包就进行解析操作,然后迭代获取Jar包中的所有类的全类名,根据拿到的全类名通过反射的方式拿到所有类的Class对象存入list后最后返回
public class ClassScanner {
private List<Class<?>> list;
public List<Class<?>> getClassList() throws Exception {
// 除了第一次都不要需要扫描,直接返回
if (list != null) {
return list;
}
List<Class<?>> classList = new ArrayList<Class<?>>();
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Enumeration<URL> urls = loader.getResources("");
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
String protocol = url.getProtocol();
if (protocol.equals("file")) {
// 在class目录中
String packagePath = url.getPath();
// 执行添加类操作
addClass(classList, packageName, packagePath);
} else if (protocol.equals("jar")) {
// 在jar包中
JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
JarFile jarFile = jarURLConnection