目录
(一)Bean扫描
1.通常用来扫描包的方法
使用标签:在 xml文件中可以借助<context:component-scan base-package="com.it"/>标签来指定要扫描的包路径
使用配置类的方式:@ComponentScan(basePackages="com.ti")使用注解来指定要扫描的包路径
2.在SpringBoot中如何扫描
为什么在使用SpringBoot的时候,既不需要使用compo-scan标签,也不用写@ComponentScan注解,就能扫描到我们写的包?
SpringBoot工程需要一个启动类,在启动类上需要添加一个注解@SpringBootApplication,
并且在启动这个SpringBootApplication的时候,把当前启动类的字节码文件作为参数传递进去了。
核心原因就是@SpringBootApplication这个注解,这个注解本质上是一个组合注解,它整合了ComponentScan注解,这也是为什么我们不需要手动添加这个注解,也能自动扫描到那些包,在使用ComponentScan注解的时候,不指定包路径,那么它默认扫描的是添加了该注解的类所在的包及其子包
SpringBoot工程默认扫描所在的包,及其子包
举例:
若将Controller这个包移到与启动类不同的包,那么再次输入网址,则无法访问到用户的信息,因为SpringBoot工程扫描不到了
若想扫描到启动类之外的包,那么就需要手动添加注解,以及包的路径
@ComponentScan(basePackages = "包路径")
(二)Bean对象的注册
注解 | 说明 | 位置 |
---|---|---|
@Component | 声明bean的基础注解 | 不属于一下三类是,有此注解 |
@Controller | @Component的衍生注解 | 标注在控制类上 |
@Service | @Component的衍生注解 | 标注在业务类上 |
@Reposity | @Component的衍生注解 | 标注在数据访问类上(用于与mybatis整合,用得少) |
如果要注册的bean对象来自于第三方(不是自定义的),是无法使用@Component及其衍生注解声明bean的(在jar包中的文件都是只读的,不可更改)
解决方法:
Spring提供了两个注解来解决这个问题:
- @Bean
- @Import
案例测试:
准备工作:
1.安装一个jar包:
命令:
mvn install:install-file -Dfile=D:\BaiduNetdiskDownload\02_Bean注册资料\02_Bean注册资料\common-pojo-1.0-SNAPSHOT.jar -DgroupId=cn.itcast -DartifactId=common-pojo -Dversion=1.0 -Dpackaging=jar
标颜色的那段需要更改
执行命令之前必须要确认Maven的环境变量是好的
这样即安装成功:
D:\Maven\maven-repository\cn\itcast\common-pojo\1.0
2.将刚才安装好的坐标引入进来:
<dependency>
<groupId>cn.itcast</groupId>
<artifactId>common-pojo</artifactId>
<version>1.0</version>
</dependency>
目标,将这两个类的bean注入到IOC容器中:
@Bean
1.在启动类中添加(不推荐)
如果要注册第三方bean,建议在配置类中集中注册
@SpringBootApplication
public class SpringBootCreateManualApplication
{
public static void main( String[] args )
{
ApplicationContext context=SpringApplication.run(SpringBootCreateManualApplication.class,args);Country country = context.getBean(Country.class);
//若能正常输出,表示bean对象注入成功
System.out.println(country);
}//注入Country对象
@Bean//将方法返回值交给IOC容器管理,成为IOC容器的bean对象
public Country country(){
return new Country();
}
}
2.定义一个配置类
@Configuration
public class CommonConfig {
//注入Country对象
@Bean//将方法返回值交给IOC容器管理,成为IOC容器的bean对象
public Country country(){
return new Country();
}
}
正常获取到了:
获取Province:
//对象默认的名字是方法名
@Bean
public Province province(){
return new Province();
}
System.out.println(context.getBean("province")); 根据名字获取
正常获取到:
@Import
- 导入配置类
- 导入ImportSelector实现类
1.导入配置类
即使配置类与启动类不在一个包下面,也能扫描到
@SpringBootApplication
@Import(CommonConfig.class)
public class SpringBootCreateManualApplication
{
public static void main( String[] args )
{
ApplicationContext context=SpringApplication.run(SpringBootCreateManualApplication.class,args);Country country = context.getBean(Country.class);
//若能正常输出,表示bean对象注入成功
System.out.println(country);System.out.println(context.getBean("province"));
}}
如果配置类有多,可以通过数组的方式来输入
也可以使用ImportSelector接口实现类来让代码更加美观
2.导入ImportSelector接口实现类
- 首先定义一个类去实现这个接口
- 然后重写selectImports方法
@SpringBootApplication
//@Import(CommonConfig.class)
@Import(CommonImportSelector.class)
public class SpringBootCreateManualApplication
{
public static void main( String[] args )
{
ApplicationContext context=SpringApplication.run(SpringBootCreateManualApplication.class,args);Country country = context.getBean(Country.class);
//若能正常输出,表示bean对象注入成功
System.out.println(country);System.out.println(context.getBean("province"));
}}
public class CommonImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"org.example.config.CommonConfig"}; //要注入到bean对象里面的全类名(可写多个)
}
}
正常获取到,没问题:
优化:
创建一个文件来存放全类名,即需要扫描的文件,若将来有多个bean对象要注入,那么换行每一行写一个类名就行
public class CommonImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//读取配置文件的内容
List<String> imports=new ArrayList<>();
InputStream is=CommonImportSelector.class.getClassLoader().getResourceAsStream("common.imports");
BufferedReader br=new BufferedReader(new InputStreamReader(is));
String line=null;
try {
while((line = br.readLine())!=null){
imports.add(line);
}
br.close();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (br!=null){
try {
br.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
return imports.toArray(new String[0]);
}
}
继续运行启动类:
正常获取到,没问题!!
3.使用@EnableXxx注解,来封装@Import注解
创建@EnableCommonConfig组合注解
import org.example.config.CommonImportSelector;
import org.springframework.context.annotation.Import;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import(CommonImportSelector.class)
public @interface EnableCommonConfig {
}在启动类上使用@EnableXxx注解即可
获取成功:
(三)注册条件
SpringBoot提供了设置注册生效条件的注解@Conditional
注解 | 说明 |
---|---|
@ConditionalOnProperty | 配置文件中存在对应的属性,才声明该bean |
@ConditionalOnMissingBean | 当不存在当前类型的bean时,才声明该bean |
@ConditionOnClass | 当前环境存在指定的这个类时,才声明该bean |
@ConditionalOnProperty
将配置文件中的内容注释掉
@ConditionalOnProperty注解,如果配置文件中配置了指定的信息,则注入,否则不注入
@ConditionalOnProperty(prefix = "country",name = {"name","system"})
配置文件中没有内容,报错:
取消注释,正常注入:
@ConditionalOnMissingBean
将配置文件中的内容注释掉
如果IOC容器中不存在Country对象,则注入Province对象,否则不注入
@ConditionalOnMissingBean(Country.class)
不存在Country对象,只注入Province
@ConditionOnClass
标签:对象,Country,bean,public,Bean,注册,注解,class From: https://blog.csdn.net/2301_76890677/article/details/143719291如果当前环境中存在DispatcherServlet类,则注入Province对象,否则不注入
如果当前环境引入了web起步依赖,则环境中存在DispatcherServlet类,否则没有
由于这个项目没有引入web依赖,所以运行时报错了: