分析balde源码,查看Web工程处理Ioc注入的背后的过程,ThreadLocal 使用保存线程所有的request and respond,

来源:互联网 发布:淘宝会员卡图片 编辑:程序博客网 时间:2024/06/05 03:18

查看blade源码,分析IOC依赖注入 IocApplication

blade是一个轻量级的JavaWeb框架,进行嵌入Jetty开发的,其实不管是否嵌入开发道理都是差不多的,至于Jetty这个怎么实现的,没有看过源码,难度估计有点大,有时间慢慢的静下心来看看,这里说的嵌入了Jeety启动服务之前在Jeety中注入了一个Listener,这个Listener和我们在原始的Web工程的原理其实是一样的,只是他们给我们规范了添加的格式的方式,我们自己写的时候,可以按照自己的方式处理自己的代码的逻辑。服务器启动的时候,我们处理IOC的逻辑也将在这里开始,设置我么你的根路径,IOC的扫描逻辑,这些就是我们学习的意义,更加的了解这些逻辑,自己即使使用其他的MVC框架也是一样的道理。

    webAppContext.addEventListener(new BladeInitListener());

看看这个Listener简单的结构

import javax.servlet.ServletContext;import javax.servlet.ServletContextEvent;import javax.servlet.ServletContextListener;import javax.servlet.http.HttpSessionEvent;import javax.servlet.http.HttpSessionListener;import static com.blade.Blade.$;/** * Blade Web Context Listener */public class BladeInitListener implements ServletContextListener, HttpSessionListener {    @Override    public void sessionCreated(HttpSessionEvent event) {        int timeout = $().config().getInt("server.timeout", 15);        event.getSession().setMaxInactiveInterval(timeout * 60);    }    @Override    public void contextInitialized(ServletContextEvent sce) {    }    @Override    public void contextDestroyed(ServletContextEvent sce) {        WebContextHolder.destroy();    }    @Override    public void sessionDestroyed(HttpSessionEvent event) {    }}

这里面的WebContextHolder处理是保存线程所有的Request和Response,有原始的HttpServletRequest 进行组合封装,在客户端进行请求的时候进行拦截到将这两个变量保存下来,在任何的地方都是可以访问的。平时我们处理的时候也是可以这样去处理的,非常的方便,实用。

public class WebContextHolder {    /**     * BladeWebContext object for the current thread     */    private static final ThreadLocal<WebContextHolder> ctx = new ThreadLocal<>();    //这个组合了我们的HttpServletRequest    private Request request;    /**     * Response     */    private Response response;    private WebContextHolder() {    }    public static WebContextHolder me() {        return ctx.get();    }    public static void init(Request request, Response response) {        WebContextHolder bladeWebContext = new WebContextHolder();        bladeWebContext.request = request;        bladeWebContext.response = response;        ctx.set(bladeWebContext);    }    /**     * 移除当前线程的Request、Response对象     */    public static void remove() {        ctx.remove();    }    public static Request request() {        return me().request;    }    public static Response response() {        return me().response;    }    public static Session session() {        return request().session();    }    public static ServletContext servletContext() {        return request().raw().getServletContext();    }    public static void destroy() {        ctx.remove();    }}

好像扯歪了,好吧!回来我们的主要的是IOC

处理IOC就是注入依赖,我们要得到依赖对象的实例,注入类的实例,所以一般的步骤是什么?反正不管,就是使用了反射哈哈,非常强大的工具,具体步骤如下。

