Spring 几个配置注解的含义

说说以下几个注解的含义

1.@Configuration 此注解的用义是让一个类成为一个配置类,它与 @Bean 注解一起使用(一般用在类中的方法上面),可以用于生成一系列的 Bean .它们是用来简单基于 xml 配置 Bean 的注解。可以这样说,一个类上面 @Configuration 就相当于一个 定义 很多Bean 的 xml 文件。


2.@ConfigurationProperties 此注解的用义是让一个类成为一个注入了 propeties 变量的配置类,一般与 @Component 和 @PropertySource 一起使用,例如:

@Component
@PropertySource("classpath:application.properties")
@ConfigurationProperties(prefix="hrService")
public class HRConfig
意思是,HRConfig 是一个装配了 propeties 的配置类(@ConfigurationProperties),装配变量的文件是 classpath:application.properties ,(@PropertySource(...)),读取文件中变量的规则是,所有以  hrService 为前缀的变量, 可以对外提供读取配置变量的服务(@Component)。

上面的配置其实可以在 Spingboot 中简化为

@Component
@ConfigurationProperties(prefix="hrService")
因为 Springboot 中 classpath:application.properties 是默认加载的配置文件。

@ConfigurationProperties 此注释从字面上来理解,可以设置配置的属性,使被装配类有不同的行为.例如,可以传入 prefix,ignoreUnknowFields 等等,以达到装配行为多样化。其实它并不真正具体一个对外提供配置的能力,@ConfigurationProperties 只是规定了一个类如何成为一个配置服务类,但并不使它真正成为一个配置服务类。使它具备这种能力也即使它成为一个 Bean,@Conponent 就能做到,@EnableConfigurationProperties 也能做取。


3.@EnableConfigurationProperties 允许任意一个类具有对外提供配置的能力。它与 @Bean 的方式不同,@Bean 是配置在类本身上,一劳永逸,一旦配置,任何地方都可以注入。而 @EnableConfigurationProperties 是配置在希望使用此配置服务的那个类上面。这样就可以实现可拔插。下面拷贝一份代码以说明:

@ConfigurationProperties(
        prefix = "fps",
        ignoreUnknownFields = true
)
@Data
public class FpsProperties {

    private String host="localhost";
    private int port=7008;
    private String username;
    private String password;
    private String orgid="99996";
    private int connectTimeout=10000;
    private int connectRequestTimeout=10000;
    private int socketTimeout=120000;//相当于读超时

    private int retryCount=3;//重试次数
    private boolean fpsEnabled=true;

}

//-------------------------------------------------------------------------------
@Configuration
@EnableConfigurationProperties({FpsProperties.class})
@ConditionalOnClass({FpsClient.class})
@ConditionalOnProperty(
        prefix = "fps",
        name = {"enabled"},
        matchIfMissing = true
)
@Slf4j
public class FpsAutoConfiguration {
    @Autowired
    private FpsProperties fpsProperties;


    @Bean
    @ConditionalOnMissingBean
    @ConfigurationProperties(
            prefix = "fps"
    )
    public FpsService fpsService() {
        FpsServiceImpl fpsService = new FpsServiceImpl(fpsProperties.getUsername(), fpsProperties.getPassword(), fpsProperties.getHost(), fpsProperties.getPort(), fpsProperties.getOrgid(), fpsProperties.getConnectRequestTimeout(), fpsProperties.getConnectTimeout(), fpsProperties.getSocketTimeout());
        return fpsService;
    }

}

首先,@configuration 表示 FpsAutoConfiguration 类是一个可生成多个 Bean 的配置器。@EnableConfigurationProperties({FpsProperties.class}) 表示使 FpsProperties 这个类拥有对“我”提供配置的能力。类里面的 @Autowired 就把这种配置能力注入进来了。@ConditionalOnClass({FpsClient.class}) 表示当整个 jvm 中存在 FpsClient 这个类时,本 @Configuration 才生效,否则不生效。当时看这个配置非常疑惑,如果 FpsClient 这个类不存在,此行代码应该会立即报错,何谈加载到 jvm 中去运行呢?解释一下,@conditionalOnClass 一般是在库中使用的,假设库工程是 A,有上面的代码。另有一个关联工程 B,A 中没有 FpsClient 类,而 B 中有,让 A 工程依赖于 B,将 A 打包,A.jar 作为一个库对外发布。此时,A.jar 是没有 FpsClient 类的定义的。此时,有一个客户工程,付费了,想使用 A.jar ,而 C 没有定义 FpsClient 类,所以 A.jar 中的上述配置就不会生效,因此,C 在运行时,就不会承担 A 里面产生的 Bean 的负担。就这是热拔插的意思。所以 @ConditionalOnClass 是为了完成这件事情的。

@ConditionalOnProperty 与 @ConditionalOnClass 目的一致,逻辑上是且的关系,只要 @ConditionalOnProperty 中规定的条件没有满足,整个 @Configuration 就不生效。上面的配置中,规定了配置变量 fps.enabled=true 时,@Configuration 才生效。

一般情况下,若变量是 fps.x.y.z.enabled,则上面要写为:prefix="fps.x.y.z", name={"enabled"}。这是因为 name 一定是最终的名字,而不含有任何前缀。

