概念篇
下面是本文章關(guān)于Spring底層原理的章節(jié)
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é)果如下圖:
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é)果如下圖所示
?這里對于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容器中假如真實(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)上的圖片
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)
啟動代碼
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類
這個類主要是掃描@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)初始化前和初始化后的操作。文章來源:http://www.zghlxwxcb.cn/news/detail-430805.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文章來源地址http://www.zghlxwxcb.cn/news/detail-430805.html
到了這里,關(guān)于Spring源碼篇(你值得擁有)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!