国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Spring源碼篇(你值得擁有)

這篇具有很好參考價值的文章主要介紹了Spring源碼篇(你值得擁有)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

概念篇

下面是本文章關(guān)于Spring底層原理的章節(jié)

Spring源碼篇(你值得擁有)

Bean的創(chuàng)建的生命周期

類-》推斷構(gòu)造方法-》根據(jù)構(gòu)造方法創(chuàng)建普通對象-》依賴注入(@Autowired等進(jìn)行屬性注入)-》初始化前(@PostConstruct)->初始化(InitializingBean)-》初始化后(AOP)-》代理對象(沒有開啟AOP就會把普通對象放入單例池)-》放入單例池-》Bean對象

依賴注入

在Spring容器中創(chuàng)建了一個普通對象后,如果這個對象有類似于@Autowired注解的屬性,如何給這個屬性賦值呢?這里利用的是反射的機(jī)制,在創(chuàng)建完一個普通對象后,利用反射機(jī)制看有沒有@Autowird注解的屬性,如果依賴注入的bean為單例,首先從單例池中尋找,找到就賦值注入,找不到就創(chuàng)建然后注入屬性,如果這個bean為多例,就會直接new 一個對象出來然后賦值。這個具體可以看下面的模擬代碼進(jìn)行深入理解。

推斷構(gòu)造方法

在Spring容器中使用構(gòu)造方法創(chuàng)建對象的時候默認(rèn)采用無參構(gòu)造方法。在Spring容器中創(chuàng)建對象是通過反射根據(jù)構(gòu)造方法進(jìn)行創(chuàng)建的,至于具體根據(jù)哪個構(gòu)造方法進(jìn)行創(chuàng)建對象,內(nèi)容如下:

1.只有一個構(gòu)造方法,那么實(shí)例化就只能使用這個構(gòu)造方法了。有參的話(前提是根據(jù)參數(shù)類型或者名字可以找到唯一的bean。
2.有多個構(gòu)造方法,不管構(gòu)造方法參數(shù)是一個還是多個,那么Spring會去找默認(rèn)的無參的構(gòu)造方法,找不到則報錯。
3.多個構(gòu)造方法,并且開發(fā)者指定了想使用的構(gòu)造方法,那么就用這個構(gòu)造方法
通過@Autowired注解,@Autowired注解可以寫在構(gòu)造方法上,所以哪個構(gòu)造方法上寫了@Autowired注解,表示開發(fā)者想使用哪個構(gòu)造方法。通過@Autowired注解的方式,需要Spring通過byType+byName的方式去找到符合條件的bean作為構(gòu)造方法的參數(shù)值,當(dāng)然找不到是要報錯的。通過byType找如果只有一個就使用該Bean對象,如果有多個再根據(jù)名字去找,Spring容器在尋找過程中是根據(jù)參數(shù)名作為名字去尋找的,找不到則報錯。這個類似于@Autowired注解,一開始根據(jù)類型去尋找,如果有多個,再根據(jù)屬性名去找對應(yīng)的是該名字的Bean對象。

@PostConstruct

如果想要在對象初始化之前執(zhí)行該對象中的一些方法,可以在該對象方法上加上@PostConstruct注解。在Spring容器中初始化之前執(zhí)行有該注解的方法。

初始化

Spring容器中對于對象的初始化可以通過繼承 InitializingBean 接口重寫?afterPropertiesSet() 方法,在此方法里面執(zhí)行自己的初始化的業(yè)務(wù)邏輯。有關(guān)代碼如下:

@Component("test")
public class Test implements InitializingBean {
    public  void hello(){
        System.out.println("執(zhí)行方法");
    }

    @PostConstruct
    public void go(){
        System.out.println("初始化之前");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("初始化");
    }
}

執(zhí)行結(jié)果如下圖:

Spring源碼篇(你值得擁有)

AOP

AOP簡介

這里先對AOP進(jìn)行簡單的介紹

AOP (Aspect?Orient Programming),直譯過來就是 面向切面編程,AOP 是一種編程思想,是面向?qū)ο缶幊蹋∣OP)的一種補(bǔ)充。面向切面編程,實(shí)現(xiàn)在不修改源代碼的情況下給程序動態(tài)統(tǒng)一添加額外功能的一種技術(shù)。AOP可以攔截指定的方法并且對方法增強(qiáng),而且無需侵入到業(yè)務(wù)代碼中,使業(yè)務(wù)與非業(yè)務(wù)處理邏輯分離,比如Spring的事務(wù),通過事務(wù)的注解配置,Spring會自動在業(yè)務(wù)方法中開啟、提交業(yè)務(wù),并且在業(yè)務(wù)處理失敗時,執(zhí)行相應(yīng)的回滾策略。AOP可以攔截指定的方法并且對方法增強(qiáng),而且無需侵入到業(yè)務(wù)代碼中,使業(yè)務(wù)與非業(yè)務(wù)處理邏輯分離,比如Spring的事務(wù),通過事務(wù)的注解配置,Spring會自動在業(yè)務(wù)方法中開啟、提交業(yè)務(wù),并且在業(yè)務(wù)處理失敗時,執(zhí)行相應(yīng)的回滾策略。

