案例 1 :隱式掃描不到bean的定義
代碼示例 :
package com.spring.puzzle.class1.example1.application
//省略 import
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
package com.spring.puzzle.class1.example1.application
//省略 import
@RestController
public class HelloWorldController {
@RequestMapping(path = "hi", method = RequestMethod.GET)
public String hi(){
return "helloworld";
};
}
這是一個(gè)簡(jiǎn)單是SpringBoot程序参咙,通過(guò)@SpringBootApplication注解掃描到HelloWorldController類,并把它實(shí)例化成bean組件注冊(cè)到IOC容器當(dāng)中去。當(dāng)我們?cè)L問(wèn)http://localhost:8080/hi地址則會(huì)返回helloworld字符串亭饵。在之后的迭代中我們改變了包的結(jié)構(gòu),如下圖:
你會(huì)發(fā)現(xiàn)HelloWorldController類生成的bean組件找不到了续誉。
原因:SpringBoot在不指定掃描包路徑的情況下栈妆,會(huì)默認(rèn)取Application類(被@SpringBootApplication注解修飾的類)路徑做為掃描包的根路徑,對(duì)于它層級(jí)以上的包所屬的文件是掃描不到的鹃觉。
解決辦法:可以指定包的掃描路徑來(lái)解決专酗。示例代碼如下:
@SpringBootApplication
@ComponentScan("com.spring.puzzle.class1.example1.controller")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
案例 2 :定義的bean缺少隱式依賴
代碼示例:
@Service
public class ServiceImpl {
private String serviceName;
public ServiceImpl(String serviceName){
this.serviceName = serviceName;
}
}
在啟動(dòng)Spring程序中報(bào)出了這樣一個(gè)異常:Parameter 0 of constructor in com.spring.puzzle.class1.example2.ServiceImpl required a bean of type 'java.lang.String' that could not be found.
Spring在生成這個(gè)類的bean組件時(shí),會(huì)去反射獲取它的構(gòu)造函數(shù)盗扇。這個(gè)類有顯示的構(gòu)造函數(shù)祷肯,所以只能去獲取這個(gè)顯示的構(gòu)造函數(shù),而這個(gè)構(gòu)造函數(shù)又有參數(shù)疗隶,這個(gè)參數(shù)哪來(lái)呢佑笋,Spring只能去IOC容器里去找,找到再拿出來(lái)放進(jìn)去“弑牵現(xiàn)在確沒有String類型的bean組件允青,所以這個(gè)肯定會(huì)報(bào)錯(cuò)的。它這個(gè)注入是隱式的卵沉。
解決辦法:寫個(gè)String類型的bean組件就OK了颠锉!代碼示例如下:
//這個(gè)bean裝配給ServiceImpl的構(gòu)造器參數(shù)“serviceName”
@Bean
public String serviceName(){
return "MyServiceName";
}
案例 3 :原型bean被固定
示例代碼:
@Service
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ServiceImpl {
}
@RestController
public class HelloWorldController {
@Autowired
private ServiceImpl serviceImpl;
@RequestMapping(path = "hi", method = RequestMethod.GET)
public String hi(){
return "helloworld, service is : " + serviceImpl;
};
}
需求是想每次調(diào)用hi接口時(shí)返回的serviceImpl對(duì)象都不一樣,都是新的對(duì)象史汗,但對(duì)象確被固定住了琼掠,每次返回的對(duì)象都是同一個(gè)對(duì)象。作者開始還在想這是啥原理怎么@Scope注解不起作用停撞,Spring有Bug啊瓷蛙,轉(zhuǎn)念一想,媽的戈毒,這個(gè)問(wèn)題怎么這么蠢艰猬,HelloWorldController就是單例的,它的屬性肯定是固定的埋市,serviceImpl注入之后又不會(huì)變了冠桃。
解決辦法:一是可以通過(guò)ApplicationContext來(lái)獲取serviceImpl;還可以使用@Lookup注解道宅;具體代碼如下:
@RestController
public class HelloWorldController {
@Autowired
private ApplicationContext applicationContext;
@RequestMapping(path = "hi", method = RequestMethod.GET)
public String hi(){
return "helloworld, service is : " + getServiceImpl();
};
public ServiceImpl getServiceImpl(){
return applicationContext.getBean(ServiceImpl.class);
}
}
@RestController
public class HelloWorldController {
@RequestMapping(path = "hi", method = RequestMethod.GET)
public String hi(){
return "helloworld, service is : " + getServiceImpl();
};
@Lookup
public ServiceImpl getServiceImpl(){
// 這里返回什么不重要食听,因?yàn)楦静粫?huì)進(jìn)入到這個(gè)方法中去
return null;
}
}