spring源码刨析总结
spring源碼刨析筆記
1.概述
spring就是 spring Framework
Ioc Inversion of Control(控制反轉(zhuǎn)/反轉(zhuǎn)控制)
DI Dependancy Injection(依賴注入)
Aop Aspect oriented Programming 面向切面編程(OOP的延續(xù))
2.Ioc與DI
Ioc與Aop的區(qū)別
Ioc在對(duì)象角度將對(duì)象實(shí)例化以及管理的權(quán)力交給了容器
DI在容器角度將對(duì)象依賴注入到其他對(duì)象
3.Aop
3.1橫切邏輯代碼
多個(gè)縱向流程中出現(xiàn)相同子流程代碼
出現(xiàn)的問題:
橫切代碼重復(fù)問題,與業(yè)務(wù)邏輯代碼混在一起,臃腫,維護(hù)不方便
Aop不改變業(yè)務(wù)邏輯情況下,增強(qiáng)橫切邏輯代碼,根本上解耦合代碼
4.自定義的Spring框架
//將private AccountDao accountDao = new JdbcAccountDaoImpl();轉(zhuǎn)換為 private AccountDao accountDao;// 構(gòu)造函數(shù)傳值/set方法傳值public void setAccountDao(AccountDao accountDao) {this.accountDao = accountDao;}4.1思路
public class BeanFactory {//集合的定義放在類的最上面來,因?yàn)楹竺娴氖褂脮r(shí)在static靜態(tài)代碼塊中,否則在使用時(shí)集合對(duì)象會(huì)為nullstatic List<String> classNames = new ArrayList<>(); // 緩存掃描到的class全限定類名static List<String> fieldsAlreayProcessed = new ArrayList<>(); // 緩存已經(jīng)進(jìn)行過依賴注入的信息/*** 任務(wù)一:讀取解析xml,通過反射技術(shù)實(shí)例化對(duì)象并且存儲(chǔ)待用(map集合)* 任務(wù)二:對(duì)外提供獲取實(shí)例對(duì)象的接口(根據(jù)id獲取)*/private static Map<String,Object> map = new HashMap<>(); // 存儲(chǔ)對(duì)象 }1.遍歷掃描路徑
//獲取掃描包的全限定類名
<beans><component-scan base-package="com.lagou.edu"></component-scan> </beans> // 加載xmlInputStream resourceAsStream = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");// 解析xmlSAXReader saxReader = new SAXReader();Document document = saxReader.read(resourceAsStream);Element rootElement = document.getRootElement();Element scanElement = (Element) rootElement.selectSingleNode("//component-scan");String scanPackage = scanElement.attributeValue("base-package");/*** 掃描指定包下的注解*/private static void doScan(String scanPackage) {String scanPackagePath = Thread.currentThread().getContextClassLoader().getResource("").getPath() + scanPackage.replaceAll("\\.", "/");File pack = new File(scanPackagePath);File[] files = pack.listFiles();for(File file: files) {if(file.isDirectory()) { // 子package// 遞歸doScan(scanPackage + "." + file.getName()); // com.lagou.demo.controller}else if(file.getName().endsWith(".class")) {String className = scanPackage + "." + file.getName().replaceAll(".class", "");classNames.add(className);}}}2.對(duì)象實(shí)例化
/*** 通過反射實(shí)例化對(duì)象,此時(shí)暫不維護(hù)依賴注入關(guān)系*/private static void doInstance() {if (classNames.size() == 0) return;try {for (int i = 0; i < classNames.size(); i++) {String className = classNames.get(i);// 反射Class<?> aClass = Class.forName(className);// 只處理標(biāo)注了注解@MyService、@MyRepository和@MyComponent的類if (aClass.isAnnotationPresent(MyService.class)|| aClass.isAnnotationPresent(MyRepository.class)|| aClass.isAnnotationPresent(MyComponent.class)) {//獲取注解value值String beanName = null;if (aClass.isAnnotationPresent(MyService.class)) {beanName = aClass.getAnnotation(MyService.class).value();} else if (aClass.isAnnotationPresent(MyRepository.class)) {beanName = aClass.getAnnotation(MyRepository.class).value();} else if (aClass.isAnnotationPresent(MyComponent.class)) {beanName = aClass.getAnnotation(MyComponent.class).value();}// 如果指定了id,就以指定的為準(zhǔn)Object o = aClass.newInstance();if ("".equals(beanName.trim())) {beanName = lowerFirst(aClass.getSimpleName());}map.put(beanName,o);// service層往往是有接口的,面向接口開發(fā),此時(shí)再以接口名為id,放入一份對(duì)象到容器中,便于后期根據(jù)接口類型注入Class<?>[] interfaces = aClass.getInterfaces();if(interfaces != null && interfaces.length > 0) {for (int j = 0; j < interfaces.length; j++) {Class<?> anInterface = interfaces[j];// 以接口的全限定類名作為id放入map.put(anInterface.getName(), aClass.newInstance());}}} else {continue;}}} catch (Exception e) {e.printStackTrace();}}3.維護(hù)注入關(guān)系
/** 實(shí)現(xiàn)依賴注入*/private static void doAutoWired(){if(map.isEmpty()) {return;}// 遍歷ioc中所有對(duì)象,查看對(duì)象中的字段,是否有@LagouAutowired注解,如果有需要維護(hù)依賴注入關(guān)系for(Map.Entry<String,Object> entry: map.entrySet()) {try {doObjectDependancy(entry.getValue());} catch (IllegalAccessException e) {e.printStackTrace();}}}/*** A 可能依賴于 B ,B 可能依賴于 C ,C 可能又依賴于D,本方法主要維護(hù)一下嵌套依賴*/private static void doObjectDependancy(Object object) throws IllegalAccessException {Field[] declaredFields = object.getClass().getDeclaredFields();if(declaredFields == null || declaredFields.length ==0) {return;}// 遍歷判斷處理for (int i = 0; i < declaredFields.length; i++) {Field declaredField = declaredFields[i];if (!declaredField.isAnnotationPresent(MyAutowired.class)) {continue;}// 判斷當(dāng)前字段是否處理過,如果已經(jīng)處理過則continue,避免嵌套處理死循環(huán)if(fieldsAlreayProcessed.contains(object.getClass().getName() + "." + declaredField.getName())){continue;}Object dependObject = null;dependObject = map.get(declaredField.getType().getName()); // 先按照聲明的是接口去獲取,如果獲取不到再按照首字母小寫if(dependObject == null) {dependObject = map.get(lowerFirst(declaredField.getType().getSimpleName()));}// 記錄下給哪個(gè)對(duì)象的哪個(gè)屬性設(shè)置過,避免死循環(huán)fieldsAlreayProcessed.add(object.getClass().getName() + "." + declaredField.getName());// 迭代doObjectDependancy(dependObject);declaredField.setAccessible(true);declaredField.set(object,dependObject);}}4.維護(hù)事務(wù)
/** 實(shí)現(xiàn)事務(wù)管理,為添加了@MyTransactional注解的對(duì)象創(chuàng)建代理對(duì)象,并覆蓋原IOC容器中的對(duì)象*/private static void doTransactional() {ProxyFactory proxyFactory = (ProxyFactory) map.get("proxyFactory");for(Map.Entry<String,Object> entry: map.entrySet()) {String beanName = entry.getKey();Object o = entry.getValue();Class<?> aClass = entry.getValue().getClass();if(aClass.isAnnotationPresent(MyTransactional.class)) {// 需要進(jìn)行事務(wù)控制// 有實(shí)現(xiàn)接口Class<?>[] interfaces = aClass.getInterfaces();if(interfaces != null && interfaces.length > 0) {// 使用jdk動(dòng)態(tài)代理map.put(beanName,proxyFactory.getJdkProxy(o));}else{// 使用cglib動(dòng)態(tài)代理map.put(beanName,proxyFactory.getCglibProxy(o));}}}}4.2代碼
創(chuàng)建connection的時(shí)候放到同一個(gè)線程中
public class ConnectionUtils {private ThreadLocal<Connection> threadLocal = new ThreadLocal<>(); // 存儲(chǔ)當(dāng)前線程的連接/*** 從當(dāng)前線程獲取連接*/public Connection getCurrentThreadConn() throws SQLException {/*** 判斷當(dāng)前線程中是否已經(jīng)綁定連接,如果沒有綁定,需要從連接池獲取一個(gè)連接綁定到當(dāng)前線程*/Connection connection = threadLocal.get();if(connection == null) {// 從連接池拿連接并綁定到線程connection = DruidUtils.getInstance().getConnection();// 綁定到當(dāng)前線程threadLocal.set(connection);}return connection;} }5. FactoryBean 和 BeanFactory區(qū)別
BeanFactory是個(gè)bean 工廠,是一個(gè)工廠類(接口), 它負(fù)責(zé)生產(chǎn)和管理bean的一個(gè)工廠
是ioc 容器最底層的接口,是個(gè)ioc容器,是spring用來管理和裝配普通bean的ioc容器(這些bean成為普通bean)。
FactoryBean是個(gè)bean,在IOC容器的基礎(chǔ)上給Bean的實(shí)現(xiàn)加上了一個(gè)簡單工廠模式和裝飾模式,是一個(gè)可以生產(chǎn)對(duì)象和裝飾對(duì)象的工廠bean,由spring管理后,生產(chǎn)的對(duì)象是由getObject()方法決定的。
// 可以讓我們?定義Bean的創(chuàng)建過程(完成復(fù)雜Bean的定義) public interface FactoryBean<T> {@Nullable// 返回FactoryBean創(chuàng)建的Bean實(shí)例,如果isSingleton返回true,則該實(shí)例會(huì)放到Spring容器的單例對(duì)象緩存池中MapT getObject() throws Exception;@Nullable// 返回FactoryBean創(chuàng)建的Bean類型Class<?> getObjectType();// 返回作?域是否單例default boolean isSingleton() {return true;} }public class CompanyFactoryBean implements FactoryBean<Company> {@Overridepublic Company getObject() throws Exception {// 模擬創(chuàng)建復(fù)雜對(duì)象CompanyCompany company = new Company();String[] strings = companyInfo.split(",");company.setName(strings[0]);company.setAddress(strings[1]);company.setScale(Integer.parseInt(strings[2]));return company;}}6.spring的循環(huán)引用
1.構(gòu)造器注入循環(huán)依賴
2.@Autowired的依賴注入
6.1流程
①:構(gòu)造器的循環(huán)依賴。【這個(gè)Spring解決不了】
Spring是先將Bean對(duì)象實(shí)例化【依賴無參構(gòu)造函數(shù)】—>再設(shè)置對(duì)象屬性的
//一級(jí)緩存 //singletonFactories : 單例對(duì)象工廠的cache /** Cache of singleton objects: bean name --> bean instance */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256); //二級(jí)緩存 // earlySingletonObjects :提前暴光的單例對(duì)象的Cache 。【用于檢測(cè)循環(huán)引用,與singletonFactories互斥】 /** Cache of early singleton objects: bean name --> bean instance */ private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16); //三級(jí)緩存//singletonObjects:單例對(duì)象的cache /** Cache of singleton factories: bean name --> ObjectFactory */ private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16); /** Names of beans that are currently in creation. */ // 這個(gè)緩存也十分重要:它表示bean創(chuàng)建過程中都會(huì)在里面呆著~ // 它在Bean開始創(chuàng)建時(shí)放值,創(chuàng)建完成時(shí)會(huì)將其移出~ private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));/** Names of beans that have already been created at least once. */ // 當(dāng)這個(gè)Bean被創(chuàng)建完成后,會(huì)標(biāo)記為這個(gè) 注意:這里是set集合 不會(huì)重復(fù) // 至少被創(chuàng)建了一次的 都會(huì)放進(jìn)這里~~~~ private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));6.2為什么不用二級(jí)緩存要用三級(jí)緩存
可以二級(jí)緩存就可以初始化一些內(nèi)容,
在將三級(jí)緩存放入二級(jí)緩存的時(shí)候,會(huì)判斷是否有SmartInstantiationAwareBeanPostProcessor這樣的后置處理器,換句話說這里是給用戶提供接口擴(kuò)展的,所以采用了三級(jí)緩存, 特殊寫法中
6.3源代碼中的特殊寫法
//添加到三級(jí)緩存中addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));//====改寫后addSingletonFactory(beanName, new ObjectFactory<Object>() {@Overridepublic Object getObject() throws BeansException {getEarlyBeanReference(beanName, mbd, bean);} });//ObjectFactory方法public interface ObjectFactory<T> {T getObject() throws BeansException;}//addSingletonFactory方法 protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(singletonFactory, "Singleton factory must not be null");synchronized (this.singletonObjects) {if (!this.singletonObjects.containsKey(beanName)) {//添加三級(jí)緩存this.singletonFactories.put(beanName, singletonFactory);//移除二級(jí)this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}}//getEarlyBeanReference方法protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;// 這么一大段就這句話是核心,也就是當(dāng)bean要進(jìn)行提前曝光時(shí),// 給一個(gè)機(jī)會(huì),通過重寫后置處理器的getEarlyBeanReference方法,來自定義操作bean// 值得注意的是,如果提前曝光了,但是沒有被提前引用,則該后置處理器并不生效!!!// 這也正式三級(jí)緩存存在的意義,否則二級(jí)緩存就可以解決循環(huán)依賴的問題exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);}}}return exposedObject;}6.4文字版敘述流程
使用context.getBean(A.class),旨在獲取容器內(nèi)的單例A(若A不存在,就會(huì)走A這個(gè)Bean的創(chuàng)建流程),顯然初次獲取A是不存在的,因此走A的創(chuàng)建之路~
實(shí)例化A(注意此處僅僅是實(shí)例化),并將它放進(jìn)緩存(此時(shí)A已經(jīng)實(shí)例化完成,已經(jīng)可以被引用了)
初始化A:@Autowired依賴注入B(此時(shí)需要去容器內(nèi)獲取B)為了完成依賴注入B,會(huì)通過getBean(B)去容器內(nèi)找B。但此時(shí)B在容器內(nèi)不存在,就走向B的創(chuàng)建之路~
實(shí)例化B,并將其放入緩存。
初始化B,@Autowired依賴注入A(此時(shí)需要去容器內(nèi)獲取A)
此處重要:初始化B時(shí)會(huì)調(diào)用getBean(A)去容器內(nèi)找到A,上面我們已經(jīng)說過了此時(shí)候因?yàn)锳已經(jīng)實(shí)例化完成了并且放進(jìn)了緩存里,所以這個(gè)時(shí)候去看緩存里是已經(jīng)存在A的引用了的,所以getBean(A)能夠正常返回(此時(shí)B也能夠被引用了)然后調(diào)用AOP的后置處理器類:getEarlyBeanReference,拿到代理后的bean(假設(shè)此處切面滿足,要?jiǎng)?chuàng)建代理);
經(jīng)過上面的步驟后,B里面,field已經(jīng)填充ok,其中,且填充的field是代理后的A,這里命名為proxy A。
B 繼續(xù)其他的后續(xù)處理。
B初始化成功(此時(shí)已經(jīng)注入A成功了,已成功持有A的引用了),return(注意此處return相當(dāng)于是返回最上面的getBean(B)這句代碼,回到了初始化A的流程中~)。
因?yàn)锽實(shí)例已經(jīng)成功返回了,因此最終A也初始化成功
到此,B持有的已經(jīng)是初始化完成的A,A持有的也是初始化完成的B
6.5 spring的事務(wù)
1.四大特征
原子性(Atomicity)
一致性(Consistency)
隔離性(Isolation)
持久性(Durability)
2.事務(wù)的隔離級(jí)別
Serializable(串?化):可避免臟讀、不可重復(fù)讀、虛讀情況的發(fā)?。(串?化) 最?
Repeatable read(可重復(fù)讀):可避免臟讀、不可重復(fù)讀情況的發(fā)?。(幻讀有可能發(fā)?) 第?
該機(jī)制下會(huì)對(duì)要update的?進(jìn)?加鎖
Read committed(讀已提交):可避免臟讀情況發(fā)?。不可重復(fù)讀和幻讀?定會(huì)發(fā)?。 第三
Read uncommitted(讀未提交):最低級(jí)別,以上情況均?法保證。(讀未提交) 最低
注意:級(jí)別依次升?,效率依次降低
MySQL的默認(rèn)隔離級(jí)別是:REPEATABLE READ
3.事務(wù)的傳播行為
PROPAGATION_REQUIRED 如果當(dāng)前沒有事務(wù),就新建?個(gè)事務(wù),如果已經(jīng)存在?個(gè)事務(wù)中,
加?到這個(gè)事務(wù)中。這是最常?的選擇。
PROPAGATION_SUPPORTS ?持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就以?事務(wù)?式執(zhí)?。
PROPAGATION_MANDATORY 使?當(dāng)前的事務(wù),如果當(dāng)前沒有事務(wù),就拋出異常。
PROPAGATION_REQUIRES_NEW 新建事務(wù),如果當(dāng)前存在事務(wù),把當(dāng)前事務(wù)掛起。
PROPAGATION_NOT_SUPPORTED 以?事務(wù)?式執(zhí)?操作,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起。
PROPAGATION_NEVER 以?事務(wù)?式執(zhí)?,如果當(dāng)前存在事務(wù),則拋出異常。
PROPAGATION_NESTED 如果當(dāng)前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)?。如果當(dāng)前沒有事務(wù),則
執(zhí)?與PROPAGATION_REQUIRED類似的操作。
6.6資料
1.https://blog.csdn.net/chaitoudaren/article/details/104833575
2.https://zhuanlan.zhihu.com/p/84267654
3.https://blog.csdn.net/qq_36381855/article/details/79752689
java代理
1.java動(dòng)態(tài)代理
實(shí)現(xiàn)了InvocationHandler接口
public Object getJdkProxy(Object obj) {Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result = null;try{// 開啟事務(wù)(關(guān)閉事務(wù)的自動(dòng)提交)transactionManager.beginTransaction();result = method.invoke(obj,args);// 提交事務(wù)transactionManager.commit();}catch (Exception e) {e.printStackTrace();// 回滾事務(wù)transactionManager.rollback();// 拋出異常便于上層servlet捕獲throw e;}return result;}}); }2.cglib動(dòng)態(tài)代理
實(shí)現(xiàn)MethodInterceptor接口
public Object getCglibProxy(Object obj) { //創(chuàng)建Enhancer對(duì)象,類似于JDK動(dòng)態(tài)代理的Proxy類,下一步就是設(shè)置幾個(gè)參數(shù)return Enhancer.create(obj.getClass(), new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {Object result = null;try{// 開啟事務(wù)(關(guān)閉事務(wù)的自動(dòng)提交)transactionManager.beginTransaction();result = method.invoke(obj,objects);// 提交事務(wù)transactionManager.commit();}catch (Exception e) {e.printStackTrace();// 回滾事務(wù)transactionManager.rollback();// 拋出異常便于上層servlet捕獲throw e;}return result;}});}3.區(qū)別
1)JDK動(dòng)態(tài)代理只能對(duì)實(shí)現(xiàn)了接口的類生成代理,而不能針對(duì)類。
2)CGLIB是針對(duì)類實(shí)現(xiàn)代理,主要是對(duì)指定的類生成一個(gè)子類,覆蓋其中的方法,
并覆蓋其中方法實(shí)現(xiàn)增強(qiáng),但是因?yàn)椴捎玫氖抢^承,所以該類或方法最好不要聲明成final,
對(duì)于final類或方法,是無法繼承的
鏈接:https://www.jianshu.com/p/46d092bb737d
補(bǔ)充
1.ThreadLocal是什么
// 存儲(chǔ)當(dāng)前線程的連接 private ThreadLocal<Connection> threadLocal = new ThreadLocal<>();ThreadLocal 內(nèi)部維護(hù)了一個(gè) Map ,這個(gè) Map 是叫做 ThreadLocalMap 里賣弄有個(gè)Entey數(shù)組的table
ThreadLocal 適用于每個(gè)線程需要自己獨(dú)立的實(shí)例且該實(shí)例需要在多個(gè)方法中被使用,也即變量在線程間隔離而在方法或類間共享的場(chǎng)景。
ThreadLocal 適用于如下兩種場(chǎng)景
- 每個(gè)線程需要有自己單獨(dú)的實(shí)例
- 實(shí)例需要在多個(gè)方法中共享,但不希望被多線程共享
1.1源代碼刨析
總結(jié)
1.每個(gè)線程持有一個(gè)ThreadLocalMap對(duì)象==》set()方法沒有的時(shí)候會(huì)去CreateMap()
2.每個(gè)線程Thread持有一個(gè)ThreadLocalMap類型的實(shí)例內(nèi)含Entry(可以理解為每個(gè)線程Thread都持有一個(gè)Entry型的數(shù)組table)
//set方法public void set(T value) {//獲取當(dāng)前線程Thread t = Thread.currentThread();//取值ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);}//創(chuàng)建一個(gè)ThreadLocalMap方法void createMap(Thread t, T firstValue) {t.threadLocals = new ThreadLocalMap(this, firstValue);}//ThreadLocalMap方法static class ThreadLocalMap {//Entry數(shù)組private Entry[] table;//Entry對(duì)象 繼承了弱引用的接口static class Entry extends WeakReference<ThreadLocal<?>> {/** The value associated(允許) with this ThreadLocal. */Object value;Entry(ThreadLocal<?> k, Object v) {super(k);value = v;}}//ThreadLocalMap對(duì)象的實(shí)例化ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {private static final int INITIAL_CAPACITY = 16;//初始化因子為16table = new Entry[INITIAL_CAPACITY];//位運(yùn)算,結(jié)果與取模相同,計(jì)算出需要存放的位int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);table[i] = new Entry(firstKey, firstValue);size = 1;setThreshold(INITIAL_CAPACITY);//給ThreadLocalMap存值 private void set(ThreadLocal<?> key, Object value) {//獲取ThreadLocalMap的TableEntry[] tab = table;int len = tab.length;//將threadLocalHashCode進(jìn)行一個(gè)位運(yùn)算(取模)得到索引iint i = key.threadLocalHashCode & (len-1);for (Entry e = tab[i];e != null;e = tab[i = nextIndex(i, len)]) {ThreadLocal<?> k = e.get();if (k == key) {e.value = value;return;}if (k == null) {replaceStaleEntry(key, value, i);return;}}tab[i] = new Entry(key, value);int sz = ++size;if (!cleanSomeSlots(i, sz) && sz >= threshold)rehash();}} }1.2總結(jié)
1.不同線程之間訪問時(shí)訪問的是不同的table數(shù)組的同一位置即都為table[i],只不過這個(gè)不同線程之間的table是獨(dú)立的。
2.對(duì)于同一線程的不同ThreadLocal來講,這些ThreadLocal實(shí)例共享一個(gè)table數(shù)組,然后每個(gè)ThreadLocal實(shí)例在table中的索引i是不同的。
1.3ThreadLocal和Synchronized
ThreadLocal和Synchronized都是為了解決多線程中相同變量的訪問沖突問題,不同的點(diǎn)是
Synchronized是通過線程等待,犧牲時(shí)間來解決訪問沖突
ThreadLocal是通過每個(gè)線程單獨(dú)一份存儲(chǔ)空間,犧牲空間來解決沖突,并且相比于Synchronized,ThreadLocal具有線程隔離的效果,只有在線程內(nèi)才能獲取到對(duì)應(yīng)的值,線程外則不能訪問到想要的值。
鏈接:https://www.jianshu.com/p/3c5d7f09dfbd
1.4關(guān)于Spring,ioc創(chuàng)建的對(duì)象和new創(chuàng)建的對(duì)象有啥區(qū)別
Spring Bean是反射創(chuàng)建,先創(chuàng)建bean之后,有一系列的步驟(ioc 12個(gè)步驟)可以被開發(fā)中敢于修改擴(kuò)展,最終把創(chuàng)建好的對(duì)象放在map里
讀源碼
今天我就給大家分享一下路神的Spring源碼學(xué)習(xí)方法:(源碼的學(xué)習(xí)方法是通用的)
1、通讀Spring官方文檔
學(xué)習(xí)Spring源碼之前,首先要把Spring官方網(wǎng)文檔系統(tǒng)的閱讀一遍。哪怕你讀不懂,也會(huì)接觸到很多名詞,讀源碼的時(shí)候大有幫助。
有人拿自己英語不好當(dāng)借口,子路笑言自己的英文水平經(jīng)常被人噴,這個(gè)困難要自己克服。
2、如何正確閱讀Spring源碼
讀完源碼就忘,是因?yàn)槟銢]有理解透徹。子路建議:“不要從字面意義上去讀源碼,通過源碼啟動(dòng)方式閱讀。”
比如讀nacos的源碼,要理解作者做這個(gè)設(shè)計(jì)變量的思路、設(shè)計(jì)代碼的原則、作者的想法是怎樣的?
比如nacos跟Spring、Spring boot、Spring cloud這四個(gè)角色分別完成什么樣的功能?Spring cloud中Spring-cloud-common這個(gè)包有什么用?Spring boot主要完成的功能?Spring又完成什么功能?
那么三者結(jié)合在一起就可以看出作者寫代碼的意圖,一定要站在作者的角度,結(jié)合全局來看源碼。
3、盡情去調(diào)試Spring吧
源碼級(jí)的知識(shí)一定要自己驗(yàn)證!特別是Spring的擴(kuò)展點(diǎn)!
在學(xué)習(xí)過程中,不要怕,盡量多去調(diào)試;看一下就去斷點(diǎn)調(diào)試一下;多去寫自己的注釋;盡量去把Spring代碼改了,把代碼給刪了!
多思考Spring某些地方預(yù)留的接口能干嘛?這個(gè)地方是不是可以做擴(kuò)展?MyBatis是如何擴(kuò)展Spring的?市面上還有哪些主流框架擴(kuò)展了Spring?邊看源碼邊思考,這樣你的記憶會(huì)加深很多。
學(xué)習(xí)Spring源碼目的就是為了讓我們能夠去對(duì)Spring做二次開發(fā)或者擴(kuò)展。
實(shí)話實(shí)說,大多數(shù)人學(xué)Spring,就是為了去面試。很多人在簡歷上寫“讀過Spring源碼”,這么寫你連電話都接不到!
我們讀過Spring源碼之后,簡歷上該怎么寫?給大家做個(gè)參考:
系統(tǒng)的閱讀過Spring源碼;
能夠?qū)pring做二次開發(fā);
并且熟知Spring當(dāng)中的各種擴(kuò)展點(diǎn);
熟知主流框架對(duì)Spring源碼的擴(kuò)展;
單詞
Injection 注射注入
current 現(xiàn)在,流通的
associated關(guān)聯(lián)的,聯(lián)系
necessary必須的,必要的
rehash重復(fù)
refresh更新,恢復(fù)
obtain獲得流行
triggered 引起 觸發(fā)
學(xué)習(xí)資源
spring循環(huán)依賴 https://mp.weixin.qq.com/s/RFxoVMeW5Mx9kzzFGhpyKA
閱讀源碼的方式:https://mp.weixin.qq.com/s/XQ5jl2pUa1W7Ueu0pWFS2Q
什么是ThreadLocal:https://mp.weixin.qq.com/s/bcH2pL06J5udBWedE1tbCA
springBean的生命周期:https://mp.weixin.qq.com/s/rz9cZRLZZnA_kahetEYjaw
總結(jié)
以上是生活随笔為你收集整理的spring源码刨析总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springMvc源码刨析笔记
- 下一篇: mybatis源码刨析总结