IOC管制反转

本文继java的spring框架简略实现后,就Service-ServiceImplDao--DaoImpl之间的依赖关系进行解耦,简略实现@AutoWired无关此局部的依赖注入(DI)。

思路

  1. 以Dao为例,在申明某个Dao时,咱们不再赋初值:
@XxgAutoWiredprivate UserDao userDao;
  1. UserDaoImpl类下面退出@XxgComponent注解
@XxgComponentpublic class UserDaoImpl extends BaseDaoImpl<User> implements UserDao { ...}
  1. 服务器启动,

    3.1 扫描包过程中,退出:判断类中是否有@XxgComponent注解,如果有,则退出咱们指定的容器

    3.2 扫描完结之后,给MethodDefinition创立所在类的实例

  2. 利用反射执行method时,传递上一步创立的所在类的实例

所在类的实例阐明:

次要将该实例中有@AutoWired注解的属性,赋予初值,每次调用办法都应用该实例,就达到了料想的成果。

赋初值的形式:

  1. Map<Class, ComponentDefinition> componentMap容器的key寄存依赖类实现的接口的class,value寄存该类的相干属性。
  2. 获取到有@AutoWired注解的属性时,获取该属性的类型class作为key,在容器中查找该key
  3. 容器中查到的数据,即为其实现类的相干属性
  4. 将其赋值给该实现类

问题

这种实现模式,有一个最大的问题:

一个Dao的接口,只能有一个对应的实现类。

其次:

依赖注入仅在Controller类中应用了才无效

能够应用xml文件来存储接口与其实现类的依赖关系。

一个接口有多个实现类时,只在须要的实现类上增加@XxgComponent注解

代码实现

1.XxgAutoWired注解

/** * @Auther dbc * @Date 2020/10/15 14:40 * @Description */@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface XxgAutoWired {}

2. XxgComponent注解

/** * @Auther dbc * @Date 2020/10/16 15:48 * @Description */@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface XxgComponent {}

3.MethodDefinition中增加一个类的实例

private Object parentInstance; // 所属类的实例

4.扫描类的局部批改

增加Component容器

private static Map<Class, ComponentDefinition> componentMap = new ConcurrentHashMap<>(); // component类容器

ComponentDefinition

/** * @Auther dbc * @Date 2020/10/16 16:03 * @Description 对有@XxgComponent注解的类 进行包装 */@Data@NoArgsConstructor@AllArgsConstructorpublic class ComponentDefinition { private Class typeClazz; // 类对象 private String typeName; // 类名 private XxgComponent component; // component注解 private Class implClazz; // 实现的父类}

批改dealClass办法

private void dealClass(Class clazz) throws Exception { // 一开始就增加 if (clazz.isAnnotationPresent(XxgComponent.class)) { // 将实现类增加到容器中 addComponent(clazz); return ; } ...} 

将实现类增加到容器中的办法

 /** * 将Component类增加到容器中 */ private void addComponent(Class clazz) throws Exception { ComponentDefinition componentDefinition = new ComponentDefinition(); componentDefinition.setComponent((XxgComponent) clazz.getAnnotation(XxgComponent.class)); componentDefinition.setTypeClazz(clazz); componentDefinition.setImplClazz(clazz.getInterfaces()[0]); componentDefinition.setTypeName(clazz.getName()); if (componentMap.get(componentDefinition.getImplClazz()) != null) { throw new Exception("已存在雷同的实现类" + componentDefinition.getImplClazz().getName()); } componentMap.put(componentDefinition.getImplClazz(), componentDefinition); }  /** * 解决controller的属性,主动注入值, 返回该类的一个实例 */ private Object dealClassField(Class clazz) { Field[] fields = clazz.getDeclaredFields(); Object instance = null; try { instance = clazz.newInstance(); } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } for(Field field : fields) { if (field.isAnnotationPresent(XxgAutoWired.class)) { // 给有XxgAutoWired注解的属性,主动注入值 field.setAccessible(true); try { ComponentDefinition componentDefinition = componentMap.get(field.getType()); if (componentDefinition != null) { // 解决@XxgComponent 的主动注入 field.set(instance, dealClassField(componentDefinition.getTypeClazz())); } } catch (Exception e) { e.printStackTrace(); } } } return instance; }

5.调用办法时,传递扫描时存入的实例

DispatcherServlet中,当获取到申请执行的办法,以及拆卸好参数之后,调用该办法时,传递创立好的实例

try {  Object result = methodDefinition.getMethod().invoke(  methodDefinition.getParentInstance(), // 所属类的实例  params.toArray());  sendResponse(result, req, resp);} catch (IllegalAccessException | InvocationTargetException e) {  e.printStackTrace();  sendResponse(e.getMessage(), req, resp);}

后续

真正的@AutoWired太强大了,能够用在属性上,还能够用在办法上等,博主就不再深究了。

下文博主将想法设法简略实现dao层的动静代理,让业务逻辑与sql拆散。