问题
I'd like to introduce some methods that are only executed during development.
I thought I might use Spring @Profile
annotation here? But how can I apply this annotation on class level, so that this method is only invoked if the specific profile is configured in properties?
spring.profiles.active=dev
Take the following as pseudocode. How can this be done?
class MyService {
void run() {
log();
}
@Profile("dev")
void log() {
//only during dev
}
}
回答1:
AS you can read on http://docs.spring.io/spring/docs/3.1.x/javadoc-api/org/springframework/context/annotation/Profile.html
The @Profile annotation may be used in any of the following ways:
as a type-level annotation on any class directly or indirectly annotated with @Component, including @Configuration classes as a meta-annotation, for the purpose of composing custom stereotype annotations If a @Configuration class is marked with @Profile, all of the @Bean methods and @Import annotations associated with that class will be bypassed unless one or more the specified profiles are active. This is very similar to the behavior in Spring XML: if the profile attribute of the beans element is supplied e.g., , the beans element will not be parsed unless profiles 'p1' and/or 'p2' have been activated. Likewise, if a @Component or @Configuration class is marked with @Profile({"p1", "p2"}), that class will not be registered/processed unless profiles 'p1' and/or 'p2' have been activated.
So, a @Profile annotation on a class, aplies to all of it's methods and imports. Not to the class.
What you're trying to do could probably be achieved by having two classes that implement the same interface, and injecting one or another depending on the profile. Take a look at the answer to this question.
Annotation-driven dependency injection which handles different environments
回答2:
For future readers who don't want to have multiple @Beans
annotated with @Profile
, this could also be a solution:
class MyService {
@Autowired
Environment env;
void run() {
if (Arrays.asList(env.getActiveProfiles()).contains("dev")) {
log();
}
}
void log() {
//only during dev
}
}
回答3:
Just wanted to add that answer saying this is possible with current spring on method-level is blatantly wrong. Using @Profile on methods in general will not work - the only methods it will work on are in the @Configuration class with @Bean annotation on them.
I run a quick test with Spring 4.2.4, where it was seen that
- @Profile in @Configuration class bean creation methods work
- @Profile in methods of a bean does not work (and is not expected to work - docs are a bit ambiguous)
- Class-level @Profile works if and only if it's at the same context as bean definition, in the configuration class or if context-scan is used, there
- env.acceptsProfiles("profile"), Arrays.asList(env.getActiveProfiles()).contains("profile") works
Test class:
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();
}
}
回答4:
Possible in 4.1
The @Profile annotation may be used in any of the following ways:
as a type-level annotation on any class directly or indirectly annotated with @Component, including @Configuration classes. As a meta-annotation, for the purpose of composing custom stereotype annotations. As a method-level annotation on any @Bean method
http://docs.spring.io/spring/docs/4.1.x/javadoc-api/org/springframework/context/annotation/Profile.html
回答5:
@Profile
can be used with method and with Java Based Configuration
e.g. separate DB timestamp for PostgreSQL (LocalDateTime) and for HSQLDB (prior to 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;
}
Have a look also at Spring Profiles example: 3. More…(sample Spring @Profile at method level)
来源:https://stackoverflow.com/questions/22349120/spring-profiles-on-method-level