@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
@ConditionalExemple
Code condionné par l'environnement d'exécution de l'application.
@ConditionalSolution 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 !!!
@ConditionalSolution 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");
}
}
@ConditionalSolution 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...
@ConditionalSolution : 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 ...;
}
}
@Conditionalclass 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@ConditionalOnPropertySpringFactoriesLoader
SpringFactoriesLoaderSituation
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
@Valueauto-configuration
SpringFactoriesLoaderSolution : 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
SpringFactoriesLoaderPropertySourceLoaderSpringApplicationRunListenerApplicationContextInitializerApplicationListener/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 !!!