這里采用SpringBoot整合AOP實(shí)例代碼如下:

導(dǎo)入依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

導(dǎo)入配置類

@Configuration
@ComponentScan("com.example.demo.test")
@EnableAspectJAutoProxy
public class AspectConfiguration {

}

導(dǎo)入切面類

@Aspect
@Component
public class MyAspect {

    @Pointcut("execution(* com.example.demo.test.*.*(..))")
    public void myPointCut(){

    }
    //前置通知
    @Before("myPointCut()")
    public void before(JoinPoint joinPoint){
        System.out.println("前置通知");
        System.out.println("目標(biāo)類對象"+joinPoint.getTarget()+"被增強(qiáng)的方法"+joinPoint.getSignature().getName());
    }
    //后置返回通知
    @AfterReturning("myPointCut()")
    public void afterreturn(JoinPoint joinPoint){
        System.out.println("后置返回通知");
        System.out.println("目標(biāo)類對象"+joinPoint.getTarget()+"被增強(qiáng)的方法"+joinPoint.getSignature().getName());
    }

      //環(huán)繞通知,返回值類型為Object,必須有一參數(shù)是ProceedingJoinPoint
    @Around("myPointCut()")
    public Object aroud(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("環(huán)繞開始,模擬開啟事務(wù)");
       //執(zhí)行當(dāng)前方法
        Object proceed = proceedingJoinPoint.proceed();
        System.out.println("環(huán)繞結(jié)束,模擬關(guān)閉事務(wù)");
        return proceed;
    }

    //異常通知
    @AfterThrowing(value = "myPointCut()",throwing = "e")
    public void except(Throwable e){
        System.out.println("異常通知"+e.getMessage());
    }

    //后置最終通知
    @After("myPointCut()")
    public void after(JoinPoint joinPoint){
        System.out.println("最終通知");
    }



}

執(zhí)行代碼

public class hello {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext=new AnnotationConfigApplicationContext(AspectConfiguration.class);
        Test test = (Test) annotationConfigApplicationContext.getBean("test");
        test.hello();
    }
}

結(jié)果如下圖所示

Spring源碼篇(你值得擁有)

?這里對于Spring5通知的執(zhí)行順序進(jìn)行簡單的總結(jié),注意Spring4通知的執(zhí)行順序和Spring5不一樣。

程序執(zhí)行正常:

1、環(huán)繞通知前
2、@Before通知
3、程序邏輯
4、@AfterReturning通知
5、@After通知
6、環(huán)繞通知后

程序執(zhí)行異常:

1、環(huán)繞通知前
2、@Before通知
3、@AfterThrowing異常通知
4、@After通知
異常日志

AOP原理

對于上面的代碼我們在執(zhí)行test.hello的時候我們的對象是Test對象嗎?還是代理對象?經(jīng)過debug我們來看一下。如下圖證實(shí)我們拿到的對象是代理對象。

Spring源碼篇(你值得擁有)

?注意在Spring容器中假如真實(shí)對象中有類似@Autowired注解進(jìn)行依賴注入的時候,我們在這里debug拿到的代理對象關(guān)于這樣的屬性實(shí)際上是空的,但是直接運(yùn)行的時候?qū)嶋H上又會獲得依賴注入對象,這是什么原因呢?

