Spring Bean 定义常见错误

案例 1 :隐式扫描不到bean的定义

代码示例 :


package

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字符串。在之后的迭代中我们改变了包的结构,如下图:

package

你会发现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;
    }  

}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容