zoukankan      html  css  js  c++  java
  • 换种眼光看Spring之bean是怎么诞生的(一)

       Java的世界里处处存在了对象,有时候换一种眼光往往会给自己带来与之前大不一样的理解。

       一个对象的出现离不开字节码,拿classforname来讲,classforname("...") 就像问你 狗 ,在你脑子里立马就出现了狗的样子,这就是狗的类,拉布拉多就出现拉布拉多狗的类,就类似于一个加载的过程,想要得到私有的方法,私有的类,比如拉布拉多和其他种类狗的区别,私有的用setAccessible设置为true,这样就可以调用,这其中加载的过程一眼就看到了父类也会加载进去,这就是类的初始化。

        而这里还要说的是classloader是从BootStrapClassLoader开始,到ExtClassLoader再到AppClassLoader,再到自己的ClassLoader。很多人看到这些有的会很明白,同样的也有很多大头的,其实拿我们自身来说,我们要生存,首先我们自己得先活着,这就要求我们有血有肉,各个器官各种完好,BootStrapClassLoader不就是类似于干这事的么,它主要用于加载一些Java自带的核心类,是不能被替换掉的,由jvm内核实现,只有加载了这些最核心的内容,才会有后面classloader的存在机会。

          在有了基本的器官之后,作为人,我们要生存还需要一些本能,呼吸,眨眼,条件反射(先天的),这个就类似于ExtClassLoader,其是加载在jre/lib/ext下的jar包,当然,我们也可以把自己的jar放到里面去,通过这个来加载,毕竟我们的好多先天的条件反射也是慢慢进化来的,是不是很形象

         作为人,我们可以学习到很多技能,认识很多事物,每个人的所见都不一样,每个人都是一个独立的虚拟机,这里就谈到了AppClassLoader,它加载的是classpath下面的内容,默认情况都由其加载。

        当然,凡事总有特殊,用户自定义的classloader要加载的内容不在上面的classpath范围内,怎么加载完全自己去定义,就像你从未见过某一种东西,你怎么去知道那是什么,要不就不打算认识说不知道,要不就给其编个名字安上!

    上面说了一些class字节码的加载顺序,然后就是对其进行解析校验,最后是初始化,既然说到了这里,那就提下,初始化的时候会调用Class对象自身的构造函数,这里static块其实是个坑,当多个线程同时访问这个类时,必须等static块执行完,要不会发生阻塞,所以不适合编写大量的业务尤其是i/o逻辑业务

        在classloader源码里发现了如下代码:

    protected final Class<?> defineClass(String name, byte[] b, int off, int len)
            throws ClassFormatError
        {
            return defineClass(name, b, off, len, null);
        }

    通过传入byte[]数组就可以动态的加载Class类,这就牵扯到了字节码加强。

         终于和上一篇接着了,只要接触过Spring都知道,AOP,动态代理,追根究底都是字节码增强,所以也免不了俗,先说动态代理,看过很多这方面的文章,说说自己的理解,首先,jdk的动态代理,有点类似于专卖店,我拿房地产中介来说可能更好理解一些,一个共同的接口,卖房,房主实现了卖方的接口,房产中介也实现了卖方的接口,然后要有一套卖家卖房的处理流程也就是处理类handler,这个处理类的内部的invoke方法,如下图所示:

    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable;
    }

    包含了代理对象,代理方法,方法参数对象,方法内部由被代理的对象来实现,其实就是包含了中介,卖房扯的过程,方法里面由卖家来实现

     java.lang.reflect.Proxy下的newProxyInstance()方法如下所示

     @CallerSensitive
        public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {
            Objects.requireNonNull(h);
    
            final Class<?>[] intfs = interfaces.clone();
            final SecurityManager sm = System.getSecurityManager();
            if (sm != null) {
                checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
            }
    
            /*
             * Look up or generate the designated proxy class.
             */
            Class<?> cl = getProxyClass0(loader, intfs);
    
            /*
             * Invoke its constructor with the designated invocation handler.
             */
            try {
                if (sm != null) {
                    checkNewProxyPermission(Reflection.getCallerClass(), cl);
                }
    
                final Constructor<?> cons = cl.getConstructor(constructorParams);
                final InvocationHandler ih = h;
                if (!Modifier.isPublic(cl.getModifiers())) {
                    AccessController.doPrivileged(new PrivilegedAction<Void>() {
                        public Void run() {
                            cons.setAccessible(true);
                            return null;
                        }
                    });
                }
                return cons.newInstance(new Object[]{h});
            } catch (IllegalAccessException|InstantiationException e) {
                throw new InternalError(e.toString(), e);
            } catch (InvocationTargetException e) {
                Throwable t = e.getCause();
                if (t instanceof RuntimeException) {
                    throw (RuntimeException) t;
                } else {
                    throw new InternalError(t.toString(), t);
                }
            } catch (NoSuchMethodException e) {
                throw new InternalError(e.toString(), e);
            }
        }
    View Code

    说白了就是想得到一个代理,就需要卖家的字节码,卖房的接口,和那个处理类handler,jdk动态代理的不好处也是显而易见的,必须实现接口,只能调用接口对应的方法,实例的其他方法无法访问,从这点也启示了我们面向接口编程和多态的用处。

       暂时先敲这么多吧,剩下的下篇接着说

  • 相关阅读:
    ‘Host’ is not allowed to connect to this mysql server
    centos7安装mysql
    further configuration avilable 不见了
    Dynamic Web Module 3.0 requires Java 1.6 or newer
    hadoop启动 datanode的live node为0
    ssh远程访问失败 Centos7
    Linux 下的各种环境安装
    Centos7 安装 python2.7
    安装scala
    Centos7 安装 jdk 1.8
  • 原文地址:https://www.cnblogs.com/yinchen/p/5343844.html
Copyright © 2011-2022 走看看