在Spring容器中代理類其實(shí)是真實(shí)類的子類,通過extends繼承,既然代理類是真實(shí)類的子對象,那么他們之間是怎么實(shí)現(xiàn)的呢?實(shí)現(xiàn)方法之一如下:

public class My extends Test {
    @Override
    public void hello() {
        //執(zhí)行切面邏輯
        super.hello();
    }
}

這樣可以正確的實(shí)現(xiàn)嗎?其實(shí)是不行,假入Test類中有依賴注入的屬性,然后My代理類執(zhí)行父類的時候,在執(zhí)行方法中的有依賴注入的屬性其實(shí)是空的,因?yàn)楦割悇?chuàng)建了一個對象并為這個屬性賦值,它的子類并不會獲得該屬性的值的。那解決辦法呢?那就是在My類中創(chuàng)建一個Test類對象的屬性Target,并把真實(shí)類賦值給Target屬性,然后在執(zhí)行方法中執(zhí)行Target.hello方法就可以了。

Spring的事務(wù)

Spring聲明式事務(wù)管理是通過AOP技術(shù)實(shí)現(xiàn)的事務(wù)管理,其本質(zhì)是對方法前后進(jìn)行攔截,在目標(biāo)方法開始之前創(chuàng)建一個事務(wù),在目標(biāo)方法執(zhí)行之后,根據(jù)執(zhí)行情況提交或回滾事務(wù)。

事務(wù)在邏輯上是一組操作,要么執(zhí)行,要不都不執(zhí)行。主要是針對數(shù)據(jù)庫而言的,為了保證事務(wù)是正確可靠的,在數(shù)據(jù)庫進(jìn)行寫入或者更新操作時,就必須得表現(xiàn)出 ACID 的 4 個重要特性:
原子性(Atomicity):一個事務(wù)中的所有操作,要么全部完成,要么全部不完成,不會結(jié)束在中間某個環(huán)節(jié)。事務(wù)在執(zhí)行過程中發(fā)生錯誤,會被回滾(Rollback)到事務(wù)開始前的狀態(tài),就像這個事務(wù)從來沒有執(zhí)行過一樣。
一致性(Consistency):在事務(wù)開始之前和事務(wù)結(jié)束以后,數(shù)據(jù)庫的完整性沒有被破壞。
事務(wù)隔離(Isolation):數(shù)據(jù)庫允許多個并發(fā)事務(wù)同時對其數(shù)據(jù)進(jìn)行讀寫和修改,隔離性可以防止多個事務(wù)并發(fā)執(zhí)行時由于交叉執(zhí)行而導(dǎo)致數(shù)據(jù)的不一致。
持久性(Durability):事務(wù)處理結(jié)束后,對數(shù)據(jù)的修改就是永久的,即便系統(tǒng)故障也不會丟失。

Spring事務(wù)其實(shí)就是在上一個AOP內(nèi)容中切面邏輯中實(shí)現(xiàn)的,在開啟事務(wù)后,Spring容器會用事務(wù)管理器新建一個數(shù)據(jù)庫連接,并且一開始設(shè)置autocommint=false,然后執(zhí)行普通對象中的相關(guān)方法如果沒有拋異常就會提交,否則就會回滾。然后下面我們來分析個案例代碼如下

@Component()
public class Test{


    @Transactional
    public  void hello(){
        System.out.println("good");
        a();
    }

    @Transactional(propagation = Propagation.NEVER)
    public void a(){
        System.out.println("a");
    }
}

@SpringBootApplication
@MapperScan("com.example.demo.mybatisplus")
@EnableTransactionManagement
public class DemoApplication {


    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
        Test bean = run.getBean(Test.class);
        bean.hello();
    }

}

