案例 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";
};
}
这是一个简单是SpringBoot程序,通过@SpringBootApplication注解扫描到HelloWorldController类,并把它实例化成bean组件注册到IOC容器当中去。当我们访问http://localhost:8080/hi地址则会返回helloworld字符串。在之后的迭代中我们改变了包的结构,如下图:
你会发现HelloWorldController类生成的bean组件找不到了。
原因:SpringBoot在不指定扫描包路径的情况下,会默认取Application类(被@SpringBootApplication注解修饰的类)路径做为扫描包的根路径,对于它层级以上的包所属的文件是扫描不到的。
解决办法:可以指定包的扫描路径来解决。示例代码如下:
@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;
}
}
在启动Spring程序中报出了这样一个异常: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在生成这个类的bean组件时,会去反射获取它的构造函数。这个类有显示的构造函数,所以只能去获取这个显示的构造函数,而这个构造函数又有参数,这个参数哪来呢,Spring只能去IOC容器里去找,找到再拿出来放进去。现在确没有String类型的bean组件,所以这个肯定会报错的。它这个注入是隐式的。
解决办法:写个String类型的bean组件就OK了!代码示例如下:
//这个bean装配给ServiceImpl的构造器参数“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;
};
}
需求是想每次调用hi接口时返回的serviceImpl对象都不一样,都是新的对象,但对象确被固定住了,每次返回的对象都是同一个对象。作者开始还在想这是啥原理怎么@Scope注解不起作用,Spring有Bug啊,转念一想,妈的,这个问题怎么这么蠢,HelloWorldController就是单例的,它的属性肯定是固定的,serviceImpl注入之后又不会变了。
解决办法:一是可以通过ApplicationContext来获取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(){
// 这里返回什么不重要,因为根本不会进入到这个方法中去
return null;
}
}