39

我想介绍一些只在开发过程中执行的方法。

我想我可以Spring @Profile在这里使用注释?但是如何在类级别应用此注释,以便仅在属性中配置了特定配置文件时才调用此方法?

spring.profiles.active=dev

将以下内容作为伪代码。如何才能做到这一点?

class MyService {

    void run() { 
       log();
    }

    @Profile("dev")
    void log() {
       //only during dev
    }
}
4

8 回答 8

34

对于不希望有多个@Beans注释的未来读者@Profile,这也可能是一个解决方案:

class MyService {

   @Autowired
   Environment env;

   void run() { 
      if (Arrays.asList(env.getActiveProfiles()).contains("dev")) {
         log();
      }
   }

   void log() {
      //only during dev
   }
}
于 2015-10-19T15:31:28.933 回答
19

如您可以在http://docs.spring.io/spring/docs/3.1.x/javadoc-api/org/springframework/context/annotation/Profile.html上阅读

@Profile 注解可以通过以下任何方式使用:

作为直接或间接使用@Component 注释的任何类的类型级别注释,包括作为元注释的@Configuration 类,用于编写自定义构造型注释如果@Configuration 类使用@Profile 标记,则所有@除非一个或多个指定配置文件处于活动状态,否则将绕过与该类关联的 Bean 方法和 @Import 注释。 这与 Spring XML 中的行为非常相似:如果提供 beans 元素的 profile 属性,例如 ,则 beans 元素将不会被解析,除非 profile 'p1' 和/或 'p2' 已被激活。同样,如果@Component 或@Configuration 类被标记为@Profile({"p1", "p2"}),那么除非配置文件'p1',否则该类将不会被注册/处理

因此,类上的 @Profile 注释适用于它的所有方法和导入。不上课。

您尝试做的可能是通过拥有两个实现相同接口的类并根据配置文件注入一个或另一个来实现。看看这个问题的答案。

处理不同环境的注解驱动的依赖注入

于 2014-03-12T10:52:51.277 回答
13

只是想补充一个答案,说这在方法级别上的当前弹簧是可能的,这是公然错误的。通常在方法上使用@Profile 是行不通的——它唯一可以使用的方法是在带有@Bean 注释的@Configuration 类中。

我用 Spring 4.2.4 运行了一个快速测试,在那里可以看到

  • @Configuration 类 bean 创建方法中的 @Profile 工作
  • bean 方法中的 @Profile 不起作用(并且预计不会起作用 - 文档有点模棱两可)
  • 当且仅当它与 bean 定义在相同的上下文中、在配置类中或使用上下文扫描时,类级别的 @Profile 才有效
  • env.acceptsProfiles("profile"), Arrays.asList(env.getActiveProfiles()).contains("profile") 有效

测试类:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Profile;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.Arrays;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { ProfileTest.ProfileTestConfiguration.class })
@ActiveProfiles("test")
public class ProfileTest {
    static class SomeClass {}
    static class OtherClass {}
    static class ThirdClass {
        @Profile("test")
        public void method() {}
    }
    static class FourthClass {
        @Profile("!test")
        public void method() {}
    }

    static class ProfileTestConfiguration {
        @Bean
        @Profile("test")
        SomeClass someClass() {
            return new SomeClass();
        }
        @Bean
        @Profile("!test")
        OtherClass otherClass() {
            return new OtherClass();
        }
        @Bean
        ThirdClass thirdClass() {
            return new ThirdClass();
        }
        @Bean
        FourthClass fourthClass() {
            return new FourthClass();
        }
    }

    @Autowired
    ApplicationContext context;

    @Test
    public void testProfileAnnotationIncludeClass() {
        context.getBean(SomeClass.class);
    }
    @Test(expected = NoSuchBeanDefinitionException.class)
    public void testProfileAnnotationExcludeClass() {
        context.getBean(OtherClass.class);
    }
    @Test
    public void testProfileAnnotationIncludeMethod() {
        context.getBean(ThirdClass.class).method();
    }
    @Test(expected = Exception.class)  // fails
    public void testProfileAnnotationExcludeMethod() {
        context.getBean(FourthClass.class).method();
    }
}
于 2017-03-24T08:56:37.533 回答
13

