換種眼光看Spring之bean是怎麼誕生的(一)

   Java的世界裏到處存在了對象,有時候換一種眼光每每會給本身帶來與以前大不同的理解。java

   一個對象的出現離不開字節碼,拿classforname來說,classforname("...") 就像問你 狗 ,在你腦子裏立馬就出現了狗的樣子,這就是狗的類,拉布拉多就出現拉布拉多狗的類,就相似於一個加載的過程,想要獲得私有的方法,私有的類,好比拉布拉多和其餘種類狗的區別,私有的用setAccessible設置爲true,這樣就能夠調用,這其中加載的過程一眼就看到了父類也會加載進去,這就是類的初始化。編程

    而這裏還要說的是classloader是從BootStrapClassLoader開始,到ExtClassLoader再到AppClassLoader,再到本身的ClassLoader。不少人看到這些有的會很明白,一樣的也有不少大頭的,其實拿咱們自身來講,咱們要生存,首先咱們本身得先活着,這就要求咱們有血有肉,各個器官各類無缺,BootStrapClassLoader不就是相似於幹這事的麼,它主要用於加載一些Java自帶的核心類,是不能被替換掉的,由jvm內核實現,只有加載了這些最核心的內容,纔會有後面classloader的存在機會。數組

      在有了基本的器官以後,做爲人,咱們要生存還須要一些本能,呼吸,眨眼,條件反射(先天的),這個就相似於ExtClassLoader,其是加載在jre/lib/ext下的jar包,固然,咱們也能夠把本身的jar放到裏面去,經過這個來加載,畢竟咱們的好多先天的條件反射也是慢慢進化來的,是否是很形象jvm

     做爲人,咱們能夠學習到不少技能,認識不少事物,每一個人的所見都不同,每一個人都是一個獨立的虛擬機,這裏就談到了AppClassLoader,它加載的是classpath下面的內容,默認狀況都由其加載。ide

    固然,凡事總有特殊,用戶自定義的classloader要加載的內容不在上面的classpath範圍內,怎麼加載徹底本身去定義,就像你從未見過某一種東西,你怎麼去知道那是什麼,要不就不打算認識說不知道,要不就給其編個名字安上!函數

上面說了一些class字節碼的加載順序,而後就是對其進行解析校驗,最後是初始化,既然說到了這裏,那就提下,初始化的時候會調用Class對象自身的構造函數,這裏static塊實際上是個坑,當多個線程同時訪問這個類時,必須等static塊執行完,要不會發生阻塞,因此不適合編寫大量的業務尤爲是i/o邏輯業務學習

    在classloader源碼裏發現了以下代碼:ui

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

經過傳入byte[]數組就能夠動態的加載Class類,這就牽扯到了字節碼增強。spa

     終於和上一篇接着了,只要接觸過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動態代理的很差處也是顯而易見的,必須實現接口,只能調用接口對應的方法,實例的其餘方法沒法訪問,從這點也啓示了咱們面向接口編程和多態的用處。

   暫時先敲這麼多吧,剩下的下篇接着說

相關文章
相關標籤/搜索