SpringBoot构建微服务实战 之 @Enable*

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012437781/article/details/78625743

SpringBoot构建微服务实战 之 @Enable*

本节我们将学一下SpringBoot 的@Enable* 注解。
SpringBoot 的@Enable* 的目的在于起因Spring的某一个特性,这一个特性可以是Spring自有的,也可以是我们自定义的。本节我们将详细学习一下启用 spring 自有的 @Enbale* 特性。


分类

Spring自生提供的 @Eable* 注解:

  • 常用的@Enbale 注解说明:

    • @EnableAspectJAutoProxy:表示开启AOP代理自动配置,如果配@EnableAspectJAutoProxy表示使用cglib进行代理对象的生成;设置@EnableAspectJAutoProxy(exposeProxy=true)表示通过aop框架暴露该代理对象,aopContext能够访问。

    • @EnableAsync:@EnableAsync注解开启异步方法的支持。参考文章

    • @EnableScheduling:@EnableScheduling注解开启计划任务的支持。参考文章

    • @EnableWebMVC:@EnableWebMVC注解用来开启Web MVC的配置支持。

    • @EnableConfigurationProperties:@EnableConfigurationProperties注解是用来开启对@ConfigurationProperties注解配置Bean的支持。

    • @EnableJpaRepositories:@EnableJpaRepositories注解开启对Spring Data JPA Repostory的支持。Spring Data JPA 框架,主要针对的就是 Spring 唯一没有简化到的业务逻辑代码,至此,开发者连仅剩的实现持久层业务逻辑的工作都省了,唯一要做的,就只是声明持久层的接口,其他都交给 Spring Data JPA 来帮你完成!

    • @EnableCaching:@EnableCaching注解开启注解式的缓存支持

    通过这些简单的@Enable*可以开启一项功能的支持,从而避免自己配置大量的代码,很大程度上降低了使用难度。


实例

