Spring源碼學(xué)習(xí)

Spring用了挺久了,但是Spring源碼一直不得其精髓,后來(lái)在B站上找視頻,看到個(gè)手寫一個(gè)簡(jiǎn)易的Spring,以此加深對(duì)Spring的理解。

Bean的生命周期

一個(gè)Spring容器的開(kāi)始是從創(chuàng)建ApplicationContext開(kāi)始的,然后通過(guò)ApplicationContext.getBean("beanName")創(chuàng)建一個(gè)實(shí)例Bean。

ApplicationContext applicationContext = new ApplicationContext(AppConfig.class);
System.out.println(applicationContext.getBean("testService"));

所以需要在ApplicationContext的構(gòu)造方法里面實(shí)現(xiàn)以下幾個(gè)點(diǎn):

  1. 從AppConfig類中獲取ComponentScan注解的參數(shù),這個(gè)參數(shù)就是表示我要到哪些包下面找類;
  2. 根據(jù)1步驟找到的絕對(duì)路徑,掃路徑下的所有文件,包含Component注解的類全部撈出來(lái)解析;
  3. 如果Component有參數(shù),就以參數(shù)為Bean名稱,沒(méi)有就小寫類名首字母。解析類的特征存儲(chǔ)進(jìn)BeanDefinition對(duì)象封裝起來(lái),并且存放到BeanDefinitionMap中,方便后續(xù)處理和創(chuàng)建Bean;
  4. 把BeanDefinitionMap里的所有標(biāo)注為單例的BeanDefinition撈出來(lái)先創(chuàng)建好單例Bean,創(chuàng)建好單例Bean后存儲(chǔ)在單例池里面,這里的單例池用的還是ConcurrentHashMap
    下面就是簡(jiǎn)易的ApplicationContext實(shí)現(xiàn):
