Autoconfiguration详解——自动注入配置参数

打印 上一主题 下一主题

主题 931|帖子 931|积分 2793

目录

Autoconfiguration详解——自动注入配置参数

一、 理解自动装配bean

1. 常用注解


  • @AutoConfiguration(每个配置类都要加上)

    • Class[] after() default {};
    • Class[] before() default {};
    • 以上两个配置可以控制加载顺序;
    • 不需要再增加@Configuration注解;

  • @AutoConfigureBefore and @AutoConfigureAfter
  • @Configuration
  • @Conditional(后面会详细讲到)

    • @ConditianalOnClass
    • @ConditionalOnMissingClass
    • @ConditionalOnWebApplication:只在web应用中加载;

  • @EnableConfigurationProperties:配置文件参数内容,参照类RedisProperties;

    • @ConfigurationProperties(prefix = "spring.redis"),该注解展示了配置文件前缀;

  • @DependsOn:列举一些前置的注入bean,以备用,用在类上需要有 @Component自动扫描的时候才能生效;

    • 实际上控制了bean加载的顺序,优先加载指定的bean,然后加载当前bean;
    • 销毁的时候,注解的bean优先与于依赖的bean销毁;

2. 定位自动装配的候选类

springboot 框架会自动扫描 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 进行引入,所以需要自动注入的Configuration文件都写在这个文件中。每个class一行。
这里本质上是一个自动版的@Import。
示例:
  1. # comments
  2. org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration
  3. org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
  4. org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration
复制代码
如果需要引入特定的Component,使用@Import注解。
3. 条件注解

在所有自动装配类出现的地方,我们都因该时加上@Conditional注解,允许使用的开发人员覆盖自动装配的bean,当然他们也可以选择什么也不做,使用默认的配置。
Spring Boot 提供了一些条件注解,可以注解在@Configuration类或者@Bean方法上。
3.1 有关类的判断

对于@Configuration类来说,@ConditionalOnClass 和@ConditionalOnMissingClass代表了在指定类存在或者不存在的时候进行加载。因为实际上注解的元数据使用ASM技术进行解析,所以可以使用value参数来指定特定的类的class对象(可以是多个),或者使用name参数来指定特定的类名(可以是多个),两种方式所指向的类即使不存在也不影响正常执行。
当@Bean方法返回值是条件注解的的目标之时,可能会因为JVM加载顺序的问题导致加载失败,上文提到的两个注解可以用在@Bean方法上。
3.2 有关bean的判断

@ConditionalOnBean和@ConditionalOnMissingBean,代表在指定bean存在或者不存在时加载。value参数可以指定bean的class(多个),name可以指定bean的名称(多个)。search参数允许你限制ApplicationContext即应用上下文的搜索范围,可选当前上下文,继承上层,或者是全部(默认)。
在@Bean方法上使用时,默认参数为当前方法返回类型。
在使用@Bean注解时,建议使用具体类型而不是父类型进行指代。
3.3 配置条件

@ConditionalOnProperty,指定配置项文件(例如dev,pro),prefix属性规定了配置前缀,name属性指定了应该被检查的参数。默认,所有存在且不等于false的参数都会被匹配到,你也可以使用havingValue和matchIfMissing属性闯将更多的校验。
例子:@ConditionalOnProperty(name = "spring.redis.client-type", havingValue = "lettuce", matchIfMissing = true);
属性名类型解析nameString[] name() default {};配置项全称,如果有prefix,可以省略prefix中的前缀部分prefixString prefix() default "";统一的配置项前缀havingValueString havingValue() default "";配置项需要匹配的内容,如果没有指定,那么配置的值等于false时结果为false,否则结果都为truematchIfMissingboolean matchIfMissing() default false;配置项不存在时的配置,默认为false3.4 源文件条件

@ConditionalOnResource,指定源文件存在时引入。
例如:@ConditionalOnResource(resources = {"classpath:test.log"});
3.5 web 应用条件

@ConditionalOnWebApplication 和 @ConditionalOnNotWebApplication ,web应用或者不是web应用时启用,以下部分只要满足一个条件即为web 应用。
servlet-based web 应用特点:

  • 使用 Spring WebApplicationContext;
  • 定义了一个session作用域的bean;
  • 有一个WebApplicationContext;
reactive web 应用特点:

  • 使用了ReactiveWebApplicationContext;
  • 有一个ConfigurableReactiveWebEnvironment;
ConditionalOnWarDeployment,仅限于使用war进行部署的场景,在嵌入式tomcat的场景里不会启用;
3.6 Spel表单式条件

ConditionalOnWarDeployment ,使用Spel表达式返回结果进行判断。
注意:在表达式中引用一个bean会导致这个bean非常早的被加载,此时还没有进行预加载(例如配置项的绑定),可能会导致不完成的加载。
二、自动注入配置基础


  • @EnableConfigurationProperties(CommonRedisProperties.class) 注解configuration类;
  • @ConfigurationProperties(prefix = "myserver")注解配置文件类,prefix标明配置文件的前缀;
  • public RedisTemplate getRedisTemplate(CommonRedisProperties properties, RedisConnectionFactory redisConnectionFactory) ,加到需要使用的参数中即可;
  • META-INF目录下添加additional-spring-configuration-metadata.json文件,格式如下
  1. {
  2.   "groups": [
  3.     {
  4.       "name": "server",
  5.       "type": "com.huawei.workbenchcommon.redis.CommonRedisProperties",
  6.       "sourceType": "com.huawei.workbenchcommon.redis.CommonRedisProperties"
  7.     }
  8.   ],
  9.   "properties": [
  10.     {
  11.       "name": "myserver.database",
  12.       "type": "java.lang.String",
  13.       "sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties"
  14.     }
  15.   ]
  16. }
复制代码
三、注释切面 @Metrics

1. 注解@Metrics
  1. @Retention(RetentionPolicy.RUNTIME)
  2. @Target({ElementType.METHOD, ElementType.TYPE})
  3. public @interface Metrics {
  4.     /**
  5.      * 在方法成功执行后打点,记录方法的执行时间发送到指标系统,默认开启
  6.      */
  7.     boolean recordSuccessMetrics() default true;
  8.     /**
  9.      * 在方法成功失败后打点,记录方法的执行时间发送到指标系统,默认开启
  10.      */
  11.     boolean recordFailMetrics() default true;
  12.     /**
  13.      * 通过日志记录请求参数,默认开启
  14.      */
  15.     boolean logParameters() default true;
  16.     /**
  17.      * 通过日志记录方法返回值,默认开启
  18.      */
  19.     boolean logReturn() default true;
  20.     /**
  21.      * 出现异常后通过日志记录异常信息,默认开启
  22.      */
  23.     boolean logException() default true;
  24.     /**
  25.      * 出现异常后忽略异常返回默认值,默认关闭
  26.      */
  27.     boolean ignoreException() default false;
复制代码
2. 切面MetricsAspect

[code]@Aspect@Slf4j@Order(Ordered.HIGHEST_PRECEDENCE)public class MetricsAspect {    /**     * 让Spring帮我们注入ObjectMapper,以方便通过JSON序列化来记录方法入参和出参     */    @Resource    private ObjectMapper objectMapper;    /**     * 实现一个返回Java基本类型默认值的工具。其实,你也可以逐一写很多if-else判断类型,然后手动设置其默认值。     * 这里为了减少代码量用了一个小技巧,即通过初始化一个具有1个元素的数组,然后通过获取这个数组的值来获取基本类型默认值     */    private static final Map
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

雁过留声

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表