中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

移動端友好網(wǎng)站產(chǎn)品營銷方案

移動端友好網(wǎng)站,產(chǎn)品營銷方案,谷歌自建站和優(yōu)化,房地產(chǎn)排名前三十強排名前置知識 《【Spring專題】Spring底層核心原理解析》 思路整理 我們在上一節(jié)《【Spring專題】Spring底層核心原理解析》課里面有簡單分析過一個Spring容器的一般流程,所以,本節(jié)課我們這里嘗試寫一下簡易的Spring容器。 手寫源碼示例 一、手寫前的準(zhǔn)…

前置知識

《【Spring專題】Spring底層核心原理解析》

思路整理

我們在上一節(jié)《【Spring專題】Spring底層核心原理解析》課里面有簡單分析過一個Spring容器的一般流程,所以,本節(jié)課我們這里嘗試寫一下簡易的Spring容器。

手寫源碼示例

一、手寫前的準(zhǔn)備

1.1 注解

既然是需要手寫Spring容器,那我們肯定需要自定義一個MyApplicationContext類,以及自定義注解@ComponentScan@Component@Autowired@Scope代碼如下:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {String value() default "";
}@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {String value() default "";
}@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {String value() default "";
}@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Autowired {
}

其中@Scope是為了驗證多例Bean跟單例Bean的。當(dāng)然,需要準(zhǔn)備的接口不止于此,后面我會隨著方法的完善,逐漸引出其余需要的接口或者注解。

1.2 測試Bean

另外就是測試用的Bean,代碼如下:

/*** @author zhangshen* @tag 【手寫】* @Date 2023/8/7 19:57* @slogan 編碼即學(xué)習(xí)**/
@Component("userService")
public class MyUserService implements InitializingBean, BeanPostProcessor {private int afterPropertiesSet = 0;private int postProcessBeforeInitialization = 0;private int postProcessAfterInitialization = 0;private static int count = 0;public void showYourFace() {System.out.println("手寫的spring。。。。。 test一下");System.out.println("初始化是第幾步,答案是:" + afterPropertiesSet);System.out.println("初始化前是第幾步,答案是:" + postProcessBeforeInitialization);System.out.println("初始化后是第幾步,答案是:" + postProcessAfterInitialization);}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("這里是初始化,是在aware回調(diào)之后");count++;afterPropertiesSet = count;}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) {System.out.println("這里是初始化前");count++;postProcessBeforeInitialization = count;return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) {System.out.println("這里是初始化后");count++;postProcessAfterInitialization = count;return bean;}
}

1.3 調(diào)用實例

調(diào)用實例:

/*** 手寫Spring容器測試** @author zhangshen* @tag 【手寫】* @Date 2023/8/7 19:55* @slogan 編碼即學(xué)習(xí)**/
public class MyApplicationContextTest {public static void main(String[] args) {MyApplicationContext context = new MyApplicationContext(MyAppConfig.class);MyUserService userService = (MyUserService) context.getBean("userService");userService.showYourFace();}
}

二、構(gòu)造方法(構(gòu)建基本流程)

在上節(jié)課中,我們說過,在容器啟動的構(gòu)造方法里面,大致的流程可以分為三步:
在這里插入圖片描述
所以,我們代碼起手式,是新建一個MyApplicationContext類,然后一個默認(rèn)的無參構(gòu)造方法,代碼如下:

public class MyApplicationContext {public MyApplicationContext(Class clazz) {// 步驟一:掃描scan(clazz);// 步驟二:IOCioc();// 步驟三:AOPaop();}
}

但事實上,我們前面說過,雖然看似大過程是3步,不過AOP是需要發(fā)生在IOC內(nèi)部的(Bean放入單例池之前),所以,后面,我們會把這個AOP的過程寫在IOC里面,如下:

public class MyApplicationContext {public MyApplicationContext(Class clazz) {// 步驟一:掃描scan(clazz);// 步驟二:IOCioc();}private void doIOC() {// 步驟三:AOPaop();}
}

三、實現(xiàn)scan()方法

先上掃描的簡易流程圖:
在這里插入圖片描述
接下來,我們只需要在doScan()方法里面實現(xiàn)這些步驟就好了。