后面类里面的,@Bean 就会很熟悉了,表示定义一个 Bean 生成的条件,依赖的变量和生成的步骤。@ConditionalOnMissingBean 表示此 Bean 生成的规则:只有当这个类的  Bean 没有生成时,才会去生成 Bean. @ConfigurationProperties 其实是多余的,因为后面的代码直接使用了 FpsProperties 去取值.

上面生成  FpsServiceImpl 的 Bean 其实可以更简单:

FpsServiceImpl fpsService = new FpsServiceImpl();//前提是有无参构造方法

此时 @ConfigurationProperties 表示去FpsProperties 中找变量的值,还是默认配置文件  application.properties 中按 prefix = fps 去读呢。这个问题可能没有意义,首先要明确一点,所有配置类的配置加载器是同一个,不可能存在不同的值,至于存在同名的多个配置文件,加载的是哪一个就要具体看了,一般是后面加载的会替换前面加载的。因此,上面的问题就不用回答的。

另外,使用了此注解的类所在的包及子包下面的类也默认使用了此注解。若将此注解应用到根目录包下面的类,则所有类也都应用了此注解。所以此注解的使用一般要放在最高级的根目录类上面。

关于这个注解,最后再举一个例:

@Configuration
@EnableConfigurationProperties(DataSourceProperties.class)
public class MyBatisConfig {


//    @Value("${spring.datasource.encode-password}")
//    private String encodePassword;
    @Autowired
    private DataSourceProperties properties;

    //这个配置会加载所有spring.datasource配置注入DataSource对象,未加载会有问题。
    @Bean
    @ConfigurationProperties(prefix = DataSourceProperties.PREFIX)
    public DataSource dataSource() {
      //  Assert.isNull(this.properties.getPassword(), "必须为空否则,加密密码会被覆盖");

        DataSourceBuilder factory = DataSourceBuilder
                .create(this.properties.getClassLoader())
                .driverClassName(this.properties.getDriverClassName())
                .url(this.properties.getUrl()).username(this.properties.getUsername())
                .password(properties.getPassword());

        if (this.properties.getType() != null) {
            factory.type(this.properties.getType());
        }
        BasicDataSource basicDataSource= (BasicDataSource)factory.build();
        basicDataSource.setMaxTotal(150);
        basicDataSource.setMaxWaitMillis(5000);

        return basicDataSource;
    }


    @Bean(name = "sqlSessionFactory")
    @ConditionalOnMissingBean
    public SqlSessionFactory sqlSessionFactoryBean(DataSource dataSource) {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setTypeAliasesPackage("com.******.entity");

        //分页插件
        PageHelper pageHelper = new PageHelper();
        Properties properties = new Properties();
        properties.setProperty("reasonable", "true");
        properties.setProperty("supportMethodsArguments", "true");
        properties.setProperty("returnPageInfo", "check");
        properties.setProperty("params", "count=countSql");
        pageHelper.setProperties(properties);
        //添加插件
        bean.setPlugins(new Interceptor[]{pageHelper});

        //添加XML目录
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        try {
            bean.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));
            return bean.getObject();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    @Bean
    @ConditionalOnMissingBean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

}


4.@EnableAutoconfiguration 这个注解作用在于让 Spring Boot 根据应用所声明的依赖来对 Spring 框架进行自动配置,比较智能的是,它还根据 classpath 中的 jar 包推断需要引入哪些注解/ Bean ,另外,使用了此注解的类所在的包及子包下面的类也默认使用了此注解。若将此注解应用到根目录包下面的类,则所有类也都应用了此注解,这也是最通常的做法,实际上, @SpingBootApplication 注解就使用了这个注解。详细的说明可以参看 EnableAutoconfiguration  注解实现文件的说明。

@Configuration
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class MyConfiguration {
}



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring的AOP(面向切面编程)是通过注解配置的。AOP是一种用于将横切关注点(如日志记录、事务管理等)与主业务逻辑分离的技术。使用注解配置AOP可以更简洁、灵活地定义切面和通知。 要配置AOP,我们需要使用到Spring几个注解。首先是使用@Aspect注解定义一个切面,该注解告诉Spring这是一个切面类。然后,我们可以在切面类内部定义多个通知方法,通知方法使用@Before、@After、@Around等注解来指定它们在目标方法之前、之后或者环绕目标方法执行。 在通知方法内部,我们可以通过使用@Pointcut注解定义切点表达式,切点表达式用于指定哪些方法需要被拦截,以何种方式进行拦截。通过@Pointcut定义的切点可以被多个通知方法共享。 除了切面和通知,我们还可以使用其他注解来指定通知的类型。例如,使用@Before注解表示在目标方法执行之前执行通知方法,使用@After注解表示在目标方法执行之后执行通知方法,使用@Around注解表示在目标方法执行之前和之后都执行通知方法。 配置AOP时,我们还需要使用@Bean注解来将切面类注册为Spring的一个bean。这样,Spring容器才能够自动识别它并将其应用于适当的目标方法。 总结一下,通过使用注解配置AOP,我们可以更方便地定义切面和通知,并将它们应用于目标方法。Spring的AOP注解提供了灵活的方式来实现横切关注点的分离,使得代码更具可读性和可维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值