概念篇
下面是本文章關(guān)于Spring底層原理的章節(jié)
Bean的創(chuàng)建的生命周期
類-》推斷構(gòu)造方法-》根據(jù)構(gòu)造方法創(chuàng)建普通對(duì)象-》依賴注入(@Autowired等進(jìn)行屬性注入)-》初始化前(@PostConstruct)->初始化(InitializingBean)-》初始化后(AOP)-》代理對(duì)象(沒(méi)有開啟AOP就會(huì)把普通對(duì)象放入單例池)-》放入單例池-》Bean對(duì)象
依賴注入
在Spring容器中創(chuàng)建了一個(gè)普通對(duì)象后,如果這個(gè)對(duì)象有類似于@Autowired注解的屬性,如何給這個(gè)屬性賦值呢?這里利用的是反射的機(jī)制,在創(chuàng)建完一個(gè)普通對(duì)象后,利用反射機(jī)制看有沒(méi)有@Autowird注解的屬性,如果依賴注入的bean為單例,首先從單例池中尋找,找到就賦值注入,找不到就創(chuàng)建然后注入屬性,如果這個(gè)bean為多例,就會(huì)直接new 一個(gè)對(duì)象出來(lái)然后賦值。這個(gè)具體可以看下面的模擬代碼進(jìn)行深入理解。
推斷構(gòu)造方法
在Spring容器中使用構(gòu)造方法創(chuàng)建對(duì)象的時(shí)候默認(rèn)采用無(wú)參構(gòu)造方法。在Spring容器中創(chuàng)建對(duì)象是通過(guò)反射根據(jù)構(gòu)造方法進(jìn)行創(chuàng)建的,至于具體根據(jù)哪個(gè)構(gòu)造方法進(jìn)行創(chuàng)建對(duì)象,內(nèi)容如下:
1.只有一個(gè)構(gòu)造方法,那么實(shí)例化就只能使用這個(gè)構(gòu)造方法了。有參的話(前提是根據(jù)參數(shù)類型或者名字可以找到唯一的bean。
2.有多個(gè)構(gòu)造方法,不管構(gòu)造方法參數(shù)是一個(gè)還是多個(gè),那么Spring會(huì)去找默認(rèn)的無(wú)參的構(gòu)造方法,找不到則報(bào)錯(cuò)。
3.多個(gè)構(gòu)造方法,并且開發(fā)者指定了想使用的構(gòu)造方法,那么就用這個(gè)構(gòu)造方法
通過(guò)@Autowired注解,@Autowired注解可以寫在構(gòu)造方法上,所以哪個(gè)構(gòu)造方法上寫了@Autowired注解,表示開發(fā)者想使用哪個(gè)構(gòu)造方法。通過(guò)@Autowired注解的方式,需要Spring通過(guò)byType+byName的方式去找到符合條件的bean作為構(gòu)造方法的參數(shù)值,當(dāng)然找不到是要報(bào)錯(cuò)的。通過(guò)byType找如果只有一個(gè)就使用該Bean對(duì)象,如果有多個(gè)再根據(jù)名字去找,Spring容器在尋找過(guò)程中是根據(jù)參數(shù)名作為名字去尋找的,找不到則報(bào)錯(cuò)。這個(gè)類似于@Autowired注解,一開始根據(jù)類型去尋找,如果有多個(gè),再根據(jù)屬性名去找對(duì)應(yīng)的是該名字的Bean對(duì)象。
@PostConstruct
如果想要在對(duì)象初始化之前執(zhí)行該對(duì)象中的一些方法,可以在該對(duì)象方法上加上@PostConstruct注解。在Spring容器中初始化之前執(zhí)行有該注解的方法。
初始化
Spring容器中對(duì)于對(duì)象的初始化可以通過(guò)繼承 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é)果如下圖:
AOP
AOP簡(jiǎn)介
這里先對(duì)AOP進(jìn)行簡(jiǎn)單的介紹
AOP (Aspect?Orient Programming),直譯過(guò)來(lái)就是 面向切面編程,AOP 是一種編程思想,是面向?qū)ο缶幊蹋∣OP)的一種補(bǔ)充。面向切面編程,實(shí)現(xiàn)在不修改源代碼的情況下給程序動(dòng)態(tài)統(tǒng)一添加額外功能的一種技術(shù)。AOP可以攔截指定的方法并且對(duì)方法增強(qiáng),而且無(wú)需侵入到業(yè)務(wù)代碼中,使業(yè)務(wù)與非業(yè)務(wù)處理邏輯分離,比如Spring的事務(wù),通過(guò)事務(wù)的注解配置,Spring會(huì)自動(dòng)在業(yè)務(wù)方法中開啟、提交業(yè)務(wù),并且在業(yè)務(wù)處理失敗時(shí),執(zhí)行相應(yīng)的回滾策略。AOP可以攔截指定的方法并且對(duì)方法增強(qiáng),而且無(wú)需侵入到業(yè)務(wù)代碼中,使業(yè)務(wù)與非業(yè)務(wù)處理邏輯分離,比如Spring的事務(wù),通過(guò)事務(wù)的注解配置,Spring會(huì)自動(dòng)在業(yè)務(wù)方法中開啟、提交業(yè)務(wù),并且在業(yè)務(wù)處理失敗時(shí),執(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)類對(duì)象"+joinPoint.getTarget()+"被增強(qiáng)的方法"+joinPoint.getSignature().getName());
}
//后置返回通知
@AfterReturning("myPointCut()")
public void afterreturn(JoinPoint joinPoint){
System.out.println("后置返回通知");
System.out.println("目標(biāo)類對(duì)象"+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é)果如下圖所示
?這里對(duì)于Spring5通知的執(zhí)行順序進(jìn)行簡(jiǎ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原理
對(duì)于上面的代碼我們?cè)趫?zhí)行test.hello的時(shí)候我們的對(duì)象是Test對(duì)象嗎?還是代理對(duì)象?經(jīng)過(guò)debug我們來(lái)看一下。如下圖證實(shí)我們拿到的對(duì)象是代理對(duì)象。
?注意在Spring容器中假如真實(shí)對(duì)象中有類似@Autowired注解進(jìn)行依賴注入的時(shí)候,我們?cè)谶@里debug拿到的代理對(duì)象關(guān)于這樣的屬性實(shí)際上是空的,但是直接運(yùn)行的時(shí)候?qū)嶋H上又會(huì)獲得依賴注入對(duì)象,這是什么原因呢?
在Spring容器中代理類其實(shí)是真實(shí)類的子類,通過(guò)extends繼承,既然代理類是真實(shí)類的子對(duì)象,那么他們之間是怎么實(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í)行父類的時(shí)候,在執(zhí)行方法中的有依賴注入的屬性其實(shí)是空的,因?yàn)楦割悇?chuàng)建了一個(gè)對(duì)象并為這個(gè)屬性賦值,它的子類并不會(huì)獲得該屬性的值的。那解決辦法呢?那就是在My類中創(chuàng)建一個(gè)Test類對(duì)象的屬性Target,并把真實(shí)類賦值給Target屬性,然后在執(zhí)行方法中執(zhí)行Target.hello方法就可以了。
Spring的事務(wù)
Spring聲明式事務(wù)管理是通過(guò)AOP技術(shù)實(shí)現(xiàn)的事務(wù)管理,其本質(zhì)是對(duì)方法前后進(jìn)行攔截,在目標(biāo)方法開始之前創(chuàng)建一個(gè)事務(wù),在目標(biāo)方法執(zhí)行之后,根據(jù)執(zhí)行情況提交或回滾事務(wù)。
事務(wù)在邏輯上是一組操作,要么執(zhí)行,要不都不執(zhí)行。主要是針對(duì)數(shù)據(jù)庫(kù)而言的,為了保證事務(wù)是正確可靠的,在數(shù)據(jù)庫(kù)進(jìn)行寫入或者更新操作時(shí),就必須得表現(xiàn)出 ACID 的 4 個(gè)重要特性:
原子性(Atomicity):一個(gè)事務(wù)中的所有操作,要么全部完成,要么全部不完成,不會(huì)結(jié)束在中間某個(gè)環(huán)節(jié)。事務(wù)在執(zhí)行過(guò)程中發(fā)生錯(cuò)誤,會(huì)被回滾(Rollback)到事務(wù)開始前的狀態(tài),就像這個(gè)事務(wù)從來(lái)沒(méi)有執(zhí)行過(guò)一樣。
一致性(Consistency):在事務(wù)開始之前和事務(wù)結(jié)束以后,數(shù)據(jù)庫(kù)的完整性沒(méi)有被破壞。
事務(wù)隔離(Isolation):數(shù)據(jù)庫(kù)允許多個(gè)并發(fā)事務(wù)同時(shí)對(duì)其數(shù)據(jù)進(jìn)行讀寫和修改,隔離性可以防止多個(gè)事務(wù)并發(fā)執(zhí)行時(shí)由于交叉執(zhí)行而導(dǎo)致數(shù)據(jù)的不一致。
持久性(Durability):事務(wù)處理結(jié)束后,對(duì)數(shù)據(jù)的修改就是永久的,即便系統(tǒng)故障也不會(huì)丟失。
Spring事務(wù)其實(shí)就是在上一個(gè)AOP內(nèi)容中切面邏輯中實(shí)現(xiàn)的,在開啟事務(wù)后,Spring容器會(huì)用事務(wù)管理器新建一個(gè)數(shù)據(jù)庫(kù)連接,并且一開始設(shè)置autocommint=false,然后執(zhí)行普通對(duì)象中的相關(guān)方法如果沒(méi)有拋異常就會(huì)提交,否則就會(huì)回滾。然后下面我們來(lái)分析個(gè)案例代碼如下
@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對(duì)象的時(shí)候,然后執(zhí)行hello方法的時(shí)候他會(huì)拋出異常嗎?實(shí)際上是不會(huì)的,那到底是什么原因呢?我們通過(guò)上面的內(nèi)容我們知道了Spring事務(wù)是在代理類中的相關(guān)方法的代理邏輯中執(zhí)行的,在執(zhí)行方法切面邏輯的時(shí)候是由我們的代理對(duì)象執(zhí)行事務(wù)管理器相關(guān)操作的,而a方法實(shí)際的執(zhí)行的是普通對(duì)象并不是代理對(duì)象,普通對(duì)象在執(zhí)行a方法的時(shí)候是不會(huì)有事務(wù)的操作的,注解僅僅就成為了一個(gè)擺設(shè)。如果有興趣的小伙伴可以嘗試一下。那么怎么解決問(wèn)題呢?當(dāng)有@Transactional的類就會(huì)在Spring容器中生成代理對(duì)象放到單例池當(dāng)中,那么可以在這個(gè)對(duì)象中使用@Autowired注解依賴注入代理對(duì)象,把a(bǔ)方法放在這個(gè)代理對(duì)象對(duì)應(yīng)的普通類中,然后通過(guò)這個(gè)依賴注入的代理對(duì)象調(diào)用a方法,就可以正常的解決。還有一個(gè)辦法就是如下面代碼也可以正常的解決。
@Transactional public void hello(){ System.out.println("good"); Test o = (Test) AopContext.currentProxy(); o.a(); }
循環(huán)依賴
這里引用
被 Spring 管理的對(duì)象叫做 Bean 。Bean的生成步驟如下:
Spring 掃描 class 得到 BeanDefinition;
根據(jù)得到的 BeanDefinition 去生成 bean;
首先根據(jù) class 推斷構(gòu)造方法;
根據(jù)推斷出來(lái)的構(gòu)造方法,反射,得到一個(gè)對(duì)象(暫時(shí)叫做原始對(duì)象);
填充原始對(duì)象中的屬性(依賴注入);
如果原始對(duì)象中的某個(gè)方法被 AOP 了,那么則需要根據(jù)原始對(duì)象生成一個(gè)代理對(duì)象;
把最終生成的代理對(duì)象放入單例池(源碼中叫做 singletonObjects)中,下次 getBean 時(shí)就直接從單例池拿即可;
對(duì)于 Spring 中的 Bean 的生成過(guò)程,步驟還是很多的,并且不僅僅只有上面的7步,還有很多很多,這里不詳細(xì)說(shuō)了。我們可以發(fā)現(xiàn),在得到一個(gè)原始對(duì)象后,Spring 需要給對(duì)象中的屬性進(jìn)行依賴注入,那么這個(gè)注入過(guò)程是怎樣的?
比如上文說(shuō)的 A 類,A 類中存在一個(gè) B 類的 b 屬性,所以,當(dāng) A 類生成了一個(gè)原始對(duì)象之后,就會(huì)去給 b 屬性去賦值,此時(shí)就會(huì)根據(jù) b 屬性的類型和屬性名去 BeanFactory 中去獲取 B 類所對(duì)應(yīng)的單例bean。
1. 如果此時(shí) BeanFactory 中存在 B 對(duì)應(yīng)的 Bean,那么直接拿來(lái)賦值給 b 屬性;
2. 如果此時(shí) BeanFactory 中不存在 B 對(duì)應(yīng)的 Bean,則需要生成一個(gè) B 對(duì)應(yīng)的 Bean,然后賦值給 b屬性。問(wèn)題就出現(xiàn)在「第二種」情況,如果此時(shí) B 類在 BeanFactory 中還沒(méi)有生成對(duì)應(yīng)的 Bean,那么就需要去生成,就會(huì)經(jīng)過(guò) B 的 Bean 的生命周期。
那么在創(chuàng)建 B 類的 Bean 的過(guò)程中,如果 B 類中存在一個(gè) A 類的 a 屬性,那么在創(chuàng)建 B 的 Bean 的過(guò)程中就需要 A 類對(duì)應(yīng)的 Bean,但是,觸發(fā) B 類 Bean 的創(chuàng)建的條件是 A 類 Bean 在創(chuàng)建過(guò)程中的依賴注入,所以這里就出現(xiàn)了循環(huán)依賴:
A Bean創(chuàng)建–>依賴了 B 屬性–>觸發(fā) B Bean創(chuàng)建—>B 依賴了 A 屬性—>需要 A Bean(但A Bean還在創(chuàng)建過(guò)程中)
從而導(dǎo)致 A Bean 創(chuàng)建不出來(lái),B Bean 也創(chuàng)建不出來(lái)。
這里就用到三級(jí)緩存了,這里設(shè)置兩個(gè)類Aservice,Bservice。Aservice中有Bservice屬性的注入,Bservice中有Aservice屬性的注入。那么三級(jí)緩存是如何解決問(wèn)題的呢?這里先對(duì)三級(jí)緩存進(jìn)行簡(jiǎn)單的描述。
「singletonObjects」:緩存某個(gè) beanName 對(duì)應(yīng)的經(jīng)過(guò)了完整生命周期的bean也就是我們的單例池;
「earlySingletonObjects」:緩存提前拿原始對(duì)象進(jìn)行了 AOP 之后得到的代理對(duì)象,原始對(duì)象還沒(méi)有進(jìn)行屬性注入和后續(xù)的 BeanPostProcesso r等生命周期;
「singletonFactories」:緩存的是一個(gè) ObjectFactory ,主要用來(lái)去生成原始對(duì)象進(jìn)行了 AOP之后得到的「代理對(duì)象」,在每個(gè) Bean 的生成過(guò)程中,都會(huì)提前暴露一個(gè)工廠,這個(gè)工廠可能用到,也可能用不到,如果沒(méi)有出現(xiàn)循環(huán)依賴依賴本 bean,那么這個(gè)工廠無(wú)用,本 bean 按照自己的生命周期執(zhí)行,執(zhí)行完后直接把本 bean 放入 singletonObjects 中即可,如果出現(xiàn)了循環(huán)依賴依賴了本 bean,則另外那個(gè) bean 執(zhí)行 ObjectFactory 提交得到一個(gè) AOP 之后的代理對(duì)象(如果有 AOP 的話,如果無(wú)需 AOP ,則直接得到一個(gè)原始對(duì)象)。
那么如何打破循環(huán)依賴呢?
摘用網(wǎng)上的圖片
Aservice ?在Spring容器創(chuàng)建過(guò)程中,在實(shí)例化后把Aservice普通對(duì)象放在緩存中,然后進(jìn)行Bservice屬性的依賴注入,首先從單例池中尋找Bservice,如果找到就會(huì)賦值,找不到就會(huì)創(chuàng)建Bservice,在進(jìn)行Aservice注入的時(shí)候從單例池尋找,找不到然后從緩存中尋找進(jìn)行屬性的注入。此時(shí)循環(huán)依賴問(wèn)題得以解決。因?yàn)樵谡麄€(gè)過(guò)程中AService都是單例的 , 所以即使從緩存中拿到的AService的原始對(duì)象也沒(méi)有關(guān)系 , 因?yàn)樵诤罄m(xù)的Bean生命周期中 ,AService在堆內(nèi)存中沒(méi)有發(fā)生變化。這種情況當(dāng)Aservice對(duì)象沒(méi)有AOP的時(shí)候這種情況是沒(méi)有問(wèn)題的,如果Aservice類有AOP,從上文可知那么單例池中的該對(duì)象是代理對(duì)象,而我們?cè)贐service中依賴注入的Aservice是普通對(duì)象,這顯而易見就有問(wèn)題了。
所以就需要二級(jí)緩存了,在Bservice進(jìn)行Aservice屬性注入的時(shí)候,要進(jìn)行提前AOP,而上面的緩存就相當(dāng)于三級(jí)緩存存儲(chǔ)原始對(duì)象,出現(xiàn)循環(huán)依賴后從二級(jí)緩存earlySingletonObjects中獲取如果獲取不到對(duì)應(yīng)的對(duì)象,然后就會(huì)從三級(jí)緩存中獲取原始對(duì)象,如果是AOP就生成代理對(duì)象,不是就是普通對(duì)象然后放在二級(jí)緩存中,此時(shí)這個(gè)對(duì)象還不能放入單例池中,為什么呢?假如這里是個(gè)代理對(duì)象,代理對(duì)象的Target原始對(duì)象還沒(méi)有完成生命周期屬性還沒(méi)有完全注入完成,如果在這里放入單例池,在多線程環(huán)境下在這時(shí)從單例池中獲取這個(gè)bean對(duì)象就會(huì)發(fā)生不可預(yù)期的錯(cuò)誤。當(dāng)Bservice Bean對(duì)象創(chuàng)建完成后然后在Aservice中填充完所有屬性后,就可以從二級(jí)緩存中獲取該對(duì)象然后放到單例池中了。
手寫源碼篇
通過(guò)手寫模擬,了解Spring的底層源碼啟動(dòng)過(guò)程
通過(guò)手寫模擬,了解掃描邏輯和依賴注入等底層源碼工作流程
通過(guò)手寫模擬,了解初始化機(jī)制工作流程
通過(guò)手寫模擬,了解BeanDefinition、BeanPostProcessor的概念
通過(guò)手寫模擬,了解Spring AOP的底層源碼工作流程
目錄結(jié)構(gòu)
啟動(dòng)代碼
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)行代碼如下圖
Component注解
這里其余的注解代碼省略
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
String value() default "";
}
ApplicationContext類
這個(gè)類主要是掃描@ComponentScan指定的包路徑生成其中類含有@Componet注解的Bean對(duì)象。
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對(duì)象
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時(shí)注入失敗為null,當(dāng)注入的屬性對(duì)象bean在單例池排序靠前可以成功。
}
}//getFields為獲得所有public的屬性,這里為所有
//后置處理器,這里沒(méi)有對(duì)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ù)相對(duì)路徑 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對(duì)象是否實(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對(duì)象
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類
這個(gè)類主要包含Bean對(duì)象的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)初始化前和初始化后的操作。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-427410.html
@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文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-427410.html
到了這里,關(guān)于Spring手寫模擬源碼篇(你值得擁有)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!