PROPAGATION_NEVER該傳播機(jī)制不支持外層事務(wù),即如果外層有事務(wù)就拋出異常,當(dāng)我們獲取Test Bean對象的時候,然后執(zhí)行hello方法的時候他會拋出異常嗎?實(shí)際上是不會的,那到底是什么原因呢?我們通過上面的內(nèi)容我們知道了Spring事務(wù)是在代理類中的相關(guān)方法的代理邏輯中執(zhí)行的,在執(zhí)行方法切面邏輯的時候是由我們的代理對象執(zhí)行事務(wù)管理器相關(guān)操作的,而a方法實(shí)際的執(zhí)行的是普通對象并不是代理對象,普通對象在執(zhí)行a方法的時候是不會有事務(wù)的操作的,注解僅僅就成為了一個擺設(shè)。如果有興趣的小伙伴可以嘗試一下。那么怎么解決問題呢?當(dāng)有@Transactional的類就會在Spring容器中生成代理對象放到單例池當(dāng)中,那么可以在這個對象中使用@Autowired注解依賴注入代理對象,把a(bǔ)方法放在這個代理對象對應(yīng)的普通類中,然后通過這個依賴注入的代理對象調(diào)用a方法,就可以正常的解決。還有一個辦法就是如下面代碼也可以正常的解決。

@Transactional
public  void hello(){
    System.out.println("good");
    Test o = (Test) AopContext.currentProxy();
    o.a();
}

循環(huán)依賴

這里引用

被 Spring 管理的對象叫做 Bean 。Bean的生成步驟如下:

Spring 掃描 class 得到 BeanDefinition;
根據(jù)得到的 BeanDefinition 去生成 bean;
首先根據(jù) class 推斷構(gòu)造方法;
根據(jù)推斷出來的構(gòu)造方法,反射,得到一個對象(暫時叫做原始對象);
填充原始對象中的屬性(依賴注入);
如果原始對象中的某個方法被 AOP 了,那么則需要根據(jù)原始對象生成一個代理對象;
把最終生成的代理對象放入單例池(源碼中叫做 singletonObjects)中,下次 getBean 時就直接從單例池拿即可;
對于 Spring 中的 Bean 的生成過程,步驟還是很多的,并且不僅僅只有上面的7步,還有很多很多,這里不詳細(xì)說了。

我們可以發(fā)現(xiàn),在得到一個原始對象后,Spring 需要給對象中的屬性進(jìn)行依賴注入,那么這個注入過程是怎樣的?

比如上文說的 A 類,A 類中存在一個 B 類的 b 屬性,所以,當(dāng) A 類生成了一個原始對象之后,就會去給 b 屬性去賦值,此時就會根據(jù) b 屬性的類型和屬性名去 BeanFactory 中去獲取 B 類所對應(yīng)的單例bean。

1. 如果此時 BeanFactory 中存在 B 對應(yīng)的 Bean,那么直接拿來賦值給 b 屬性;
2. 如果此時 BeanFactory 中不存在 B 對應(yīng)的 Bean,則需要生成一個 B 對應(yīng)的 Bean,然后賦值給 b屬性。

問題就出現(xiàn)在「第二種」情況,如果此時 B 類在 BeanFactory 中還沒有生成對應(yīng)的 Bean,那么就需要去生成,就會經(jīng)過 B 的 Bean 的生命周期。

那么在創(chuàng)建 B 類的 Bean 的過程中,如果 B 類中存在一個 A 類的 a 屬性,那么在創(chuàng)建 B 的 Bean 的過程中就需要 A 類對應(yīng)的 Bean,但是,觸發(fā) B 類 Bean 的創(chuàng)建的條件是 A 類 Bean 在創(chuàng)建過程中的依賴注入,所以這里就出現(xiàn)了循環(huán)依賴:

A Bean創(chuàng)建–>依賴了 B 屬性–>觸發(fā) B Bean創(chuàng)建—>B 依賴了 A 屬性—>需要 A Bean(但A Bean還在創(chuàng)建過程中)

從而導(dǎo)致 A Bean 創(chuàng)建不出來,B Bean 也創(chuàng)建不出來。

這里就用到三級緩存了,這里設(shè)置兩個類Aservice,Bservice。Aservice中有Bservice屬性的注入,Bservice中有Aservice屬性的注入。那么三級緩存是如何解決問題的呢?這里先對三級緩存進(jìn)行簡單的描述。