@Profile可以与方法和基于 Java 的配置一起使用

例如 PostgreSQL (LocalDateTime) 和 HSQLDB (2.4.0 Timestamp 之前) 的单独数据库时间戳:

@Autowired
private Function<LocalDateTime, T> dateTimeExtractor;

@Bean
@Profile("hsqldb")
public Function<LocalDateTime, Timestamp> getTimestamp() {
    return Timestamp::valueOf;
}

@Bean
@Profile("postgres")
public Function<LocalDateTime, LocalDateTime> getLocalDateTime() {
    return dt -> dt;
}

还可以查看Spring Profiles 示例:3. 更多…(示例 Spring @Profile 在方法级别)

于 2017-04-26T22:18:57.917 回答
7

可能在 4.1 中

@Profile 注解可以通过以下任何方式使用:

作为使用@Component 直接或间接注释的任何类的类型级别注释,包括@Configuration 类。作为元注释,用于编写自定义构造型注释。作为任何@Bean 方法的方法级注释

http://docs.spring.io/spring/docs/4.1.x/javadoc-api/org/springframework/context/annotation/Profile.html

于 2015-03-31T04:00:00.630 回答
3

@Profile不能用于此,但您不妨编写自己的@RunOnProfile注释和方面。您的方法如下所示:

@RunOnProfile({"dev", "uat"})
public void doSomething() {
    log.info("I'm doing something on dev and uat");
}

或者

@RunOnProfile("!prod")
public void doSomething() {
    log.info("I'm doing something on profile other than prod");
}

这是@RunOnProfile注释和方面的代码:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RunOnProfile {
    String[] value();

    @Aspect
    @Configuration
    class RunOnProfileAspect {

        @Autowired
        Environment env;

        @Around("@annotation(runOnProfile)")
        public Object around(ProceedingJoinPoint joinPoint, RunOnProfile runOnProfile) throws Throwable {
            if (env.acceptsProfiles(runOnProfile.value()))
                return joinPoint.proceed();
            return null;
        }
    }
}

注意 1:如果您期望得到回报并且配置文件不适用,您会得到null.

注意 2:这项工作与任何其他 Spring 方面一样。您需要调用自动装配的 bean 方法,以便 bean 代理启动。换句话说,您不能直接从其他类方法调用该方法。如果需要,您需要在类上自动装配组件并调用self.doSomething().

于 2021-02-26T21:43:54.847 回答
2

使用接受配置文件(配置文件)

class Test {

  @Autowired
  Environment env

  public void method1(){
     if(env.acceptsProfiles(Profiles.of("dev")){
        //invoke method
        doStuff();
     }
  }
}
于 2021-11-10T13:57:32.043 回答
1

使用环境配置文件可以实现:

class MyClass {

   @Autowired
   Environment env;

   void methodA() { 
      if (env.acceptsProfiles(Profiles.of("dev"))) {
         methodB();
      }
   }

   void methodB() {
      // when profile is 'dev'
   }
}

Profiles.of也可以与逻辑表达式一起使用:

static Profiles of(String...profiles) 创建一个新的 Profiles 实例,用于检查是否与给定的配置文件字符串匹配。如果给定的配置文件字符串中的任何一个匹配,则返回的实例将匹配。

配置文件字符串可能包含一个简单的配置文件名称(例如“生产”)或配置文件表达式。配置文件表达式允许表达更复杂的配置文件逻辑,例如“生产和云”。

配置文件表达式中支持以下运算符:

!- 配置文件的逻辑非 & - 配置文件的逻辑与 | - 配置文件的逻辑或 请注意 & 和 | 不使用括号不能混合运算符。例如“a & b | c”不是一个有效的表达式;它必须表示为“(a & b) | c”或“a & (b | c)”。

于 2020-06-05T11:08:09.810 回答