PS:本人才疏学浅,如代码中出现什么纰漏,忘大神们不吝赐教
首先呢我们需要先了解一下什么是IOC
IOC是Inversion of Control的缩写,多数书籍翻译成“控制反转”,还有些书籍翻译成为“控制反向”或者“控制倒置”。
1996年,Michael Mattson在一篇有关探讨面向对象框架的文章中,首先提出了IOC 这个概念。对于面向对象设计及编程的基本思想,前面我们已经讲了很多了,不再赘述,简单来说就是把复杂系统分解成相互合作的对象,这些对象类通过封装以后,内部实现对外部是透明的,从而降低了解决问题的复杂度,而且可以灵活地被重用和扩展
让我们开始吧,首先建立两个自定义注解,@Bean(声明这是一个Bean),@Inject(声明需要注入)
我会在@Bean注解上 详细的描述 2个常用的元注解的含义
package com.yuxuan66.ioc.support.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author Sir丶雨轩
* @date 2020-05-18
*
* 元注解
* 1.@Retention(RetentionPolicy value) 注解的生命周期 default = RetentionPolicy.CLASS
* RetentionPolicy.SOURCE 表示注解的信息会被编译器抛弃,不会留在class文件中,注解的信息只会留在源文件中
* RetentionPolicy.CLASS 表示注解的信息被保留在class文件(字节码文件)中当程序编译时,但不会被虚拟机读取在运行的时候
* RetentionPolicy.RUNTIME 表示注解的信息被保留在class文件(字节码文件)中当程序编译时,会被虚拟机保留在运行时
*
* 2.@Target(ElementType\[\] value) 注解的作用域 可同时使用多个 @Target({ElementType.TYPE,ElementType.METHOD})
* ElementType.TYPE 接口、类、枚举、注解
* ElementType.FIELD 字段、枚举的常量
* ElementType.METHOD 方法
* ElementType.PARAMETER 方法参数
* ElementType.CONSTRUCTOR 构造函数
* ElementType.LOCAL_VARIABLE 局部变量
* ElementType.ANNOTATION_TYPE 注解
* ElementType.PACKAGE 包
* ElementType.TYPE_PARAMETER (@since 1.8) 泛型参数
* ElementType.TYPE_USE (@since 1.8) 使用泛型的地方
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Bean {
/**
* beanName
* @return beanName
*/
String value() default "";
}
package com.yuxuan66.ioc.support.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author Sir丶雨轩
* @date 2020-05-18
*
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Inject {
String value() default "";
}
定义一个Bean工厂接口
package com.yuxuan66.ioc.support.bean;
/**
* @author Sir丶雨轩
* @date 2020/5/18
*/
public interface BeanFactory {
/**
* 根据类型获取一个bean
* @param type 类型
* @param
* @return bean
*/
public
/**
* 根据名称获取一个bean
* @param beanName 名称
* @return bean
*/
public Object getBean(String beanName);
/**
* 根据名称和类型获取一个bean
* @param beanName 名称
* @param clazz 类型
* @param
* @return bean
*/
public
}
实现这个接口
package com.yuxuan66.ioc.support.bean;
import com.yuxuan66.ioc.support.annotation.Bean;
import com.yuxuan66.ioc.support.annotation.Inject;
import com.yuxuan66.ioc.support.common.ClassScanner;
import com.yuxuan66.ioc.support.common.StrUtil;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author Sir丶雨轩
* @date 2020/5/18
*/
public class ApplicationContext implements BeanFactory {
private final String packageName;
private Map<String, Object> beans = new HashMap<String, Object>();
private ApplicationContext(String packageName) {
this.packageName = packageName;
}
private void refresh() {
Set<Class<?>> classes = ClassScanner.getClasses(packageName);
//初始化Bean
classes.forEach(clazz -> {
Bean bean = clazz.getAnnotation(Bean.class);
if (bean != null) {
String beanName = StrUtil.toLowerCaseFirstOne(clazz.getSimpleName());
try {
beans.put(beanName, clazz.getConstructor().newInstance());
} catch (RuntimeException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
});
//注入Bean
beans.forEach((beanName, bean) -> {
//获取所有字段
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
Inject inject = field.getAnnotation(Inject.class);
if (inject != null) {
String injectBeanName = inject.value();
if (injectBeanName.length() == 0) {
injectBeanName = field.getName();
}
Object _bean = beans.get(injectBeanName);
if (_bean == null) {
throw new RuntimeException("bean " + injectBeanName + " not found");
}
field.setAccessible(true);
try {
field.set(bean, _bean);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
});
}
public static ApplicationContext start(String packageName) {
ApplicationContext applicationContext = new ApplicationContext(packageName);
applicationContext.refresh();
return applicationContext;
}
@Override
public
for (Map.Entry<String, Object> stringObjectEntry : beans.entrySet()) {
if(stringObjectEntry.getValue().getClass().equals(type)){
return (T) stringObjectEntry.getValue();
}
}
return null;
}
@Override
public Object getBean(String beanName) {
return beans.get(beanName);
}
@Override
public
return (T) getBean(beanName);
}
}
还有一些工具类我将发布在Gitee
测试使用方法
package com.yuxuan66.ioc.test;
import com.yuxuan66.ioc.support.bean.ApplicationContext;
/**
* @author Sir丶雨轩
* @date 2020/5/18
*/
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext = ApplicationContext.start("com.yuxuan66");
Study study = applicationContext.getBean(Study.class);
study.say();
}
}
项目地址 [https://gitee.com/yuxuan-old-project/mini-ioc](https://gitee.com/yuxuan-old-project/mini-ioc)
评论区