「singletonObjects」:緩存某個 beanName 對應(yīng)的經(jīng)過了完整生命周期的bean也就是我們的單例池;
「earlySingletonObjects」:緩存提前拿原始對象進(jìn)行了 AOP 之后得到的代理對象,原始對象還沒有進(jìn)行屬性注入和后續(xù)的 BeanPostProcesso r等生命周期;
「singletonFactories」:緩存的是一個 ObjectFactory ,主要用來去生成原始對象進(jìn)行了 AOP之后得到的「代理對象」,在每個 Bean 的生成過程中,都會提前暴露一個工廠,這個工廠可能用到,也可能用不到,如果沒有出現(xiàn)循環(huán)依賴依賴本 bean,那么這個工廠無用,本 bean 按照自己的生命周期執(zhí)行,執(zhí)行完后直接把本 bean 放入 singletonObjects 中即可,如果出現(xiàn)了循環(huán)依賴依賴了本 bean,則另外那個 bean 執(zhí)行 ObjectFactory 提交得到一個 AOP 之后的代理對象(如果有 AOP 的話,如果無需 AOP ,則直接得到一個原始對象)。

那么如何打破循環(huán)依賴呢?

摘用網(wǎng)上的圖片

Spring源碼篇(你值得擁有)

Aservice ?在Spring容器創(chuàng)建過程中,在實(shí)例化后把Aservice普通對象放在緩存中,然后進(jìn)行Bservice屬性的依賴注入,首先從單例池中尋找Bservice,如果找到就會賦值,找不到就會創(chuàng)建Bservice,在進(jìn)行Aservice注入的時候從單例池尋找,找不到然后從緩存中尋找進(jìn)行屬性的注入。此時循環(huán)依賴問題得以解決。因?yàn)樵谡麄€過程中AService都是單例的 , 所以即使從緩存中拿到的AService的原始對象也沒有關(guān)系 , 因?yàn)樵诤罄m(xù)的Bean生命周期中 ,AService在堆內(nèi)存中沒有發(fā)生變化。這種情況當(dāng)Aservice對象沒有AOP的時候這種情況是沒有問題的,如果Aservice類有AOP,從上文可知那么單例池中的該對象是代理對象,而我們在Bservice中依賴注入的Aservice是普通對象,這顯而易見就有問題了。

所以就需要二級緩存了,在Bservice進(jìn)行Aservice屬性注入的時候,要進(jìn)行提前AOP,而上面的緩存就相當(dāng)于三級緩存存儲原始對象,出現(xiàn)循環(huán)依賴后從二級緩存earlySingletonObjects中獲取如果獲取不到對應(yīng)的對象,然后就會從三級緩存中獲取原始對象,如果是AOP就生成代理對象,不是就是普通對象然后放在二級緩存中,此時這個對象還不能放入單例池中,為什么呢?假如這里是個代理對象,代理對象的Target原始對象還沒有完成生命周期屬性還沒有完全注入完成,如果在這里放入單例池,在多線程環(huán)境下在這時從單例池中獲取這個bean對象就會發(fā)生不可預(yù)期的錯誤。當(dāng)Bservice Bean對象創(chuàng)建完成后然后在Aservice中填充完所有屬性后,就可以從二級緩存中獲取該對象然后放到單例池中了。

手寫源碼篇

通過手寫模擬,了解Spring的底層源碼啟動過程

通過手寫模擬,了解掃描邏輯和依賴注入等底層源碼工作流程

通過手寫模擬,了解初始化機(jī)制工作流程

通過手寫模擬,了解BeanDefinition、BeanPostProcessor的概念

通過手寫模擬,了解Spring AOP的底層源碼工作流程

目錄結(jié)構(gòu)

Spring源碼篇(你值得擁有)

啟動代碼

public class test {
    public static void main(String[] args) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        ApplicationContext applicationContext = new ApplicationContext(AppConfig.class);
        UserInterface userservice = (UserInterface) applicationContext.getBean("userservice");
        userservice.test();

    }
}

運(yùn)行代碼如下圖

Spring源碼篇(你值得擁有)

Component注解

這里其余的注解代碼省略

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

ApplicationContext類

這個類主要是掃描@ComponentScan指定的包路徑生成其中類含有@Componet注解的Bean對象。

public class ApplicationContext {


