大廠面試官最常問(wèn)的@Configuration+@Bean(JDKConfig編程方式)

大廠面試官最常問(wèn)的@Configuration+@Bean(JDKConfig編程方式)案例分享

現(xiàn)在大部分的Spring項(xiàng)目都采用了基于注解的配置,采用了@Configuration 替換標(biāo)簽的做法。一行 簡(jiǎn)單的注解就可以解決很多事情。但是,其實(shí)每一個(gè)注解背后都有很多值得學(xué)習(xí)和思考的內(nèi)容。這 些思考的點(diǎn)也是很多大廠面試官喜歡問(wèn)的內(nèi)容。

@Configuration處理類:org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition

@Bean處理類:org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader$ConfigurationClassBeanDefinition

· 項(xiàng)目包結(jié)構(gòu)

F:.

├─java

│ └─com

│ └─example

│ └─demo4

│ │ Demo4Application.java

│ │

│ ├─configuration

│ │ PersonConfiguration.java

│ │ StuConfiguration.java

│ │

│ ├─controll

│ │ StuController.java

│ │

│ ├─dao

│ │ StuDao.java

│ │ StuDaoImp.java

│ │

│ ├─entity

│ │ Person.java

│ │ Stu.java

│ │

│ └─server

│ StuService.java

│ StuServiceImp.java

└─resources

application.properties

project.text

· Beans依賴圖

·

·

問(wèn)題1:@Configuration和@Component區(qū)別**(@Configuration自動(dòng)cglib動(dòng)態(tài)代理)**

·

o @Configuration 中所有帶 @Bean 注解的方法都會(huì)被動(dòng)態(tài)代理,因此調(diào)用該方法返回的都是同一個(gè)實(shí)例(Spring啟動(dòng)時(shí)會(huì)專門(mén)處理@Configuration)。proxyBeanMethods可以設(shè)置成false,取消代理。除此之外以下@Bean無(wú)法動(dòng)態(tài)代理。

o 配置類必須以類的形式提供(不能是工廠方法返回的實(shí)例),允許通過(guò)生成子類在運(yùn)行時(shí)增強(qiáng)(cglib 動(dòng)態(tài)代理)。

o 配置類不能是 final 類

o 配置類必須是非本地的(即不能在方法中聲明,不能是 private)。

o 任何嵌套配置類都必須聲明為static。

o @Bean必須是單例(默認(rèn)就是,別改成prototype)

o @Component里面的@Bean不是代理的

o 代理和不代理的區(qū)別如下代碼:

//拿到@Bean->person

Person person = context.getBean(Person.class);

//拿到組件

PersonConfiguration personConfiguration = context.getBean(PersonConfiguration.class);

//執(zhí)行組件里面的person()方法

Person person1=personConfiguration.person();

//使用stu

System.out.println(stu.getClass().getName());

//獲取組件里面的person()方法對(duì)象的hashCode

System.out.println("person1:"+person1.getClass().getName() + "@" + Integer.toHexString(person1.hashCode()));

//@Bean->person對(duì)象的hashCode

System.out.println("person:"+person.getClass().getName() + "@" + Integer.toHexString(person.hashCode()));

//從IOC容器中取出存在的personBean

Map<String, Person> beansOfType = context.getBeansOfType(Person.class);

//對(duì)比知道不代理執(zhí)行組件里面的person()方法的對(duì)象不會(huì)被Spring管理,代理就會(huì)管理

System.out.println("beansOfType:"+beansOfType.get("person").getClass().getName() + "@" + Integer.toHexString(person.hashCode()));

·

問(wèn)題2:expected single matching bean but found 2

·

o

同類型多個(gè)Beans,引發(fā)原因比如使用了context.getBean(Stu.class)、@Autowired只用ByType類獲取或者注入Beans的時(shí)候

o

o

使用名稱獲取,不優(yōu)先使用ByType,==如果是其它第三方(也許第三方直接ByType)那么可以采取【禁止使用】或【優(yōu)先使用】

o

o

禁止使用

o

o @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class })

o application.properties里配置:spring.autoconfigure.exclude=全類名,全類名

o

優(yōu)先使用(在設(shè)計(jì)層面不建議這樣使用)

o

o

@Bean

@Primary

public Person person() {

return new Person();

}

o

o

==正確姿態(tài)約定好命名規(guī)則尤為重要==

o

·

問(wèn)題3:could not be registered. A bean with that name has already been defined in file

·

o 組件重復(fù)問(wèn)題,大多使用配置:spring.main.allow-bean-definition-overriding=true

o 以上配置會(huì)覆蓋Bean,并且依然產(chǎn)生具體對(duì)象

具體底層實(shí)現(xiàn)類(誰(shuí)定義存儲(chǔ)了這些注冊(cè)類??):

·

AnnotatedGenericBeanDefinition:存儲(chǔ)@Configuration注解注釋的類

·

·

ScannedGenericBeanDefinition:存儲(chǔ)@Component、@Service、@Controller等注解注釋的類

·

·

spring初始化時(shí),會(huì)用GenericBeanDefinition或是ConfigurationClassBeanDefinition(用@Bean注解注釋的類)存儲(chǔ)用戶自定義的Bean,在初始化Bean時(shí),又會(huì)將其轉(zhuǎn)換為RootBeanDefinition

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容