@Component
class MyDao {
void save(String value) {
// write to file
}
}
@Component
class MyService {
@Autowired
MyDao dao;
void doSomething() {
dao.save("foo");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="..." />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="...">...</prop>
</props>
</property>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="default" />
</bean>
<tx:annotation-driven />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
</beans>
@Configuration
public class JpaDatabaseConfig {
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(...);
return dataSource;
}
@Bean
public SessionFactory sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
Properties properties = new Properties();
properties.put("...", ...);
sessionFactory.setHibernateProperties(properties);
return sessionFactory.getObject();
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPersistenceUnitName("default");
return entityManagerFactoryBean;
}
@Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
}
spring.datasource.url=...
Maven
<?xml version="1.0" encoding="UTF-8"?>
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>fr.pinguet62</groupId>
<artifactId>spring-boot</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.5.4.RELEASE</version>
</dependency>
</dependencies>
</project>
Java
@SpringBootApplication
@RestController
public class MyController {
public static void main(String[] args) throws Exception {
SpringApplication.run(MyController.class, args);
}
@GetMapping("/")
public String home() {
return "Hello Davidson!";
}
}
$ curl localhost:8080/
Hello Davidson!
@Conditional
@Conditional
Exemple
Code condionné par l'environnement d'exécution de l'application.
@Conditional
Solution 1 : le bon vieux if/else
...
@Service
class MyService {
void doSomething() {
String currentEnv = System.getProperty("environment");
if (currentEnv.equals("DEV"))
System.out.println("I'm in development");
else if (currentEnv.equals("PROD"))
System.out.println("I'm in production");
}
}
Moche !!!
@Conditional
Solution 2 : le polymorphisme
interface Script {
void execute();
}
class DevScript implements Script {
@Override
public void execute() {
System.out.println("In development");
}
}
class ProdScript implements Script {
@Override
public void execute() {
System.out.println("In production");
}
}
@Conditional
Solution 2 : le polymorphisme
@Service
class MyService {
Script script;
// Factory
MyService() {
String currentEnv = System.getProperty("environment");
if (currentEnv.equals("DEV"))
script = new DevScript();
else if (currentEnv.equals("PROD"))
script = new ProdScript();
}
void doSomething() {
script.execute();
}
}
Context Spring...
@Conditional
Solution : des @Bean
@Component
class DevScript implements Script { /*...*/ }
@Component
class ProdScript implements Script { /*...*/ }
@Service
class MyService {
@Autowired
Script script;
void doSomething() {
script.execute();
}
}
Collision...
@Conditional
@Conditional(MyCondition.class)
@Component
class MyComponent {}
class MyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return ...;
}
}
@Conditional
class EnvCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnEnv.class.getName());
String expectedEnv = (String) attributes.get("value");
String currentEnv = System.getProperty("environment");
boolean matches = currentEnv.equals(expectedEnv);
return new ConditionOutcome(matches, (String) null);
}
}
@Conditional(EnvCondition.class)
@interface ConditionalOnEnv {
String value();
}
@Conditional
@ConditionalOnEnv("DEV")
@Component
class DevScript implements Script { /*...*/ }
@ConditionalOnEnv("PROD")
@Component
class ProdScript implements Script { /*...*/ }
@Conditional
@ConditionalOnMissingBean
@ConditionalOnClass
@ConditionalOnProperty
SpringFactoriesLoader
SpringFactoriesLoader
Situation
Classe MyConfig
qui fournie une (bon vieux) Properties
Properties properties = new MyConfig().getProperties();
String value = properties.getProperty("key");
Problème/Conséquence
Configuration manuelle : absence du PropertySource
de Spring
@Value
auto-configuration
SpringFactoriesLoader
Solution : EnvironmentPostProcessor
public class MyConfigEnvironmentLoader implements EnvironmentPostProcessor {
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
Properties properties = new MyConfig().getProperties();
PropertySource<?> propertySource = new PropertiesPropertySource("MyConfig", properties);
environment.getPropertySources().addLast(propertySource);
}
}
/META-INF/spring.factories
org.springframework.boot.env.EnvironmentPostProcessor = \
fr.pinguet62.MyConfigPropertiesEnvironmentLoader
SpringFactoriesLoader
PropertySourceLoader
SpringApplicationRunListener
ApplicationContextInitializer
ApplicationListener
/META-INF/spring.factories
# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\
org.springframework.boot.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.logging.LoggingApplicationListener
Arrêtez de configurez !!!