    /*** 掃描方法** @param clazz 配置類*/private void scan(Class clazz) {// 步驟一:獲取掃描路徑String basePackage = doGetScanPackage(clazz);if (StrUtil.isEmpty(basePackage)) {return;}// 步驟二、三:從電腦磁盤中加載文件,并且掃描doLoadClassFromDiskAndScan(basePackage, clazz);}

3.1 doGetScanPackage():獲取掃描路徑

    /*** 獲取包掃描路徑** @param clazz 配置類* @return 掃描路徑*/private String doGetScanPackage(Class clazz) {if (clazz.isAnnotationPresent(ComponentScan.class)) {ComponentScan componentScanAnnotation = (ComponentScan) clazz.getAnnotation(ComponentScan.class);return componentScanAnnotation.value();}return null;}

3.2 doLoadClassFromDiskAndScan():從電腦磁盤中加載文件,并且掃描

    /*** 從磁盤中加載class,并且掃描** @param basePackage 掃描路徑*/private void doLoadClassFromDiskAndScan(String basePackage) {// 將Java包名轉(zhuǎn)換為電腦路徑名basePackage = basePackage.replace(".", "/");// 加載ClassLoader classLoader = MyApplicationContext.class.getClassLoader();URL resource = classLoader.getResource(basePackage);File file = new File(resource.getFile());if (file.isDirectory()) {for (File listFile : file.listFiles()) {// 獲取全限定名String fullyQualifiedClassName = transferToFullyQualifiedClassName(listFile);try {Class<?> beanClass = classLoader.loadClass(fullyQualifiedClassName);if (!beanClass.isAnnotationPresent(Component.class)) {continue;}// 記錄Bean信息doRecordBeanInfo(beanClass);} catch (ClassNotFoundException e) {e.printStackTrace();}}}}

方法解讀:

  1. 在上一步,我們已經(jīng)獲取到了掃描路徑,但是掃描路徑是我們Java包名,現(xiàn)在需要從磁盤重讀取的話,定然是需要轉(zhuǎn)換成電腦磁盤重的路徑的。
  2. 大家可能對classLoader這一塊比較難理解,這是屬于JVM那一塊的。不過這么說,我們自己寫的業(yè)務(wù)代碼,除非特別指定,不然都是使用的同一個類加載器
  3. 這里還有2個關(guān)鍵方法調(diào)用,一個是transferToFullyQualifiedClassName(),是將文件名轉(zhuǎn)換為類加載器能識別的類全限定名;另一個是doRecordBeanInfo()方法,記錄Bean定義信息的。代碼會在后面

3.3 transferToFullyQualifiedClassName() :獲取全限定名

    /*** 將電腦磁盤上的文件,轉(zhuǎn)換為AppClassLoader能識別的類全限定名(包 + 類名)** <p>* 由于JVM的類加載器有三種,默認(rèn)加載用戶自定義class文件的,其實是ApplicationClassLoader* 該類加載器所能識別的,其實是包名* </p>** @param listFile 電腦磁盤上的文件*/private String transferToFullyQualifiedClassName(File listFile) {String absolutePath = listFile.getAbsolutePath();absolutePath = absolutePath.substring(absolutePath.indexOf("org"), absolutePath.indexOf(".class"));absolutePath = absolutePath.replace("\\", ".");return absolutePath;}

*3.4 doRecordBeanInfo() :記錄Bean信息

    /*** 過濾,并且記錄Bean信息*/private void doRecordBeanInfo(Class<?> beanClass) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {// 獲取bean的名字String beanName = doGetBeanName(beanClass);// 記錄BeanPostProcessorif (BeanPostProcessor.class.isAssignableFrom(beanClass)) {BeanPostProcessor instance = (BeanPostProcessor) beanClass.getConstructor().newInstance();beanPostProcessorList.add(instance);}BeanDefinition beanDefinition = new BeanDefinition();beanDefinition.setType(beanClass);if (beanClass.isAnnotationPresent(Scope.class)) {Scope scopeAnnotation = beanClass.getAnnotation(Scope.class);String value = scopeAnnotation.value();beanDefinition.setScope(value);}// 記錄BeanDefinitionbeanDefinitionMap.put(beanName, beanDefinition);}

這里,引入了一個新的類BeanDefinition類,源碼如下:

/*** 手寫B(tài)ean定義** @author zhanghuitong* @tag 【手寫】 【Bean定義】 【圖紙】* @Date 2023/8/8 10:54* @slogan 編碼即學(xué)習(xí)**/
@Getter
@Setter
public class BeanDefinition {private static final String SINGLETON = "singleton";/*** Bean類型*/private Class type;/*** 作用域* 是原型,還是單例*/private String scope = SINGLETON;
}

也許大家會很奇怪,為什么需要引入這么一個東西呢?我都已經(jīng)掃描好了,我直接根據(jù)類信息生成不就行了嗎?如果你也有這個想法,那么我反問你一個問題:如果我后面想修改怎么辦?還別說,真的有可能修改!Spring提供了那么多拓展機(jī)制,其中就有對類信息修改的拓展點(至于具體應(yīng)用場景,我還沒徹底學(xué)清楚,我后面學(xué)到了我會回來更新的)。但是為了方便大家理解這個玩意的存在,我舉個通俗的例子,如下:

BeanDefinition的存在更像是一份家具定制的圖紙,Bean是具體的某個家具。而Spring里面,在后面我們會學(xué)到的ApplicationContext,則是生產(chǎn)家具的廠家。這樣類比的話,你應(yīng)該能想明白,為什么需要BeanDefinition了吧。
總結(jié)一句話:ApplicationContext廠家根據(jù)BeanDefinition圖紙生成具體的某個家具Bean。(PS:ApplicationContext 包含 BeanFactory,都是Bean工廠)

四、實現(xiàn)ioc()方法

先看看ioc簡易流程圖:
在這里插入圖片描述
(PS:下面的手寫源碼,沒有實現(xiàn)【推斷構(gòu)造方法】的邏輯)

    /*** 進(jìn)行IOC過程*/private void ioc() {// 循環(huán)遍歷beanDefinitionMapSet<Map.Entry<String, BeanDefinition>> entries = beanDefinitionMap.entrySet();for (Map.Entry<String, BeanDefinition> entry : entries) {String beanName = entry.getKey();BeanDefinition beanDefinition = entry.getValue();if (beanDefinition.getScope().equals(BeanDefinition.SINGLETON)) {// 創(chuàng)建BeanObject bean = createBean(beanName, beanDefinition);// AOPaop();singletonPool.put(beanName, bean);}}}

方法解讀:

  1. 在這里,就是遍歷我們上一步獲得的beanDefinitionMap圖紙Map。
  2. 接著就開始根據(jù)圖紙生成Bean了(createBean()方法)
  3. 接著看看是否需要AOP了(在放入單例池之前)
  4. 最后就是放入單例池里面了

*4.1 createBean() :創(chuàng)建Bean

    /*** 創(chuàng)建bean** @param beanName       bean名稱* @param beanDefinition 對應(yīng)的bean定義*/private Object createBean(String beanName, BeanDefinition beanDefinition) {Class clazz = beanDefinition.getType();Object instance = null;try {// 實例化。本應(yīng)該實現(xiàn)推斷構(gòu)造方法,但是這里從簡使用默認(rèn)的instance = clazz.getConstructor().newInstance();// 依賴注入doDependecyInjection(clazz, instance);// 各種Aware回調(diào)doAwareCallBack(beanName, instance);// 初始化前instance = doInitBefore(beanName, instance);// 初始化doInit(instance);// 初始化后instance = doInitAfter(beanName, instance);} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}// 返回return instance;}

方法解讀:
雖然上面的代碼是簡單的實現(xiàn),但也稍微能窺見一點IOC的生命周期了,大家需要好好記住。

實例化 -> 依賴注入 -> 各種Aware回調(diào) -> 初始化前 -> 初始化 -> 初始化后

因為是簡單實現(xiàn),所以上面這個流程不全,應(yīng)該是缺了點其他拓展點的實現(xiàn)的。但是局部上的順序是沒啥問題,而且這不是我吹的,而是在Spirng接口上注釋的。

4.2 doDependecyInjection() :依賴注入

    /*** 依賴注入** @param clazz    需要被注入的對象的類信息* @param instance 需要被注入的對象*/private void doDependecyInjection(Class clazz, Object instance) throws IllegalAccessException {Field[] declaredFields = clazz.getDeclaredFields();for (Field declaredField : declaredFields) {if (declaredField.isAnnotationPresent(Autowired.class)) {declaredField.setAccessible(true);declaredField.set(instance, getBean(declaredField.getName()));}}}

4.3 doAwareCallBack() :各種Aware回調(diào)

    /*** 實現(xiàn)各種Aware的回調(diào)處理** @param beanName bean名稱* @param instance bean對象*/private void doAwareCallBack(String beanName, Object instance) {if (instance instanceof BeanNameAware) {((BeanNameAware) instance).setBeanName(beanName);}}

方法解讀:
在這里,引入了一個新的接口BeanNameAware,它實現(xiàn)自Aware接口。其實除了這個我們用來展示的BeanNameAware還有很多其他的XxxAware,主要的目的是在實例化之后,讓我們獲得感知一些Spring組件等等能力。下面是BeanNameAware接口的代碼示例(其中注釋源于Spring源碼):

/*** 手寫Spring的BeanNameAware接口** @author zhangshen* @tag 【手寫】* @Date 2023/8/8 19:04* @slogan 編碼即學(xué)習(xí)**/
public interface BeanNameAware {/*** 在創(chuàng)建該bean的bean工廠中設(shè)置該bean的名稱。* 在填充普通bean屬性之后,但在初始化回調(diào)(如InitializingBean.afterPropertiesSet())或自定義初始化方法之前調(diào)用。* 參數(shù):* 名稱-工廠中bean的名稱。請注意,這個名稱是工廠中使用的實際bean名稱,它可能與最初指定的名稱不同:特別是對于內(nèi)部bean名稱,實際bean名稱可能通過附加“#…”后綴來使其唯一。如果需要,使用BeanFactoryUtils.originalBeanName(String)方法提取原始bean名稱(不帶后綴)。*/void setBeanName(String name);
}

4.4 doInitBefore() :初始化前

    /*** 實施初始化之前** @param beanName bean名稱* @param instance bean對象*/private Object doInitBefore(String beanName, Object instance) {for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);}return instance;}

方法解讀:

  1. 初始化前這是屬于SpringIOC提供的一個拓展點,需要一個非常非常非常重要的接口BeanPostProcessor ,它的定義如下:(其中注釋源于Spring源碼)
/*** 手寫Spring的ABeanPostProcessor接口** @author zhangshen* @tag 【手寫】* @Date 2023/8/8 19:04* @slogan 編碼即學(xué)習(xí)**/
public interface BeanPostProcessor {/*** 在任何bean初始化回調(diào)(如InitializingBean的afterPropertiesSet或自定義初始化方法)之前,將此BeanPostProcessor應(yīng)用于給定的新bean實例。這個bean已經(jīng)被屬性值填充了。返回的bean實例可能是原始bean實例的包裝器。* 默認(rèn)實現(xiàn)按原樣返回給定的bean。* 參數(shù):* Bean——新的Bean實例* beanName—bean的名稱* 返回:* 要使用的bean實例,無論是原始的還是包裝的;如果為空,則不會調(diào)用后續(xù)的BeanPostProcessors* 拋出:* BeansException -在錯誤的情況下*/default Object postProcessBeforeInitialization(Object bean, String beanName) {return bean;}/*** 在任何bean初始化回調(diào)(如InitializingBean的afterPropertiesSet或自定義init-method)之后,將此BeanPostProcessor應(yīng)用于給定的新bean實例。這個bean已經(jīng)被屬性值填充了。返回的bean實例可能是原始bean實例的包裝器。* 對于FactoryBean,將為FactoryBean實例和由FactoryBean創(chuàng)建的對象調(diào)用這個回調(diào)(從Spring 2.0開始)。后處理器可以通過相應(yīng)的FactoryBean instanceof檢查來決定是應(yīng)用于FactoryBean還是已創(chuàng)建的對象,或者兩者都應(yīng)用。* 這個回調(diào)也將在由InstantiationAwareBeanPostProcessor觸發(fā)的短路之后被調(diào)用。postProcessBeforeInstantiation方法,與所有其他BeanPostProcessor回調(diào)相反。* 默認(rèn)實現(xiàn)按原樣返回給定的bean。* 參數(shù):* Bean——新的Bean實例* beanName—bean的名稱* 返回:* 要使用的bean實例,無論是原始的還是包裝的;如果為空,則不會調(diào)用后續(xù)的BeanPostProcessors* 拋出:* BeansException -在錯誤的情況下* 參見:* org.springframework.beans.factory.InitializingBean。afterPropertiesSet, org.springframework.beans.factory.FactoryBean* 以上翻譯結(jié)果來自有道神經(jīng)網(wǎng)絡(luò)翻譯(YNMT)· 通用場景*/default Object postProcessAfterInitialization(Object bean, String beanName) {return bean;}
}

從上面的注釋希望大家在后面真的閱讀源碼的時候能知道,BeanPostProcessor這個拓展點就是作用在初始化前后的

4.5 doInit() :初始化

    /*** 實施初始化方法** @param instance bean對象*/private void doInit(Object instance) throws Exception {if (instance instanceof InitializingBean) {((InitializingBean) instance).afterPropertiesSet();}}

方法解讀:

  1. 初始化方法,在這里又是需要一個新的接口,InitializingBean,在工作使用頻率挺高的。當(dāng)然也可以通過自定義初始化方法,不一定就是這個。接口代碼如下:(其中注釋源于Spring源碼)
/*** 手寫Spring的ABeanPostProcessor接口** @author zhangshen* @tag 【手寫】* @Date 2023/8/8 19:04* @slogan 編碼即學(xué)習(xí)**/
public interface InitializingBean {/*** 在設(shè)置了所有bean屬性并滿足BeanFactoryAware、ApplicationContextAware等要求后,由包含bean的BeanFactory調(diào)用。* 此方法允許bean實例在設(shè)置了所有bean屬性后對其總體配置和最終初始化執(zhí)行驗證。* 拋出:* 異常-在配置錯誤的情況下(例如設(shè)置基本屬性失敗),或者由于任何其他原因?qū)е鲁跏蓟?/void afterPropertiesSet() throws Exception;
}

4.6 doInitAfter() :初始化后

    /*** 實施初始化之后** @param beanName bean名稱* @param instance bean對象*/private Object doInitAfter(String beanName, Object instance) {for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);}return instance;}

方法解讀:

  1. 初始化后,跟初始化前一樣,是屬于SpringIOC提供的一個拓展點。并且使用的也是BeanPostProcessor接口

五、實現(xiàn)aop()方法

這個就不實現(xiàn)了,大家知道有這個東西就好

六、MyApplicationContext完整源碼

package org.tuling.spring.handwriten;import cn.hutool.core.util.StrUtil;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.*;/*** 手寫一個簡易的Spring容器** @author zhangshen* @tag 【Spring】 【手寫】* @Date 2023/8/7 19:37* @slogan 編碼即學(xué)習(xí)**/
public class MyApplicationContext {private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();private Map<String, Object> singletonPool = new HashMap<>();private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();public MyApplicationContext(Class clazz) {// 掃描scan(clazz);// IOCioc();}/*** 進(jìn)行IOC過程*/private void ioc() {// 循環(huán)遍歷beanDefinitionMapSet<Map.Entry<String, BeanDefinition>> entries = beanDefinitionMap.entrySet();for (Map.Entry<String, BeanDefinition> entry : entries) {String beanName = entry.getKey();BeanDefinition beanDefinition = entry.getValue();if (beanDefinition.getScope().equals(BeanDefinition.SINGLETON)) {// 創(chuàng)建BeanObject bean = createBean(beanName, beanDefinition);// AOPaop();singletonPool.put(beanName, bean);}}}/*** 創(chuàng)建bean** @param beanName       bean名稱* @param beanDefinition 對應(yīng)的bean定義*/private Object createBean(String beanName, BeanDefinition beanDefinition) {Class clazz = beanDefinition.getType();Object instance = null;try {// 實例化。本應(yīng)該實現(xiàn)推斷構(gòu)造方法,但是這里從簡使用默認(rèn)的instance = clazz.getConstructor().newInstance();// 依賴注入doDependecyInjection(clazz, instance);// 各種Aware回調(diào)doAwareCallBack(beanName, instance);// 初始化前instance = doInitBefore(beanName, instance);// 初始化doInit(instance);// 初始化后instance = doInitAfter(beanName, instance);} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}// 返回return instance;}/*** 實施初始化之后** @param beanName bean名稱* @param instance bean對象*/private Object doInitAfter(String beanName, Object instance) {for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);}return instance;}/*** 實施初始化方法** @param instance bean對象*/private void doInit(Object instance) throws Exception {if (instance instanceof InitializingBean) {((InitializingBean) instance).afterPropertiesSet();}}/*** 實施初始化之前** @param beanName bean名稱* @param instance bean對象*/private Object doInitBefore(String beanName, Object instance) {for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);}return instance;}/*** 實現(xiàn)各種Aware的回調(diào)處理** @param beanName bean名稱* @param instance bean對象*/private void doAwareCallBack(String beanName, Object instance) {if (instance instanceof BeanNameAware) {((BeanNameAware) instance).setBeanName(beanName);}}/*** 依賴注入** @param clazz    需要被注入的對象的類信息* @param instance 需要被注入的對象*/private void doDependecyInjection(Class clazz, Object instance) throws IllegalAccessException {Field[] declaredFields = clazz.getDeclaredFields();for (Field declaredField : declaredFields) {if (declaredField.isAnnotationPresent(Autowired.class)) {declaredField.setAccessible(true);declaredField.set(instance, getBean(declaredField.getName()));}}}/*** 進(jìn)行AOP過程*/private void aop() {}/*** 根據(jù)beanName獲取Bean** @param beanName bean名稱* @return bean對象*/public Object getBean(String beanName) {if (StrUtil.isEmpty(beanName)) {return null;}// 不存在beanDefinition,則肯定不是beanif (!beanDefinitionMap.containsKey(beanName)) {throw new NoSuchBeanDefinitionException("沒有對應(yīng)的bean定義");}BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);// 創(chuàng)建對象if (beanDefinition.getScope().equals(BeanDefinition.SINGLETON)) {// 獲取單例Object singletonBean = singletonPool.get(beanName);if (singletonBean == null) {singletonBean = createBean(beanName, beanDefinition);singletonPool.put(beanName, singletonBean);}return singletonBean;} else {// 獲取多例Object prototype = createBean(beanName, beanDefinition);return prototype;}}/*** 掃描方法** @param clazz 配置類*/private void scan(Class clazz) {// 獲取掃描路徑String basePackage = doGetScanPackage(clazz);if (StrUtil.isEmpty(basePackage)) {return;}// 從電腦磁盤中加載文件,并且掃描doLoadClassFromDiskAndScan(basePackage);}/*** 從磁盤中加載class,并且掃描** @param basePackage 掃描路徑*/private void doLoadClassFromDiskAndScan(String basePackage) {// 將Java包名轉(zhuǎn)換為電腦路徑名basePackage = basePackage.replace(".", "/");// 加載ClassLoader classLoader = MyApplicationContext.class.getClassLoader();URL resource = classLoader.getResource(basePackage);File file = new File(resource.getFile());if (file.isDirectory()) {for (File listFile : file.listFiles()) {// 獲取全限定名String fullyQualifiedClassName = transferToFullyQualifiedClassName(listFile);try {Class<?> beanClass = classLoader.loadClass(fullyQualifiedClassName);if (!beanClass.isAnnotationPresent(Component.class)) {continue;}// 記錄Bean信息try {doRecordBeanInfo(beanClass);} catch (NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}} catch (ClassNotFoundException e) {e.printStackTrace();}}}}/*** 過濾,并且記錄Bean信息*/private void doRecordBeanInfo(Class<?> beanClass) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {// 獲取bean的名字String beanName = doGetBeanName(beanClass);// 記錄BeanPostProcessorif (BeanPostProcessor.class.isAssignableFrom(beanClass)) {BeanPostProcessor instance = (BeanPostProcessor) beanClass.getConstructor().newInstance();beanPostProcessorList.add(instance);}BeanDefinition beanDefinition = new BeanDefinition();beanDefinition.setType(beanClass);if (beanClass.isAnnotationPresent(Scope.class)) {Scope scopeAnnotation = beanClass.getAnnotation(Scope.class);String value = scopeAnnotation.value();beanDefinition.setScope(value);}// 記錄BeanDefinitionbeanDefinitionMap.put(beanName, beanDefinition);}/*** 獲取當(dāng)前Bean的名字** @param aClass 要加載的類* @return bean的名字*/private String doGetBeanName(Class<?> aClass) {Component componentAnnotaion = aClass.getAnnotation(Component.class);String beanName = componentAnnotaion.value();if (StrUtil.isEmpty(beanName)) {beanName = Introspector.decapitalize(aClass.getSimpleName());}return beanName;}/*** 將電腦磁盤上的文件,轉(zhuǎn)換為AppClassLoader能識別的類全限定名(包 + 類名)** <p>* 由于JVM的類加載器有三種,默認(rèn)加載用戶自定義class文件的,其實是ApplicationClassLoader* 該類加載器所能識別的,其實是包名* </p>** @param listFile 電腦磁盤上的文件*/private String transferToFullyQualifiedClassName(File listFile) {String absolutePath = listFile.getAbsolutePath();absolutePath = absolutePath.substring(absolutePath.indexOf("org"), absolutePath.indexOf(".class"));absolutePath = absolutePath.replace("\\", ".");return absolutePath;}/*** 獲取包掃描路徑** @param clazz 配置類* @return 掃描路徑*/private String doGetScanPackage(Class clazz) {if (clazz.isAnnotationPresent(ComponentScan.class)) {ComponentScan componentScanAnnotation = (ComponentScan) clazz.getAnnotation(ComponentScan.class);return componentScanAnnotation.value();}return null;}
}
http://www.risenshineclean.com/news/52660.html

相關(guān)文章:

  • 營銷顧問公司seo是什么部位
  • 普定縣建設(shè)局網(wǎng)站怎么辦網(wǎng)站平臺
  • 南昌網(wǎng)站空間怎么優(yōu)化
  • 網(wǎng)站開發(fā)公司海報如何做好網(wǎng)站站內(nèi)優(yōu)化
  • 福建漳州網(wǎng)站建設(shè)費用seo外鏈怎么做
  • 寧波英文網(wǎng)站建設(shè)如何做個網(wǎng)站推廣自己產(chǎn)品
  • 視頻手機(jī)網(wǎng)站開發(fā)seo優(yōu)化公司哪家好
  • 設(shè)計網(wǎng)站都有哪些南京最新消息今天
  • 手機(jī)維修網(wǎng)站模板長沙互聯(lián)網(wǎng)推廣公司
  • 有限責(zé)任公司注冊條件網(wǎng)絡(luò)推廣seo教程
  • 配件網(wǎng)站模板網(wǎng)站優(yōu)化什么意思
  • 開啟wordpress mu優(yōu)化模型的推廣
  • 下列關(guān)于網(wǎng)站開發(fā)中seo顧問是干什么
  • 沒有公司 接單做網(wǎng)站搜索引擎推廣文案
  • 杭州做網(wǎng)站套餐新手銷售怎么和客戶交流
  • 成都網(wǎng)頁制作公司排名北京優(yōu)化seo
  • 網(wǎng)站開發(fā)checklist如何讓百度收錄自己信息
  • 房地產(chǎn)網(wǎng)站建設(shè)與優(yōu)化分析北京seo專業(yè)團(tuán)隊
  • 軟件外包學(xué)院大學(xué)承認(rèn)嗎網(wǎng)站免費seo
  • 上海做外貿(mào)網(wǎng)站建設(shè)湖南企業(yè)競價優(yōu)化首選
  • 網(wǎng)站建設(shè)地位友情鏈接交換網(wǎng)
  • 揭陽網(wǎng)站制作軟件技能培訓(xùn)機(jī)構(gòu)
  • 移動應(yīng)用開發(fā)難學(xué)嗎上海有哪些優(yōu)化網(wǎng)站推廣公司
  • WordPress離線博客江蘇網(wǎng)站seo設(shè)計
  • dw做網(wǎng)站怎么換圖片南京最新消息今天
  • 中國外發(fā)加工網(wǎng)app北京網(wǎng)站優(yōu)化推廣公司
  • 有什么好用的模擬建站軟件營銷策劃方案怎么做
  • 國內(nèi)做網(wǎng)站費用seo建站網(wǎng)絡(luò)公司
  • 校本教研網(wǎng)站建設(shè)網(wǎng)絡(luò)營銷的方法有哪些?舉例說明
  • 華強北 做網(wǎng)站中國輿情觀察網(wǎng)