springboot-2-IOC容器的基本注解

@Configuration

告诉springboot这是一个配置类,用于补充IOC容器,

示例:

@Configuration  //告诉springboot这是一个配置类,作为IOC容器的自定义补充
public class MyConfig {
    
    @Bean   //给容器添加组件bean,方法名即为组件id
    public Pet pet(){
        return new Pet("左",12.2);
    }
}

从IOC容器尝试获取(只要没再pojo上用@Repository就能获取到,否则报错)

@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        //1、返回IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
        //2、查看IOC容器中的bean
        String[] beanDefinitionNames = run.getBeanDefinitionNames();
        for (String i:beanDefinitionNames){
            System.out.println(i);
        }
        //3、从容器中获取自定义的bean
        Pet pet = run.getBean("pet", Pet.class);
        System.out.println("pet------------>>>>>"+pet);
    }
}

@Configuration的proxyBeanMethods属性

属性默认为true,我们每次调用这个方法实际上都是从IOC容器中去找这个bean(在项目启动的时候就加载到IOC容器中去了)为全模式(FULL)

属性调为false,我们每次调用这个方法都会产生一个新的实例,为Lite模式,解决的问题是组件依赖(轻量级模式(每次调用方法不需要从IOC容器中找,运行速度较快)

验证是否为单实例(结果为true)

//4、配置类本身也是一个bean,我们可以通过IOC容器获取配置类
MyConfig ConfigBean = run.getBean(MyConfig.class);
System.out.println("config---------->>>>>>>>"+ConfigBean);
//再通过获取到的bean调用里面的方法获取自定义bean
Pet pet1 = ConfigBean.pet();
Pet pet2 = ConfigBean.pet();
//判断获取到的这两个实例是否一致
System.out.println("equals---------->>>>>>"+pet1.equals(pet2));

但如果我们把配置类的proxyBeanMethods属性设为false(关闭单实例)

每次调用这个方法ConfigBean.pet()放回来的都是一个不同的bean实例(地址一定不同)

组件依赖

就比如在咋person类中,有一个pet属性,我们咋配置类中为这两个pojo都创建了bean实例,其中在person中是直接调用了pet创建实例的方法注入的pet属性,那么现在IOC容器中person实例里的pet实例,是否和IOC容器中的pet实例相同呢?这就是组件依赖,由proxyBeanMethods属性定义可以知道:开启为true时这两个实例是一致的,但如果false则不一致

由于我们一般都是直接从IOC容器中拿实例对象,而不会直接去调用这个对应的方法去获得实例对象,所以只要没有组件依赖的话,一般把proxyBeanMethods调为false,这样我们的启动速度较快

两种注入注入属性的方法的对照

两种配置bean的方式一起使用会导致多个实例报错(默认为单实例模式)

  • 配置文件的注入属性一般是修改在starter中默认配置好的一些使用环境需要的bean的属性(他们原来就是含有一定的默认属性的

  • 在配置类中注入创建实例化对象并注入属性一般是针对一些自定义的bean的操作

@Import

可以加在任意类的上面,@Import( {这里是一个集合,把需要实例化的类放到这里就会自动实例化放到IOC容器中} ),生成的bean实例的id为全类名

用于实例化对象,在IOC容器中添加bean,当配置类中含有这个类的配置时,不会再创建了

@Import注解主要可以用于导入第三方包,然后再使用yaml配置文件注入属性

@Conditional

条件装配:满足Conditional指定的条件,配置类才会进行组件注入

衍生了很多按照不同种类条件的注解

@ImportResource

导入xml配置的xml文件

在一个基础的配置类的上面加上@ImportResource就可以导入其他xml配置文件

示例:

@Configuration(proxyBeanMethods = true)		//没有这个注解@ImportResource也会无效
@ImportResource("classpath:applicationContext.xml")
public class MyConfig {}

@ConfigurationProperties

就是使用yaml配置文件进行属性注入,需要和@Component注解配合,前者用于给这个bean实例去别名,后者把这个bean实例放到IOC容器中去。

示例:

@Component
@ConfigurationProperties(prefix = "person")
//有了这个注解之后,如果有注解提示的依赖得话,在yaml文件中就会出现person的提示
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {

    private String name;
    private Integer age;
    private Pet pet;
}

springboot应用实践的流程

1、引入场景依赖(在官网上看是否有这个starter)

官网:https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter

2、查看自动配置了哪些

在yaml配置文件中添加debug: true即可在控制台看到哪些class生效哪些没生效

3、参照官方文档对yaml配置文件修改一些bean的属性

官方:https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#common-application-properties

4、加上需要自定义得类,在用配置类注入属性就完成了IOC容器的配置

了解配置文件的到底是怎么配置的

自动配置类,在spring.factory类中可以全浏览

实例打开HttpEncodingAutoConfiguration一探究竟

//表名这时一个配置类(为轻量级模式)
@Configuration(proxyBeanMethods = false)
//自动配置类的配置属性(关键)
@EnableConfigurationProperties(ServerProperties.class)
//下面均为在一定环境下才生效这个配置类
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {

    
    private final Encoding properties;
	//@EnableConfigurationProperties配置过来的属性会自动配置到这个里
   public HttpEncodingAutoConfiguration(ServerProperties properties) {
      this.properties = properties.getServlet().getEncoding();
   }

    //@Bean表示这里输出一个bean
   @Bean
   @ConditionalOnMissingBean
   public CharacterEncodingFilter characterEncodingFilter() {
      CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
      filter.setEncoding(this.properties.getCharset().name());
      filter.setForceRequestEncoding(this.properties.shouldForce(Encoding.Type.REQUEST));
      filter.setForceResponseEncoding(this.properties.shouldForce(Encoding.Type.RESPONSE));
      return filter;
   }

    //@Bean表示这里输出一个bean
   @Bean
   public LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
      return new LocaleCharsetMappingsCustomizer(this.properties);
   }

   static class LocaleCharsetMappingsCustomizer
         implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {

      private final Encoding properties;

      LocaleCharsetMappingsCustomizer(Encoding properties) {
         this.properties = properties;
      }

      @Override
      public void customize(ConfigurableServletWebServerFactory factory) {
         if (this.properties.getMapping() != null) {
            factory.setLocaleCharsetMappings(this.properties.getMapping());
         }
      }

      @Override
      public int getOrder() {
         return 0;
      }

   }

}

@EnableConfigurationProperties(ServerProperties.class)单独拿出来看

打开serverproties类查看源码

@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {

    //普通属性
   private Integer port;
    
    。。。
        
   //还有内部类
   public static class Servlet {
   。。。
   private String contextPath;
   。。。
   }
}

根据前缀和属性名字,可知道这个地方的port配置应该是

根据前缀和内部类名字和内部类的属性,可知contextPath配置应该是

配置文件配置到组件使用的流程

posted @ 2021-06-12 15:26  Coder-Wang  阅读(238)  评论(0编辑  收藏  举报