  1. 配置文件,我们需要扫描包的位置在哪里com.xxx.contorl,这个就是举个例子
  2. 然后根据包名 String packageDirName = packageName.replace(‘.’, ‘/’);得到包的Dir路径。根据这个我们可以获得当前文件路径的URL,可以获得当前路径下的所有URL的枚举。 Enumeration dirs = this.getClass().getClassLoader().getResources(packageDirName);
  3. 获取了URL这个是文件协议+路径的地址,这样我们可以一个个的枚举得到文件的物理路径信息,比如:String filePath = URLDecoder.decode(url.getFile(), “UTF-8”);
  4. 找的了文件的路径,我们就可以创建文件File dir = new File(packagePath);
  5. 这里就可以递归的获取当前文件夹下面的所有的文件啊,对了我们可以过滤下文件只有当前文件下的文件夹和.class才是我们选择的范围哦
  6. 当我们遍历到当前不是文件的夹的时候就可以处理啦,因为获取到了file的实例,我们可以获取到文件的名称,每次递归的时候我们把包的名称也是传递下去(packageName + “.” + file.getName()),还有当前文件的绝对路径(file.getAbsolutePath()),通过这个我们又去创建文件,然后过滤哦。
  7. 上面那一步我们得到了当前类在项目中的包名称+类名(稍微处理一下),这样就可以反射到该类的Class
    public class ClassInfo {        private String className;        private Class<?> clazz;        public ClassInfo(String className) {            this.className = className;        }        public ClassInfo(Class<?> clazz) {            this.clazz = clazz;            this.className = clazz.getName();        }        public ClassInfo(String className, Class<?> clazz) {            this.clazz = clazz;            this.className = className;        }        public String getClassName() {            return className;        }        public Class<?> getClazz() {            return clazz;        }        public Object newInstance() {            try {                return clazz.newInstance();            } catch (Exception e) {                throw new RuntimeException(e);            }        }    }

就如上面讲的那样,我们不断的递归就可以收集了一个Set的集合哦。
———————————————————————————————————————————————————————————————————————————————

收集到的包集合->ClassInfo集合->一步步的遍历——>Class中的方法

我们知道的是,我们现在写程序都喜欢使用注解,IOC等等都是使用注解去处理,自动化的给我们处理了很多的麻烦事。简单的方便啊!我们处理完了Class的集合还的需要去处理CLass上面的注解。有主要集中Controller,Compent,Service,RestController,Intercept等等

