一个超级简略的IOC容器,代码见: spring-code/src/main/java/com/IOC at main · CodePpoi/spring-code · GitHub
参考了手写一个最简单的IOC容器,从而了解spring的核心原理-技术圈
一开始是自己写ClassLoader,结果发现自己写的ClassLoader不能加载到放在类上面的注解,我猜测是defineClass()有问题,因为字节码是一样的(通过工具看了),后面直接放弃自定义ClassLoader,采用UrlClassLoader
首先定义注解MyBean用来标注这个类是一个Bean,以及注解AutoInject,功能类似Autowire
@Retention(RetentionPolicy.RUNTIME)
@Target(value={ElementType.TYPE})
//@Documented
public @interface MyBean {
String value() default "TBean";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(value={ElementType.FIELD})
//@Documented
public @interface AutoInject {
String value() default "";
}
创建BeanFactory,scanPackageAndLoadBeans用来扫描包以及injectBeans用来给注解了AutoInject的类赋值, typeBeanMap用来存储Class和Bean实例的对应关系
package com.IOC;
import com.IOC.beans.*;
import java.lang.reflect.Field;
import java.util.*;
public class TBeanFactory {
private Map<Class, Object> typeBeanMap = new HashMap<>();
private String basePackage = "com.IOC.beans";
public <T> T getBean(Class clazz) {
return (T) typeBeanMap.get(clazz);
}
public static void main(String[] args) {
TBeanFactory beanFactory = new TBeanFactory();
beanFactory.scanPackageAndLoadBeans();
beanFactory.injectBeans(beanFactory.typeBeanMap);
UserController userController = beanFactory.getBean(UserController.class);
//调用Bean中的方法
User user = userController.getUserById(1L);
System.out.println(user);
}
// inject 用来给标注了AutoInject 设置值
private void injectBeans(Map<Class, Object> typeBeanMap) {
for(Object bean : typeBeanMap.values()) {
Class clasz = bean.getClass();
Field[] fields = clasz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(AutoInject.class)) {
field.setAccessible(true);
Class beanType = field.getType();
Object proxyBean = typeBeanMap.get(beanType);
try {
field.set(bean, proxyBean);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
private void scanPackageAndLoadBeans() {
//找到包下所有类
Set<String> classNames = ClassUtils.getClassName(basePackage, true);
for (String className : classNames) {
try {
//查找类
Class clasz = Class.forName(className);
//判断类上是否存在MyBean注解
if (clasz.isAnnotationPresent(MyBean.class)) {
typeBeanMap.put(clasz, clasz.newInstance());
}
} catch (Exception exception) {
}
}
}
}
然后就是两个MyBean.Class,其中UserController中AutoInject了userService
package com.IOC.beans;
@MyBean(value = "userController")
public class UserController {
@AutoInject
private UserServiceImpl userService;
public User getUserById(Long id) {
return userService.getUserById(id);
}
public UserController() {
System.out.println("beans.BeanA created");
}
public void print() {
System.out.println("called by someone");
}
}
@MyBean("userService")
public class UserServiceImpl {
public User getUserById(Long id) {
User user = new User();
if (id == 1) {
user.setId(id);
user.setName("zhangsan");
} else if (id == 2) {
user.setId(id);
user.setName("lisi");
}
return user;
}
}