应用情景🐟
情景
在开发中,如果我们采用Controller,Service,Dao的三层架构,那么可能出现以下情况。
首先,我们有一个名为MyService的接口,基于这个接口我们实现了Service1这个类,并在Service层使用了这个类。
public interface MyService {
}
public class Service1 implements MyService {
}
@RestController
public class MyController {
private MyService myService=new Service1();
}
因为某些原因,我们将用Service2替换Service1,此时我们需要将每一个创建Service1这个对象的地方改为创建Service2对象。
这种情况有很明显的问题:代码耦合度太高,操作繁琐
思路
此时,我们有一个想法,那就是不在类中new MyService实现类了,因为一旦在类中new了一个实现类,就存在耦合的情况。于是MyController的代码变成了这样
@RestController
public class MyController {
private MyService myService;
}
但这样了是有问题的,那就是我们虽然声明了这么一个对象,但我们并没有对其赋值。
此时我们假设,我们将Service的实现类放到一个容器中,而我们的myService能自动的从这个容器中找到自己需要的对象,那程序便能够正常运行了。这也是SpringBoot所使用的解决方案。
Bean
什么是Bean?
Bean就是被我们放在容器中的对象,我们习惯称容器为Spring容器或者IOC(Inverse of controll)容器,称IOC容器中的对象为Bean
如何创建Bean?
基础注解
得益于Spring框架的强大,我们只需要使用_@Component_这个注解就可以很方便地创建Bean.
只需要把这个注解挂载到想要成为Bean对象的类上即可
@Component
public class Service1 implements MyService {
}
衍生注解
除了@Component这个基础注解外,还有三个衍生注解:
-
@Controller
-
@Service
-
@Repository
@Component 挂载到不属于以下三种类的其他类上 @Service 挂载到业务类上 @Controller 挂载到控制类上 @Repository 挂载到数据访问类上 这三个衍生注解的作用与@Component的作用是几乎是一致的,对其进行分类是为了代码的可读性,使得可读性更高。但注意,在SpringBoot集成Web开发中,声明控制器bean只能使用@Controller
@Component(value="name") public class Service1 implements MyService { }
在声明bean得时候,可以通过value属性指定bean得名字,如果没有指定,默认为类名首字母小写。
生效条件
一个Bean想要生效,需要被组件扫描注解@ComponentScan扫描。
在SpringBoot启动类中有一个注解@SpringBootApplication
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
我们查看它的源码可以发现默认的扫描范围是启动类所在的包及其子包。
查看@ComponentScan的源码
@AliasFor("basePackages")
String[] value() default {};
@AliasFor("value")
String[] basePackages() default {};
我们可以通过指定basePackages或value属性指定扫描的范围。
如何使用Bean
基础使用
Bean的使用更加简单,只需使用@Autowired注解即可
@RestController
public class MyController {
@Autowired
private MyService myService;
}
注意事项
@Autowired注解默认是通过类型进行自动装配的,但如果容器中有多个类型相同的Bean,直接注入会出现问题。
此时可通过以下三个注解来解决
-
@Primary
-
@Qualifier
-
@Resource
@Primary注解加在@Component及其衍生注解上,有该注解的Bean将优先被注入。
@Qualifier作用在@Autowired注解上,通过__类名首字母小写__来进行注入.
@RestController public class MyController { @Qualifier("service1") @Autowired private MyService myService; }
@Resource注解是另一种使用Bean的注解,@Autowired注解通过类的类型进行注入,@Resource通过类的名字进行注入。同时需要注意,这里也是__类名首字母小写__,并且该注解是由JDK提供的。
@RestController public class MyController { @Resource("service1") private MyService myService; }