下面我们着重讲解三个 @Enable* 注解功能。

  • @EnableConfigurationProperties

    • 在默认配置文件(application.properties)中配置:

      condition.onPropertyCondition=true
      
      tomcat.host=192.168.100.19
      tomcat.port=8080
    • EnableConfigurationProperty.java

      package com.springBoot.entrance.enableAnnotation;
      
      import org.springframework.boot.context.properties.ConfigurationProperties;
      import org.springframework.boot.context.properties.EnableConfigurationProperties;
      import org.springframework.stereotype.Component;
      
      /**
       *使用@EnableConfigurationProperties 可以将SpringBoot读取的配置文件中的属性注入到某个实体中
       *该实体的所有字段应和配置文件中的保持一致
       */
      @Component
      @ConfigurationProperties(prefix ="tomcat")
      @EnableConfigurationProperties
      public class EnableConfigurationProperty {
          private String host;
          private Integer port;
          public String getHost() {
              return host;
          }
          public void setHost(String host) {
              this.host = host;
          }
          public Integer getPort() {
              return port;
          }
          public void setPort(Integer port) {
              this.port = port;
          }
          @Override
          public String toString() {
              return "EnableConfigurationProperty [host=" + host + ", port=" + port + "]";
          }
      }
      
    • App.java 核心代码:

      System.out.println(context.getBean(EnableConfigurationProperty.class));
    • 结果:

      这里写图片描述


  • @EnableAsync

  • AsyncExample.java

    package com.springBoot.entrance.enableAnnotation;
    
    import java.util.concurrent.TimeUnit;
    
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.scheduling.annotation.EnableAsync;
    import org.springframework.stereotype.Component;
    
    @Component
    @EnableAsync
    public class AsyncExample {
    
        @Async
        public void running() {
            try {
                for(int i=1;i<10;i++){
                    System.out.println("===================="+i);
                    TimeUnit.SECONDS.sleep(1);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    }
    
  • App.java

    context.getBean(AsyncExample.class).running();
    System.out.println("==================After Async sysout======================");
    

    代码解读:一般@EnableAsync 需要和 @Async一起使用,@EnableAsync 用于类声明,@Async 用于方法声明。

  • 结果:
    这里写图片描述

    有结果可以看出我们执行的两个方法是异步输出的,这就是@EnableAsync 的特性。


  • @EnableTransactionManagement

    • EnableTransaction.java

      package com.springBoot.entrance.enableAnnotation;
      
      import org.springframework.stereotype.Component;
      import org.springframework.transaction.annotation.EnableTransactionManagement;
      import org.springframework.transaction.annotation.Isolation;
      import org.springframework.transaction.annotation.Propagation;
      import org.springframework.transaction.annotation.Transactional;
      
      @Component
      @EnableTransactionManagement
      public class EnableTransaction {
      
          /**
           * 启用@EnableTransactionManagement 并陪着 @Transactional 实现Spring 声明式事务
           */
          @Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.DEFAULT,timeout=1,readOnly=true,rollbackFor=Throwable.class)
          public void enableTransaction(){
              System.out.println("This Method has setted up  EnableTransaction ");
          }
      }
      

      代码解读:一般 @EnableTransactionManagement 需要和 @Transactional 配合使用,@EnableTransactionManagement 用于类声明,@Transactional 用户方法声明。


自定义@Enable * 特性

在SpringBoot 中我们可以通过自定义一些特定 @Enable* 注解,下面我们将通过一个实例来说明一下。

  • 新建目录
    这里写图片描述

  • Market.java(无任何属性或实现)

    package com.springBoot.entrance.importBean.indirectImportSelector;
    
    public class Market {
    
    }
    
  • Sales.java(无任何属性或实现)

    package com.springBoot.entrance.importBean.indirectImportSelector;
    
    public class Sales {
    
    }
    
  • EnableLogInfo.java

    package com.springBoot.entrance.importBean.indirectImportSelector;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    import org.springframework.context.annotation.Import;
    
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @Documented
    @Import(MyImportSelector.class)
    /**
     *自定义Enable*
     *1.
     */
    public @interface EnableLogInfo {
    
        String[] name();
    
    
    }
    
  • MyImportSelector.java

    package com.springBoot.entrance.importBean.indirectImportSelector;
    
    import org.springframework.context.annotation.Import;
    import org.springframework.context.annotation.ImportSelector;
    import org.springframework.core.type.AnnotationMetadata;
    import org.springframework.stereotype.Component;
    
    @Component
    @Import(value = { MyImportSelector.class })
    @EnableLogInfo(name="onlySale")
    /**
     * Bean的批量注入 使用自定义 ImportSelector 须实现 ImportSelector
     * 接口,返回值必须是class全称测集合,该集合内的所有类都将被Spring IOC容器统一管理
     */
    public class MyImportSelector implements ImportSelector {
    
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
    
            System.out.println(importingClassMetadata.getAnnotationAttributes(EnableLogInfo.class.getName()).toString().contains("onlySale"));
    
            //获取自定的@EnableLogInfo 信息 如果包含 onlySale 则只注入Sales class 否则 注入 Sales 和 Market 两个类
            if (importingClassMetadata.getAnnotationAttributes(EnableLogInfo.class.getName()) != null
                    && importingClassMetadata.getAnnotationAttributes(EnableLogInfo.class.getName()).toString().contains("onlySale")) {
    
                return new String[] {Sales.class.getName() };
            }
    
            // 将指定的类
            return new String[] { Market.class.getName(), Sales.class.getName() };
        }
    
    }
    

    代码解读:此处使用了@Import注解和实现了 ImportSelector 来注入Bean

    代码逻辑:通过 实现 ImportSelector 获得 importingClassMetadata 对象,然后再由 importingClassMetadata 获得 我们自定的@EnableLogInfo 中的 值,如果 该值包含 onlySale 则 我们只装配Sale 类实例,否则 装配 Sale 和Market 两个类的实例。

    特别说明:要理解ImportSelecotor 是如何抽象Bean 实例注入的请参考:SpringBoot构建微服务实战 之 @Import

  • App.java

    //实现 ImportSelector 实现Bean 的批量注入
            System.out.println(context.getBean(MyImportSelector.class));
            System.out.println(context.getBean(Market.class));
            System.out.println(context.getBean(Sales.class));
  • 结果

    • 本例子

      这里写图片描述

      由结果可知在我们指定的 @EnableLogInfo注解中我们传入了 onlySale 字符串,因而 Spring IOC Container 中只注入了 Sale.java 的实例。

    • 其他结果
      此次演示我们在自定义的 @EnableLogInfo 中传入 AllClasses 字符串。

      这里写图片描述
      由结果我们看出 Sale.java 和Market.java 的实例都已注入到了 Spring IOC 容器中。


小结

  • SpringBoot 为我们提供一些列的 @Enable* 特性,我们只需要根据逻辑的需要开启特定的特性即可,而不再需要做配置了。

  • SpringBoot 中除了提供了Spring 自有的@Enable* 特性我们还可以高度自定义 @Enable* 特性,来满足我特定的需求和应用场景。

  • 一般SpringBoot @Enbale*特性需要结合@Import 注解来一起使用,关于@Import的使用我们将在后面的章节中学习,因而在学习是请一定结合@Enable * 和 @Import 一起学习。

  • 在创建自定义@Enable* 时 类型必须为@interface 且 必须使用一下注解,具体可参考代码:

    • @Retention(RetentionPolicy.RUNTIME)
    • @Target(ElementType.TYPE)
    • @Documented

猜你喜欢

转载自blog.csdn.net/u012437781/article/details/78625743