  • 判断当前类的信息,接口和抽象类不要 ( !clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers()) 根据返回值判断.
  • 看看返回值中是否为NULL 然后进行相应的处理哦,就代表时候有注解在上面
    Service service = clazz.getAnnotation(Service.class);    Controller controller = clazz.getAnnotation(Controller.class);    RestController restController = clazz.getAnnotation(RestController.class);    Component component = clazz.getAnnotation(Component.class);    @Target(ElementType.TYPE)    @Retention(RetentionPolicy.RUNTIME)    @Documented    public @interface Component {        String value() default "";    }
  • 这里主要是Compent讲解,这个比较简单.既然都说了讲解IOC容器说白了就是一个Map吧,哈哈!SimpleIoc 组合了HashMap,这个并不需要做并发处理
public class SimpleIoc implements Ioc {    private final Map<String, BeanDefine> pool = new HashMap<>(32);    public void addBean(Object bean) {        addBean(bean.getClass().getName(), bean);    }    public void addBean(Class<?> beanClass, Object bean) {        Assert.notNull(beanClass);        addBean(beanClass.getName(), bean);    }    public void addBean(String name, Object bean) {        Assert.notNull(bean);        BeanDefine beanDefine = new BeanDefine(bean);        addBean(name, beanDefine);        // add interface        Class<?>[] interfaces = beanDefine.getType().getInterfaces();        if (interfaces.length > 0) {            for (Class<?> interfaceClazz : interfaces) {                this.addBean(interfaceClazz.getName(), beanDefine);            }        }    }    /**     * Register @Component marked objects     */    public Object addBean(Class<?> type, boolean singleton) {        Assert.notNull(type);        return addBean(type.getName(), type, singleton);    }    public Object addBean(String name, Class<?> beanClass, boolean singleton) {        Assert.notNull(name);        Assert.notNull(beanClass);        Assert.isFalse(beanClass.isInterface(), "Must not be interface: %s", beanClass.getName());        Assert.isFalse(Modifier.isAbstract(beanClass.getModifiers()), "Must not be abstract class: %s", beanClass.getName());//        LOGGER.debug("addBean: {} = {}", name, beanClass.getName());        BeanDefine beanDefine = this.getBeanDefine(beanClass, singleton);        if (pool.put(name, beanDefine) != null) {            LOGGER.warn("Duplicated Bean: {}", name);        }        // add interface        Class<?>[] interfaces = beanClass.getInterfaces();        if (interfaces.length > 0) {            for (Class<?> interfaceClazz : interfaces) {                if (null != this.getBean(interfaceClazz)) {                    break;                }                this.addBean(interfaceClazz.getName(), beanDefine);            }        }        return beanDefine.getBean();    }}

BeanDefine 这个就是简单的对于这个进行封装。

public class BeanDefine {    private Object bean;    private Class<?> type;    private boolean isSignle;    public BeanDefine(Object bean) {        this(bean, bean.getClass());    }    public BeanDefine(Object bean, Class<?> type) {        this.bean = bean;        this.type = type;        this.isSignle = true;    }    public BeanDefine(Object bean, Class<?> type, boolean isSingle) {        this.bean = bean;        this.type = type;        this.isSignle = isSingle;    }    public Object getBean() {        return bean;    }    public void setBean(Object bean) {        this.bean = bean;    }    public Class<?> getType() {        return type;    }    public void setType(Class<?> type) {        this.type = type;    }    public boolean isSignle() {        return isSignle;    }    public void setSignle(boolean isSignle) {        this.isSignle = isSignle;    }
  • 看了源码发现我们在定义Compent上定义的值无效的,这里没有进行处理仅仅根据当前类的包的名称进行定义的,没有去管理这个值。
 Component component = clazz.getAnnotation(Component.class); 看到没有这里没有去处理这个的值哦!if (null != service || null != component) {        ioc.addBean(clazz);    }

收集到的包集合->ClassInfo集合——>Class中的方法->SimpleIoc中的Map

现在我们该往里面注入注解存在的Object吧!这些注入进去的Service等等,之前我们在扫描包的时候都是得到实例了的,遍历一遍每个Class中的定义的Field然后注入就好了.

 List<BeanDefine> beanDefines = ioc.getBeanDefines();//得到IOC-Map中的值的部分if (null != beanDefines) {    beanDefines.forEach(b -> IocKit.injection(ioc, b));}//这里就是遍历处理,对于每一个private XXXX xxx;这种类注入哈哈!

BeanDefine中拥有Class< ?>,Object,Single等等信息。IocKit就是Ioc的工具包,将ioc传递进去不就是通过b的包名称获取实例变量的节奏?然后注入到Filed,大概就是这个意思吧,慢慢的分析源码。
进入这个方法:

