自定义注解实现简单的IOC
IOC
一般实现IOC使用的是java的反射技术,IOC和反射的概念再次不做赘述
1.首先我们需要自定义注解
本次是对ioc容器的简单实现,所以定义了3个用的最多的注解
Autowired ,依赖注入
import java.lang.annotation.*;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
}
Component ,生成bean交给容器
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Component {
Class <?> classes ();
}
Value ,给属性赋值
import java.lang.annotation.*;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {
String stringValue () default "";
int intValue() default 0;
}
创建学生类,并添加自定义注解
@Component(classes = Student.class)
@Data
public class Student {
@Value(stringValue = "jack")
private String name;
}
接下来就是我们的简答实现步骤
2.添加pom依赖,该包是一个反射框架,这里我们用于扫描包
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.11</version>
</dependency>
3.有人说spring容器就是多个Map的有序结合,这里我们创建一个hashMap用于存储实例化后的对象
Map<String,Object> beanFactory = new HashMap<String,Object>();
4.扫描包,找到所有需要实例化的对象,也就是有注解Component的类
// 要扫描的包
String packageName = "com.mytest.myIoc";
Reflections ref = new Reflections(packageName);
// 获取包下所有有注解的对象的class
Set<Class<?>> classSet = ref.getTypesAnnotatedWith(Component.class);
5.实例化bean,通过反射,对有注解Value的字段进行赋值
classSet.forEach(c -> {
try {
// 生成对象
Object obj = c.newInstance();
// 获取对象中的所有字段
Field[] declaredFields = obj.getClass().getDeclaredFields();
for (Field declaredField : declaredFields) {
// 设置私有属性可以访问
declaredField.setAccessible(true);
if (declaredField.isAnnotationPresent(Value.class)) {
String type = declaredField.getType().getName();
Object v = null;
if (type.equals("java.lang.String")) {
v = declaredField.getAnnotation(Value.class).stringValue();
}else if (type.equals("java.lang.Integer")){
v =declaredField.getAnnotation(Value.class).intValue();
}
declaredField.set(obj,v);
}
}
registerBean(c.getName(),obj);
}catch (Exception e){
log.error("对象生成失败");
e.printStackTrace();
}
});
/**
* 注册bean
*/
private void registerBean(String name,Object obj){
beanFactory.put(name,obj);
}
6.到这里已经把实例好的对象交给map容器了,不妨打印一下map看看是否对象创建成功,字段是否赋值成功
可以看到对象已经创建成功,并且给name赋值成功
7.接下来就是实现依赖注入的功能了,首先我们定义一个私有属性,通过类型找到map容器中已经实例好的对象
注入
@Autowired
private Student student;
/**
* 自动注入实现
*/
private void inject(Object o) {
Field[] declaredFields = o.getClass().getDeclaredFields();
for (Field declaredField : declaredFields) {
declaredField.setAccessible(true);
if (declaredField.isAnnotationPresent(Autowired.class)){
Class<?> type = declaredField.getType();
Object bean = beanFactory.get(type.getTypeName());
try {
declaredField.set(o,bean);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
}
8.开始测试
public static void main(String[] args) {
// 实例化容器对象
MyIoc myIoc = new MyIoc();
myIoc.scanPackages();
// 容器中的对象
myIoc.beanFactory.forEach((k,v) ->{
System.out.println(k + "->" + v);
});
// 此时为null
System.out.println(myIoc.student);
//实现注入
myIoc.inject(myIoc);
// 此时为Student(name=jack)
System.out.println(myIoc.student);
}