    private Class configClass;
    private ConcurrentHashMap<String,Object> singletonObjects=new ConcurrentHashMap<>();//單列池
    private ConcurrentHashMap<String,BeanDefinition> beanDefinitionConcurrentHashMap=new ConcurrentHashMap<>();
    private List<BeanPostProcessor> beanPostProcessorList=new ArrayList<>();

    public ApplicationContext(Class configClass) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        this.configClass = configClass;
        scan(configClass);
        for (Map.Entry<String, BeanDefinition> stringBeanDefinitionEntry : beanDefinitionConcurrentHashMap.entrySet()) {
            String beanName = stringBeanDefinitionEntry.getKey();
            BeanDefinition beanDefinition = stringBeanDefinitionEntry.getValue();
            if(beanDefinition.getScope().equals("singleton")){
                Object bean = createBean(beanDefinition);
                singletonObjects.put(beanName,bean);
            }
        }
    }

    //創(chuàng)造Bean對象
    public Object createBean(BeanDefinition beanDefinition){
        Class clazz = beanDefinition.getClazz();
        Object o = null;
        try {
            o = clazz.getDeclaredConstructor().newInstance();
            for (Field declaredField : clazz.getDeclaredFields()) {
                if(declaredField.isAnnotationPresent(Autowired.class)){
                    Object bean = getBean(declaredField.getName());
                    declaredField.setAccessible(true);
                    declaredField.set(o,bean);//此處有bug,當(dāng)singleton時注入失敗為null,當(dāng)注入的屬性對象bean在單例池排序靠前可以成功。
                }
            }//getFields為獲得所有public的屬性,這里為所有
            //后置處理器,這里沒有對beanName進(jìn)行設(shè)計(jì)
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                beanPostProcessor.postProcessBeforeInitialization(o,null);
            }

            //下面為初始化機(jī)制
            if (o instanceof InitializingBean){
                try {
                    ((InitializingBean) o).afterPropertiesSet();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
               o = beanPostProcessor.postProcessAfterInitialization(o, null);
            }

            return o;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }

   //掃描包路徑
    public void scan(Class configClass) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        ComponentScan componentScan = (ComponentScan) configClass.getDeclaredAnnotation(ComponentScan.class);
        String value = componentScan.value();
//        System.out.println(value);
        String replace = value.replace('.', '/');
        ClassLoader classLoader = ApplicationContext.class.getClassLoader();
        URL resource = classLoader.getResource(replace);//根據(jù)相對路徑 com.example.service
//        System.out.println(resource);
        File file=new File(resource.getFile());
        if(file.isDirectory()){
            File[] files=file.listFiles();
            for (File file1 : files) {
                String absolutePath = file1.getAbsolutePath();
                if (absolutePath.endsWith(".class")) {
//                System.out.println(absolutePath);
                    String com = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
                    String replace1 = com.replace("\\", ".");//注意\是轉(zhuǎn)義字符,而/不是,com.example.service.xx
//                System.out.println(replace1);
                    Class<?> aClass = null;
                    try {
                        aClass = classLoader.loadClass(replace1);
                        if (aClass.isAnnotationPresent(Component.class)) {
                            if(BeanPostProcessor.class.isAssignableFrom(aClass)){//該class對象是否實(shí)現(xiàn)了BeanPostProcessor接口,不能用instanceof
                               BeanPostProcessor beanPostProcessor = (BeanPostProcessor) aClass.getDeclaredConstructor().newInstance();
                                beanPostProcessorList.add(beanPostProcessor);
                            }


                            Component declaredAnnotation = aClass.getDeclaredAnnotation(Component.class);
                            String beanName = declaredAnnotation.value();
                            BeanDefinition beanDefinition = new BeanDefinition();
                            beanDefinition.setClazz(aClass);
                            if (aClass.isAnnotationPresent(Scope.class)) {
                                Scope scope = aClass.getDeclaredAnnotation(Scope.class);
                                beanDefinition.setScope(scope.value());
                            } else {
                                beanDefinition.setScope("singleton");
                            }
                            beanDefinitionConcurrentHashMap.put(beanName,beanDefinition);

                        }
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }


                }
            }
        }
    }


   //從Spring容器中獲取Bean對象
    public Object getBean(String beanName){
      if(beanDefinitionConcurrentHashMap.containsKey(beanName)){
          BeanDefinition beanDefinition = beanDefinitionConcurrentHashMap.get(beanName);
          if(beanDefinition.getScope().equals("singleton")){
              Object o = singletonObjects.get(beanName);
              return o;
          }
          else {
              Object bean = createBean(beanDefinition);
              return bean;
          }
      }else {
        throw new NullPointerException();
      }
    }
}

