方法级别的Spring配置文件?

时间:2014-03-12 10:49:21

标签: java spring spring-profiles

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

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

spring.profiles.active=dev

将以下内容作为伪代码。怎么办呢?

class MyService {

    void run() { 
       log();
    }

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

7 个答案:

答案 0 :(得分:13)

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

class MyService {

   @Autowired
   Environment env;

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

   void log() {
      //only during dev
   }
}

答案 1 :(得分:11)

您可以阅读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中的行为非常相似:如果是配置文件   例如,bean元素的属性被提供,除非配置文件,否则将不解析beans元素   'p1'和/或'p2'已被激活。同样,如果@Component或   @Configuration类标有@Profile({“p1”,“p2”}),该类   除非配置文件'p1'和/或'p2'具有,否则不会注册/处理   被激活了。

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

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

Annotation-driven dependency injection which handles different environments

答案 2 :(得分:10)

只是想补充一点,answer saying this is possible with current spring on method-level显然是错误的。一般情况下对方法使用@Profile是行不通的 - 它将使用的唯一方法是在@Configuration类中使用@Bean注释。

我使用Spring 4.2.4进行快速测试,在那里可以看到

  • @Profile in @Configuration类bean创建方法工作
  • @Profile in bean的方法不起作用(预计不会起作用 - 文档有点含糊不清)
  • 类级别@Profile工作当且仅当它与bean定义在相同的上下文中时,在配置类中或者如果使用了context-scan,那么
  • env.acceptsProfiles(“profile”),Arrays.asList(env.getActiveProfiles())。contains(“profile”)works

测试类:

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();
    }
}

答案 3 :(得分:7)

可能在4.1

  

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

     

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

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

答案 4 :(得分:6)

@Profile可以与方法一起使用,也可以与Java Based Configuration

一起使用

e.g。 PostgreSQL(LocalDateTime)和HSQLDB(2.4.0时间戳之前)的单独DB时间戳:

@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 example:3。更多...(在方法级别采样Spring @Profile)

答案 5 :(得分:0)

使用Environment个人资料可以实现:

class MyClass {

   @Autowired
   Environment env;

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

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

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

(字符串...个人档案)的静态个人档案创建一个新的个人档案实例 根据给定的配置文件字符串检查匹配项。的 如果有任何给定的配置文件字符串,则返回的实例将匹配 匹配。

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

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

! -逻辑非概要文件&-逻辑非概要文件| -- 逻辑或配置文件,请注意&和|经营者 不使用括号不能混用。例如,“ a&b | c”是 不是有效的表达;它必须表示为“(a&b)| c”或“ a& (b | c)”。

答案 6 :(得分:0)

@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()