     public static void injection(Ioc ioc, BeanDefine beanDefine) {            ClassDefine classDefine = ClassDefine.create(beanDefine.getType());            //对于Class进行封装            List<FieldInjector> fieldInjectors = IocKit.getInjectFields(ioc, classDefine);            Object bean = beanDefine.getBean();            for (FieldInjector fieldInjector : fieldInjectors) {                fieldInjector.injection(bean);            }        }

看看 ClassDefine

在说这个源码的时候,这里有很多的封装,将CLass对象进行了包装,能够很实用。

import java.lang.annotation.Annotation;import java.lang.reflect.Field;import java.lang.reflect.Modifier;import java.util.ArrayList;import java.util.Collections;import java.util.List;import java.util.concurrent.ConcurrentHashMap;public final class ClassDefine {    private static final ConcurrentHashMap<Class<?>, ClassDefine> pool = new ConcurrentHashMap<Class<?>, ClassDefine>(128);    private final Class<?> clazz;    private ClassDefine(Class<?> type) {        this.clazz = type;    }    public static ClassDefine create(Class<?> clazz){        ClassDefine classDefine = pool.get(clazz);        if (classDefine == null) {            classDefine = new ClassDefine(clazz);            ClassDefine old = pool.putIfAbsent(clazz, classDefine);            if (old != null) {                classDefine = old;            }        }        return classDefine;    }    @SuppressWarnings("unchecked")    public <T> Class<T> getType() {        return (Class<T>) clazz;    }    public String getName() {        return clazz.getName();    }    public String getSimpleName() {        return clazz.getSimpleName();    }    public ClassDefine getSuperKlass() {        Class<?> superKlass = clazz.getSuperclass();        return (superKlass == null) ? null : ClassDefine.create(superKlass);    }    public List<ClassDefine> getInterfaces() {        Class<?>[] interfaces = clazz.getInterfaces();        if (interfaces.length == 0) {            return Collections.emptyList();        }        List<ClassDefine> results = new ArrayList<ClassDefine>(interfaces.length);        for (Class<?> intf : interfaces) {            results.add(ClassDefine.create(intf));        }        return results;    }    // ------------------------------------------------------------------    public Annotation[] getAnnotations() {        return clazz.getAnnotations();    }    public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {        return clazz.getAnnotation(annotationClass);    }    public <T extends Annotation> boolean isAnnotationPresent(Class<T> annotationClass) {        return clazz.isAnnotationPresent(annotationClass);    }    public Field[] getDeclaredFields() {        return clazz.getDeclaredFields();    }    // ------------------------------------------------------------------    public int getModifiers() {        return clazz.getModifiers();    }    public boolean isInterface() {        return Modifier.isInterface(getModifiers());    }    public boolean isAbstract() {        return Modifier.isAbstract(getModifiers());    }    public boolean isStatic() {        return Modifier.isStatic(getModifiers());    }    public boolean isPrivate() {        return Modifier.isPrivate(getModifiers());    }    public boolean isProtected() {        return Modifier.isProtected(getModifiers());    }    public boolean isPublic() {        return Modifier.isPublic(getModifiers());    }}

List< FieldInjector> fieldInjectors = IocKit.getInjectFields(ioc, classDefine); 看看定义的FileInJector

这个定义很简单的,就是将我们过滤过的Field(需要进行注入的Field抓出来),getInjectFields就是这样处理的啊,看看上面有没有某个注解,有的话装到List中去。

public class FieldInjector implements Injector {    private Ioc ioc;    private Field field;    public FieldInjector(Ioc ioc, Field field) {        this.ioc = ioc;        this.field = field;    }    @Override    public void injection(Object bean) {        try {            Class<?> fieldType = field.getType();            Object value = ioc.getBean(fieldType);            if (value == null) {                throw new IllegalStateException("Can't inject bean: " + fieldType.getName() + " for field: " + field);            }            field.setAccessible(true);//可访问性            field.set(bean, value);//当前类的实例变量,当前field的值        } catch (Exception e) {            throw new RuntimeException(e);        }    }}

将满足某个注解的留下来

 public static List<FieldInjector> getInjectFields(Ioc ioc, ClassDefine classDefine) {        List<FieldInjector> injectors = new ArrayList<FieldInjector>(8);        for (Field field : classDefine.getDeclaredFields()) {            for (Annotation annotation : field.getAnnotations()) {                InjectWith with = annotation.annotationType().getAnnotation(InjectWith.class);                if (with != null) {                    injectors.add(new FieldInjector(ioc, field));                }            }        }        if (injectors.size() == 0) {            return Collections.emptyList();        }        return injectors;    }

再来看看

    public static void injection(Ioc ioc, BeanDefine beanDefine) {        ClassDefine classDefine = ClassDefine.create(beanDefine.getType());        List<FieldInjector> fieldInjectors = IocKit.getInjectFields(ioc, classDefine);        Object bean = beanDefine.getBean();        //便利所有需要注入的field的封装,然后注入当前类的实例变量,搞定        for (FieldInjector fieldInjector : fieldInjectors) {            fieldInjector.injection(bean);        }    }

大工告成,基于注解的IOC

0 0
原创粉丝点击