SpringBoot第二天

Bean管理

Bean扫描

在Spring中,Bean的扫描有两种写法

第一种是在xml配置文件中用标签扫描

第二种是是注解扫描

@ComponentScan(basePackages="com.cacb")

 而在SpringBoot中,我们在启动类中使用了

@SpringBootApplication

注解,该注解实际上包含如下注解

SpringBoot第二天_第1张图片

故只要调用该注解Spring就能扫描启动类所在的包及其子包中的Bean,在我们使用时就实现了自动扫描,同时我们也应注意所有的Bean应该放在启动类所在的包及其子包中。

Bean注册

SpringBoot第二天_第2张图片

如果要注册的Bean来自第三方(不是自定义的),是无法使用@Component及衍生注解声明Bean的,可以使用如下两个注解

@Bean

譬如,我们在一个jar包中有一个实体类Book,需要在当前工程中导入Book实体,首先我们就需要在启动类中使用@Bean注解来注入Book对象

@SpringBootApplication
public class SpringBootMybatisApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringBootMybatisApplication.class, args);
	}

    
    @Bean
    public Book book(){
        return new Book();
    }

}

但是这种方法需要在启动类中注解,不推荐,更好的方法是单独创建一个配置类来集中管理注册第三方Bean,该配置类需要在启动类同一个包及其子包中,并且要有@Configuration注解

@Configuration
public class CommonConfig {
    @Bean
    public Book book(){
        return new Book();
    }
}

如果需要改名,例如,要将Book对象名改为user,可以在Bean注释后更改(默认对象名为方法名):

    @Bean("user")
    public Book book(){
        return new Book();
    }

如果一个第三方对象内需要注入另一个第三方对象,可以在参数内自动注入,如下例在BookStore中注入Book:

    @Bean
    public Book book(){
        return new Book();
    }
    
    @Bean
    public BookStore bookstore(Book book){
        return new BookStore();
    }

@Import 

导入配置类

 例如,上文所写的CommonConfig不与启动类放在同一个包中,启动类就无法自动扫描到该配置类,此时就需要在启动类中使用@Import来完成手动注解

@SpringBootApplication
@Import(CommonConfig.class)
public class SpringBootMybatisApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringBootMybatisApplication.class, args);
	}

}

注:如果有多个配置类需要注解,可以使用{}数组的形式来完成注解,同时,也可以通过导入ImportSelector接口来完成该工作。 

导入ImportSelector接口实现类

例如此时,config文件与启动类不在同一个文件,我们也可以通过导入ImportSelector接口实现类来手动注解。

SpringBoot第二天_第3张图片

首先我们需要制作一个ImportSelector接口实现类

public class CommonImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.cacb.config.CommonConfig"};
    }
}

然后再去启动类中使用@Import注解来完成手动注解

@SpringBootApplication
@Import(CommonImportSelector.class)
public class SpringBootMybatisApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringBootMybatisApplication.class, args);
	}

}

当然,需要注入的Bean一般是从配置文件中读取的,方法如下,先构建配置文件 

SpringBoot第二天_第4张图片

 注:每行指书写一个Bean的全类名

com.cacb.config.CommonConfig

然后去接口实现类中加载配置文件

public class CommonImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        List 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);
            }
        } 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]);
    }
}

 组合类注解@EnableXxxx注解封装@Import注解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import(CommonImportSelector.class)
public @interface EnableCommonConfig {
}

完成后就可以在启动类中使用@EnableCommonConfig注解来代替@Import注解使用

@SpringBootApplication
@EnableCommonConfig
public class SpringBootMybatisApplication {

注册条件

SpringBoot提供了设置注册生效条件的注解@Conditional

SpringBoot第二天_第5张图片

自动配置原理 

自动配置

遵循约定大于配置的原则,在boot程序启动后,起步依赖中的一些Bean对象会自动注入到IOC容器

程序引入spring-boot-starter-web起步依赖,启动后,会自动往IOC容器中注入DispatcherServlet

在主启动类上添加了SpringBootApplication注解,这个注解组合了EnableAutoConfiguration注解

EnableAutoConfiguration注解又组合了Import注解,导入了AutoConfigurationImportSelector类

实现selectImports方法,这个方法经过多层调用,最终会读取META-INF目录下的后缀名为imports的文件,boot2.7以前的版本读取的是spring.factories文件

读取到imports文件中的全类名之后,会解析注册条件,也就是@Conditional及其衍生注解,把满足注册条件的Bean对象自动注入到IOC容器中

自定义starter

以Mybatisstarter为例

我们需要构建两个模块

在自动配置模块中首先要导入相应依赖坐标

  
    
      org.springframework.boot
      spring-boot-starter
      3.2.2
    

    
      org.springframework.boot
      spring-boot-starter-data-jdbc
      3.0.0
    
    
      org.mybatis
      mybatis
      3.5.14

    

    
      junit
      junit
      3.8.1
      test
    
    
      org.mybatis
      mybatis-spring
      3.0.3
      compile
    
  

然后提供自动配置类

@AutoConfiguration
public class MyBatisAutoConfig {

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean;
    }

    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer(BeanFactory beanFactory){
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        //扫描的包:启动类所在的包及其子包
        List packages =  AutoConfigurationPackages.get(beanFactory);
        String p = packages.get(0);
        mapperScannerConfigurer.setBasePackage(p);

        //扫描的注解
        mapperScannerConfigurer.setAnnotationClass(Mapper.class);
        return mapperScannerConfigurer;
    }
}

自建import文件,并将自动配置类完整路径写入

 注意imports文件存储路径一定要在META-INF.spring下

com.cacb.config.MyBatisAutoConfig

下面开始配置stater模块,该模块只需要导入相应坐标,故src文件可以直接删除掉


    
      org.springframework.boot
      spring-boot-starter
      3.2.2
    

    
      org.springframework.boot
      spring-boot-starter-data-jdbc
      3.0.0
    
    
      org.mybatis
      mybatis
      3.5.14

    

    
      junit
      junit
      3.8.1
      test
    
    
      org.mybatis
      mybatis-spring
      3.0.3
      compile
    
  

最重要的是导入我们写的自动装配模块,最好也要将自装配模块所依赖的坐标一并导入 

 

你可能感兴趣的:(spring,boot,java)