BeanDefinition類

這個類主要包含Bean對象的class類型和scope。

public class BeanDefinition {
    private Class clazz;
    private String scope;

    public BeanDefinition(Class clazz, String scope) {
        this.clazz = clazz;
        this.scope = scope;
    }

    public BeanDefinition() {
    }

    public Class getClazz() {
        return clazz;
    }

    public void setClazz(Class clazz) {
        this.clazz = clazz;
    }

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }
}

BeanPostProcessor接口實(shí)現(xiàn)

繼承BeanPostProcessor接口主要是實(shí)現(xiàn)初始化前和初始化后的操作。

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        if(bean instanceof UserInterface)
        System.out.println("初始化前");
        return null;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        //AOP模擬
        if(bean instanceof UserInterface){
            Object proxyInstance = Proxy.newProxyInstance(MyBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("代理前");
                    Object invoke = method.invoke(bean, args);
                    System.out.println("代理后");
                    System.out.println("初始化后");
                    return invoke;
                }
            });
            return proxyInstance;
        }

        return bean;
    }
}

相關(guān)代碼可以在我的文件資源下載https://download.csdn.net/download/qq_43649937/87506483?spm=1001.2014.3001.5503文章來源地址http://www.zghlxwxcb.cn/news/detail-430805.html

到了這里,關(guān)于Spring源碼篇(你值得擁有)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 200+的AI寫作工具你值得擁有

    200+的AI寫作工具你值得擁有 工具 簡介 鏈接 分類 描述1 描述2 是否免費(fèi) Better Synonyms BetterSynonyms是一個方便的工具,可以幫助你在特定語境中找到更好的同義詞。它可以幫助你搜索更自然地放入句子中的同義詞,從而更容易傳達(dá)出你想要表達(dá)的意思。 http://www.bettersynonyms.com 寫

    2024年02月05日
    瀏覽(21)
  • 軟件工程師,TypeScript值得你擁有

    軟件工程師,TypeScript值得你擁有

    背景 ?????????□ TypeScript起源于使用JavaScript開發(fā)的大型項(xiàng)目。由于JavaScript語言本身的局限性,難以勝任和維護(hù)大型項(xiàng)目開發(fā),因此微軟開發(fā)了TypeScript,使得其能夠勝任開發(fā)大型項(xiàng)目。 ????????□ TypeScript是微軟開發(fā)的一個開源的編程語言,通過在JavaScript的基礎(chǔ)上添

    2024年02月16日
    瀏覽(21)
  • 盤點(diǎn)搜索引擎一些高級技巧,你值得擁有!

    盤點(diǎn)搜索引擎一些高級技巧,你值得擁有!

    搜索引擎是我們?nèi)粘I钪胁豢苫蛉钡墓ぞ咧唬ㄟ^搜索引擎,我們可以在互聯(lián)網(wǎng)上找到任何我們需要的信息。 平時我們使用搜索引擎除來直接輸入外,它們還包含了一些高級技巧?,接下來我們以 Google 搜索引擎為例進(jìn)行演示。 1、雙引號 \\\"\\\" 雙引號?\\\"\\\"?可以讓搜索

    2024年01月16日
    瀏覽(27)
  • 5款辦公必備的好軟件,你值得擁有

    5款辦公必備的好軟件,你值得擁有

    隨著網(wǎng)絡(luò)信息技術(shù)的發(fā)展,越來越多的人在辦公時需要用到電腦了。如果你想提高辦公效率,那么就少不了工具的幫忙,今天給大家分享5款辦公必備的好軟件。 TagSpaces 是一款開源的文件管理工具,它可以通過標(biāo)簽來組織文件,讓你以更符合人類思維方式的方式管理文件。它界

    2024年02月03日
    瀏覽(20)
  • JavaFX愛好者看過來,這款工具值得擁有

    JavaFX愛好者看過來,這款工具值得擁有

    ? ? ? ?各位CSDN的博友們,隨著各地政策的放開,大伙現(xiàn)在是在水深火熱當(dāng)中呢?還是天選打工人-安然無羊。在這里,希望陽了的朋友,趕緊恢復(fù)健康,早日康復(fù)。希望沒有陽的朋友們,繼續(xù)堅(jiān)持,萬一要陽,也一定要做一直美羊羊。 ? ? ? 之前因?yàn)楣ぷ餍枰?,看了一些J

    2023年04月20日
    瀏覽(37)
  • 微服務(wù)必學(xué)!RedisSearch終極使用指南,你值得擁有!

    微服務(wù)必學(xué)!RedisSearch終極使用指南,你值得擁有!

    ????歡迎來到我的CSDN主頁!???? ??我是塵緣,一個在CSDN分享筆記的博主。???? ??點(diǎn)擊這里,就可以查看我的主頁啦!???? 塵緣的個人主頁 ??如果感覺還不錯的話請給我點(diǎn)贊吧!???? ??期待你的加入,一起學(xué)習(xí),一起進(jìn)步!???? 前些天發(fā)現(xiàn)了一個巨牛的人工智

    2024年02月08日
    瀏覽(18)
  • 八款免費(fèi) & 開源的 SQL 客戶端,你值得擁有!

    八款免費(fèi) & 開源的 SQL 客戶端,你值得擁有!

    訪問和修改數(shù)據(jù)庫等操作雖然令人生畏,但卻是必不可少的。過去,訪問數(shù)據(jù)庫的唯一方式就是通過命令行,這樣不僅不夠直觀,也容易出錯,釀成大事。好在經(jīng)過幾十年發(fā)展,已經(jīng)出了很多帶有可視化界面 (GUI) 的數(shù)據(jù)庫圖形客戶端工具能夠幫助簡化「管理數(shù)據(jù)庫」,他們中

    2024年02月04日
    瀏覽(32)
  • 全新最全Stable Diffusion 提示詞資料包,你值得擁有!?。。? decoding=

    全新最全Stable Diffusion 提示詞資料包,你值得擁有?。。?!

    Stable Diffusion無疑是最近最火的AI繪畫工具之一,所以本期給大家?guī)砹巳耂table Diffusion 提示詞資料包(文末可獲?。?Stable Diffusion提示詞是什么? 提示詞是prompt翻譯過來的詞匯,在我們業(yè)內(nèi)人稱之為、咒語,在Stable Diffusion中一般分為正向提示詞和負(fù)向提示詞。 打個比

    2024年02月03日
    瀏覽(16)
  • 值得擁有并收藏的 3個安卓/鴻蒙手機(jī)解鎖軟件

    值得擁有并收藏的 3個安卓/鴻蒙手機(jī)解鎖軟件

    手機(jī)無論支持哪種操作系統(tǒng),都占據(jù)了每個人口袋里的空間。隨著大量移動設(shè)備的使用,搜索引擎上也出現(xiàn)了同樣數(shù)量的查詢,其中最常見的是提供 安卓/鴻蒙屏幕鎖定刪除工具 。由于安卓是當(dāng)今最暢銷的設(shè)備,我們的首要任務(wù)是為您提供最好的安卓手機(jī)解鎖軟件。 幾乎所有

    2024年02月11日
    瀏覽(28)
  • 推薦幾款小眾且無廣告的軟件,你值得擁有

    推薦幾款小眾且無廣告的軟件,你值得擁有

    你是否喜歡一些小眾且無廣告的軟件?如果是的話,我這邊有一些給你推薦的。 ? EyeLoveU是一款免費(fèi)的護(hù)眼軟件,可以在你使用電腦一段時間后,提醒你該讓眼睛休息。EyeLoveU是一種智能的眼睛保護(hù)程序,根據(jù)你的鼠標(biāo)和鍵盤的操作動作,來判斷你的電腦使用時間。它還提供

    2024年02月14日
    瀏覽(22)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包