public ApplicationContext(Class className) {
    this.className = className;
    // 我們拿到配置類的名稱之后,就要去配置類里面拿信息,第一個(gè)要拿的,就是配置類可以掃哪些包,即獲取ComponentScan的信息
    if (className.isAnnotationPresent(ComponentScan.class)) {
        // 判斷一下有沒(méi)有ComponentScan的注解,有就拿出來(lái)
        ComponentScan componentScan = (ComponentScan) className.getAnnotation(ComponentScan.class);
        // 拿出配置的參數(shù)值,就是com.my.code.service這個(gè)值
        String path = componentScan.value();
        path = path.replace(".", "/");
        // 根據(jù)相對(duì)路徑找絕對(duì)路徑
        ClassLoader classLoader = ApplicationContext.class.getClassLoader();
        URL resource = classLoader.getResource(path);
        File file = new File(resource.getFile());
        if (file.isDirectory()) {
            // 判斷一下是不是文件夾
            File[] files = file.listFiles();
            for (File f : files) {
                String fileName = f.getAbsolutePath();
                if (fileName.endsWith(".class")) {
                    // 判斷這個(gè)類是不是有Component注解,用反射;先將絕對(duì)路徑換成相對(duì)路徑
                    String classPathName = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
                    classPathName = classPathName.replace("\\", ".");
                    try {
                        Class<?> clazz = classLoader.loadClass(classPathName);
                        // 獲取到類之后,判斷是否有Component注解
                        if (clazz.isAnnotationPresent(Component.class)) {
                            Component component = clazz.getAnnotation(Component.class);
                            String beanName = component.value();
                            if (beanName.equals("")) {
                                // 如果不寫Component的參數(shù),默認(rèn)是類名的首字母小寫
                                beanName = Introspector.decapitalize(clazz.getSimpleName());
                            }
                            // 有這個(gè)注解,我們不直接創(chuàng)建Bean,而是先創(chuàng)建BeanDefinition
                            BeanDefinition beanDefinition = new BeanDefinition();
                            if (clazz.isAnnotationPresent(Scope.class)) {
                                Scope scopeAnnotation = clazz.getAnnotation(Scope.class);
                                beanDefinition.setScope(scopeAnnotation.value());
                            } else {
                                beanDefinition.setScope("singleton");
                            }
                            beanDefinition.setType(clazz);
                            beanDefinitionMap.put(beanName, beanDefinition);
                        }
                    } catch (ClassNotFoundException e) {
                        System.err.println("反射獲取.class文件出錯(cuò)");
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    // 開(kāi)始創(chuàng)建單例對(duì)象
    for (String beanName : beanDefinitionMap.keySet()) {
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (beanDefinition.getScope().equals("singleton")) {
            Object bean = createBean(beanName, beanDefinition);
            singletonObjectsMap.put(beanName, bean);
        }
    }

}

可以直接根據(jù)全限定類名從類加載器里面獲取類,然后用isAnnotationPresent方法來(lái)判斷是否有某個(gè)注解


以上就是完成了包掃描,加載好了Bean的相關(guān)信息,單例Bean也已經(jīng)創(chuàng)建好了。只需要調(diào)用getBean就能夠獲取了。這里只考慮是否是單例Bean而討論。實(shí)現(xiàn)思路還是很直接,拿BeanDefinitionMap里的信息,判斷是單例還是多例,單例就從單例池里取,沒(méi)有重新創(chuàng)建,有就拿出返回;多例就直接創(chuàng)建一個(gè)返回回去。這里的創(chuàng)建Bean有點(diǎn)復(fù)雜,所以單獨(dú)拎出去寫一個(gè)新方法。getBean實(shí)現(xiàn)如下:

public Object getBean(String beanName) {
    BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
    if (beanDefinition == null) {
        throw new NullPointerException();
    } else {
        String scope = beanDefinition.getScope();
        if (scope.equals("singleton")) {
            Object bean = singletonObjectsMap.get(beanName);
            if (bean == null) {
                bean = createBean(beanName, beanDefinition);
                assert bean != null;
                singletonObjectsMap.put(beanName, bean);
            }
            return bean;
        } else {
            return createBean(beanName, beanDefinition);
        }
    }
}

private Object createBean(String beanName, BeanDefinition beanDefinition) {

    Class<?> clazz = beanDefinition.getType();
    try {
        Object instance = clazz.getConstructor().newInstance();
        // 對(duì)instance對(duì)象里面的屬性自動(dòng)配置,找有Autowired注解的屬性
        for (Field declaredField : clazz.getDeclaredFields()) {
            if (declaredField.isAnnotationPresent(Autowired.class)) {
                declaredField.setAccessible(true);
                declaredField.set(instance, getBean(declaredField.getName()));
            }
        }
        return instance;
    } catch (InstantiationException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
        e.printStackTrace();
    }

    return null;
}

這是創(chuàng)建Bean的實(shí)現(xiàn),里面涉及到Autowired的自動(dòng)注入注解,還有一個(gè)循環(huán)依賴的解決。


AOP的實(shí)現(xiàn):先創(chuàng)建一個(gè)BeanPostProcessor,里面搞個(gè)后置處理器,在后置處理器里面創(chuàng)建一個(gè)代理類,替換原先的bean并且返回。這里JDK代理只能代理接口。

@Override
public Object postProcessAfterInitialization(String beanName, Object bean) {

    // AOP的核心,就是在后置處理器里面創(chuàng)建了一個(gè)新的代理對(duì)象,這個(gè)代理對(duì)象不是原來(lái)的bean,而是在原有bean上加工過(guò)的對(duì)象
    Object proxyInstance = Proxy.newProxyInstance(TestBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("加入操作XXXX");
            return method.invoke(bean, args);
        }
    });

    return proxyInstance;
}

AOP的本質(zhì)就是在創(chuàng)建這個(gè)Bean的時(shí)候,在后置處理器里面,創(chuàng)建一個(gè)同接口的實(shí)現(xiàn)類,這個(gè)實(shí)現(xiàn)類有自己加的新功能,也有原先的方法,所有的方法都被植入新操作,并以代理類代替了原先的實(shí)現(xiàn)類。


綜上我們可以總結(jié)如下的Bean的生命周期:
ApplicationContext的構(gòu)造方法里面,開(kāi)始掃@Component注解的類。


流程圖.jpg

Spring事務(wù)底層原理

事務(wù)開(kāi)啟會(huì)做兩件事,一件是Spring自己建立一個(gè)JDBC連接,然后就是關(guān)閉自動(dòng)提交。如果將提交和連接交給jdbcTemplate,那么就會(huì)出現(xiàn)jdbctemplate執(zhí)行一個(gè)sql就提交一個(gè),遇到異常拋出時(shí),sql都已經(jīng)提交了,回滾不回來(lái)了。所以需要spring自己管理一個(gè)連接。
spring事務(wù)失效的原理

@Transactional
public void test(){
    jdbcTemplate.execute("insert into t1 values(1,1,1)");
    a();
}
@Transactional
public void a(){
    jdbcTemplate.execute("insert into t1 values(2,2,2)");
}

當(dāng)調(diào)用Spring里的Bean(testService)的test()方法時(shí),test()的@Transactional是會(huì)生效的,但是test()里面的a()方法的事務(wù)注解是不會(huì)生效的。
原因:在產(chǎn)生代理對(duì)象替代原普通對(duì)象時(shí),普通對(duì)象里面的自動(dòng)注入的屬性在代理對(duì)象里面是沒(méi)有用的,也就是自動(dòng)注入注不到代理對(duì)象里面,CGlib的解決方法是在代理對(duì)象里面加一個(gè)同類型的target對(duì)象,這個(gè)target就是上面提到的普通對(duì)象,也可以認(rèn)為是被代理的對(duì)象。這個(gè)時(shí)候再執(zhí)行普通對(duì)象里面的test()方法和a()方法。于是問(wèn)題就出現(xiàn)了:test()方法的事務(wù)注解是被解析過(guò)的并且在代理對(duì)象里是有事務(wù)的操作,所以不會(huì)失效,a()方法就不會(huì)了,他沒(méi)有被事務(wù)解析過(guò),調(diào)用的時(shí)候是調(diào)的target這個(gè)普通對(duì)象,你寫的@Transactional他理都不理,等于沒(méi)寫。解決方法就是在這個(gè)類里面再自動(dòng)注入自己,spring會(huì)幫忙解決循環(huán)依賴的問(wèn)題。


三級(jí)緩存

一級(jí)緩存:?jiǎn)卫?,存放已?jīng)完成初始化后的完整Bean;
二級(jí)緩存:因?yàn)槌霈F(xiàn)循環(huán)依賴,而不得不提前進(jìn)行AOP產(chǎn)生代理對(duì)象,存放在二級(jí)緩存中;二級(jí)緩存是為了保證這個(gè)代理對(duì)象單例唯一;
三級(jí)緩存:如果二級(jí)緩存中沒(méi)有找到提前出現(xiàn)的代理對(duì)象,就會(huì)將執(zhí)行反射創(chuàng)建代理對(duì)象的操作封裝進(jìn)函數(shù)式接口中,存放在三級(jí)緩存里面;

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容