- 该系列,其实是对《架构探险》这本书的实践。本人想记录自己的学习心得所写下的。
- 从一个简单的Servlet项目开始起步。对每一层进行优化,然后形成一个轻量级的框架。
- 每一篇,都是针对项目的不足点进行优化的。
- 项目已放上github
本篇
在这篇,主要是建立一个Bean容器,实现IOC 控制反转。这样只需要注解就可以实现依赖注入了。
整体实现思路
- 建立一个Bean容器,Map类型的,映射关系是key---class value----实例
- 遍历过滤出基础包下类注解中有Controller或者Service和Entity 等注解的类,然后实例化他们,把他们存到Bean容器中。
- 然后遍历Bean容器中的每一组映射。遍历每个class下的成员遍历,检查出具有Inject注解的成员遍历,然后对其进行赋值操作,从Bean容器中查找出实例并将该实例赋予这个变量
框架实现
BeanHelper类
建立一个Bean 容器
/*
* Bean 助手类
* 加载类,建立Bean容器
* */
public final class BeanHelper {
private static final Logger log = LoggerFactory.getLogger(BeanHelper.class);
/*
* 建立一个Bean容器,(存放Bean类与Bean实例的映射关系)
* */
private static final Map<Class<?>, Object> BEAN_MAP = new HashMap<Class<?>, Object>();
static {
/*
* 调用getBeanClassSet 方法
* 获取bean类方法,也就是有Controller 或Service 等注解的类
* */
Set<Class<?>> classSet = ClassHelper.getBeanClassSet();
classSet.forEach(s-> {
try {
BEAN_MAP.put(s,s.newInstance());
} catch (Exception e) {
log.error("创建类失败",e);
e.printStackTrace();
}
});
}
/*
* 获取Bean容器
* */
public static Map<Class<?>, Object> getBeanMap() {
return BEAN_MAP;
}
/*
* 获取Bean 实例
* */
public static <T> T getBean(Class<T> cls) {
if (!BEAN_MAP.containsKey(cls)) {
log.error("没有获取到{0}实例",cls.getSimpleName());
throw new RuntimeException("没有获取到实例"+cls.getSimpleName());
}
return (T)BEAN_MAP.get(cls);
}
}
IOCHelper 实现依赖注入
查找出具有Inject注解的成员变量并赋值
/*
* 依赖注入助手类
* */
public final class IOCHelper {
/*
* 思路:
* 从BeanHelper Bean容器里获取到所有Bean的映射关系。
* 然后遍历这个容器。获取 类--key,实例--value
* 检查类的成员变量是否有Inject注解,如果有,那么就对该变量注入实例
*
* */
static {
//获取到容器
Map<Class<?>, Object> beanMap = BeanHelper.getBeanMap();
if (MapUtils.isNotEmpty(beanMap)) {
for (Map.Entry<Class<?>,Object> beanEntity:beanMap.entrySet()) {
Class<?> key = beanEntity.getKey();
Object value = beanEntity.getValue();
//获取Bean 类定义的所有成员变量(简称Bean Field)
Field[] declaredFields = key.getDeclaredFields();
if (ArrayUtils.isNotEmpty(declaredFields)) {
for (Field field : declaredFields) {
if (field.isAnnotationPresent(Inject.class)) {
Class<?> type = field.getType();
//在容器中获取该实例
Object o = beanMap.get(type);
if (o != null) {
ReflectionUtil.setField(value,field,o);
} } } } } }
}
}
测试
将CustomerService 添加个成员变量并加上注解
public class CustomerService {
@Inject
public Customer customer;
测试类
@Test
public void testInject() {
try {
Class.forName("com.smart.mysimpleframework.Helper.IOCHelper");
//从容器里获取customerService 的实例查看
CustomerService bean = BeanHelper.getBean(CustomerService.class);
if (bean.customer!=null) {
System.out.println("Inject is ok!!");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
输出
Inject is ok!!
总结:
- 想理解是怎么实现IOC的,还是去github 上clone 整个项目细看一下。
- 到目前为止,我们可以实现依赖注入来了。
- 但是对于Controll层业务代码臃肿的问题还没解决,所以接下来是针对Controller 层请求方法的封装了