http://localhost:8080/credit\?name\=Targarian\&amount\=100
@RestController @RequiredArgsConstructor public class IronBankController { private final TransferMoneyService transferMoney; private final MoneyDao moneyDao; @GetMapping("/credit") public String credit(@RequestParam String name, @RequestParam long amount) { long resultedDeposit = transferMoney.transfer(name, amount); if (resultedDeposit == -1) { return "Rejected<br/>" + name + " <b>will`t</b> survive this winter"; } return format( "<i>Credit approved for %s</i> <br/>Current bank balance: <b>%s</b>", name, resultedDeposit ); } @GetMapping("/state") public long currentState() { return moneyDao.findAll().get(0).getTotalAmount(); } }
@Service public class NameBasedProphetService implements ProphetService { @Override public boolean willSurvive(String name) { return !name.contains("Stark") && ThreadLocalRandom.current().nextBoolean(); } }
public interface MoneyDao extends JpaRepository<Bank, String> { }
@SpringBootApplication @EnableConfigurationProperties(ProphetProperties.class) public class MoneyRavenApplication { public static void main(String[] args) { SpringApplication.run(MoneyRavenApplication.class, args); } }
spring-boot-dependencies
. There will be a huge block of dependency-management. <dependencyManagement> <dependencies> <dependency> <groupId>io.spring.platform</groupId> <artifactId>platform-bom</artifactId> <version>Brussels-SR2</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
dependencyManagement { imports { mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.RELEASE' } }
'org.springframework.boot:spring-boot-starter-web' 'org.springframework.boot:spring-boot-starter-data-jpa' 'com.h2database:h2'
AnnotationConfigApplicationContext
, some beanpostprocessors that could configure the bins according to the annotations got there, but the context was also almost empty.SpringApplication.run
and no context is visible: @SpringBootApplilcation class App { public static void main(String[] args) { SpringApplication.run(App.class,args); } }
SpringApplication.run
returns us some context.ClassPathXmlApplicationContext
, etc.SpringApplication.run
, it takes configurations as arguments and constructs the contextRipperApplication.class
public⦠main(String[] args) { SpringApplication.run(?,args); }
RipperApplication.class
String.class
"context.xml"
new ClassPathResource("context.xml")
Package.getPackage("conference.spring.boot.ripper")
String.class
, and in some conditions you donβt even have to do anything to make it work. But this is a separate story. SpringApplication.run(Object[] sources, String[] args) # APPLICATION SETTINGS (SpringApplication) spring.main.sources= # class name, package name, xml location spring.main.web-environment= # true/false spring.main.banner-mode=console # log/off
SpringApplication
is really important here - further along the slides we will have it by Carlson.SpringApplication.run
:RipperApplication.class
String.class
"context.xml"
new ClassPathResource("context.xml")
Package.getPackage("conference.spring.boot.ripper")
SpringApplication
do for us?new
through the new
ourselves, we had a lot of different classes that implement the ApplicationContext
interface:WebApplicationContext
) or a generic context ( AnnotationConfigApplicationContext
).SpringApplication.run
. At the entrance, it gets a class labeled with some Spring Boot annotation.InternalResourceViewResolver
. Connect the jpa starter - you need an EntityManagerFactory
bin. All these bins are already somewhere in the configurations of starters are registered, and they magically come into the application without any action on our part.ContextRefreshEvent
. public class IronListener implements ApplicationListener<ContextRefreshedEvent> { @Override public void onApplicationEvent(ContextRefreshedEvent event) { System.out.println(" ..."); } }
@Configuration public class IronConfiguration { @Bean public RavenListener ravenListener() { return new RavenListener(); } }
@Enable
for everyone? And if the starter has several configurations? The main configuration class will be all hung up @Enable*
, how is the Christmas tree?spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.ironbank.IronConfiguration
@Configuration public class IronConfiguration { @Bean public RavenListener ravenListener() { return new RavenListener(); } }
compile project(':iron-starter')
new AnnotationConfigApplicationContext
and passed some configuration to the input, which was a java class. Now we also write SpringApplication.run
and pass there a class that is a configuration, only it is marked with another rather powerful annotation @SpringBootApplication
, which bears the whole world behind it. @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication { β¦ }
@Configuration
, that is, it is a configuration. There you can write @Bean
and, as usual, prescribe bins.@ComponentScan
stands above it. By default, it scans all packages and subpackages. Accordingly, if you start creating services in the same package or in its @Service
β @Service
, @RestController
β they are automatically scanned, since the scanning process starts your main configuration.@SpringBootApplication
does nothing new. He simply collected all the best practices that were in applications on Spring, so that it is now some composition of annotations, including @ComponentScan
.@EnableAutoConfiguration
. It was this class that I wrote in spring.factories.@EnableAutoConfiguration
, if you look, carries with it @Import
: @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({EnableAutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<?>[] exclude() default {}; String[] excludeName() default {}; }
@EnableAutoConfiguration
is to make an import that we wanted to get rid of in our application, because its implementation should have forced us to write the name of some class from the starter. And we can only learn it from the documentation. But everything must be on its own.ImportSelector
. In the usual Spring, we write Import(Some Configuration.class)
some configuration and it loads, like all dependent ones. Same ImportSelector
, it is not a configuration. ImportSelector
all our starters into context. It processes the @EnableAutoConfiguration
annotation from spring.factories, which selects which configurations to load, and adds to the context those bins that we registered in IronConfiguration. static <T> List<T> loadFactories( Class<T> factoryClass, ClassLoader cl ) static List<String> loadFactoryNames( Class<?> factoryClass, ClassLoader cl )
org.springframework.boot:spring-boot-autoconfigure
, META-INF/spring.factories EnableAutoConfiguration
, ( , , 80). spring-boot-autoconfigure.jar/spring.factories</b> org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\ org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\ org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration.\ ...
CacheAutoConfiguration
, β , : for (int i = 0; i < types.length; i++) { Imports[i] = CacheConfigurations.getConfigurationClass(types[i]); } return imports;
private static final Map<CacheType, Class<?>> MAPPINGS; static { Map<CacheType, Class<?>> mappings = new HashMap<CacheType, Class<?>>(); mappings.put(CacheType.GENERIC, GenericCacheConfiguration.class); mappings.put(CacheType.EHCACHE, EhCacheCacheConfiguration.class); mappings.put(CacheType.HAZELCAST, HazelcastCacheConfiguration.class); mappings.put(CacheType.INFINISPAN, InfinispanCacheConfiguration.class); mappings.put(CacheType.JCACHE, JCacheCacheConfiguration.class); mappings.put(CacheType.COUCHBASE, CouchbaseCacheConfiguration.class); mappings.put(CacheType.REDIS, RedisCacheConfiguration.class); mappings.put(CacheType.CAFFEINE, CaffeineCacheConfiguration.class); addGuavaMapping(mappings); mappings.put(CacheType.SIMPLE, SimpleCacheConfiguration.class); mappings.put(CacheType.NONE, NoOpCacheConfiguration.class); MAPPINGS = Collections.unmodifiableMap(mappings); }
@Conditional
, conditions, , true
false
. , . java- Spring , conditional. , , conditional false
, . @Configuration <b>@ConditionalOnProduction</b> public class IronConfiguration { @Bean public RavenListener ravenListener() { return new RavenListener(); } }
@Retention(RUNTIME) @Conditional(OnProductionCondition.class) public @interface ConditionalOnProduction { }
public class OnProductionCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { return JOptionPane.showConfirmDialog(parentComponent: null, " ?") == 0; } }
@Conditional(OnProductionCondition.class)
, , true
false
. , , - .@ConditionalOnProduction
. , . , β @ConditionalOnProduction
. , , 15 , . . @Configuration @ConditionalOn public class UndeadArmyConfiguration { ... } @Configuration public class DragonIslandConfiguration { @Bean @ConditionalOn public DragonGlassFactory dragonGlassFactory() { return new DragonGlassFactory(); } ... }
OnProductionCondition.class
, β ). . , , , - . 5 ?@Component
, @Configuration
@Service
), . , . @Configuration @ConditionalOn public class UndeadArmyConfiguration { ... }
@Configuration public class DragonIslandConfiguration { @Bean @ConditionalOn public DragonGlassFactory dragonGlassFactory() { return new DragonGlassFactory(); } ... }
application.properties
application.yml
. , IDEA. @ConditionalOnBean @ConditionalOnClass @ConditionalOnCloudPlatform @ConditionalOnExpression @ConditionalOnJava @ConditionalOnJndi @ConditionalOnMissingBean @ConditionalOnMissingClass @ConditionalOnNotWebApplication @ConditionalOnProperty @ConditionalOnResource @ConditionalOnSingleCandidate @ConditionalOnWebApplication ...
@ConditionalOnProperty
. , , property property - , application.yml. @ConfigurationalProperty
, . @ConfigurationProperties("") public class RavenProperties { List<String> ; }
subproject { dependencies { compileOnly 'org.springframework.boot:spring-boot-configuration-processor' compile 'org.springframework.boot: spring-boot-starter' } }
@ConfigurationalProperties
, property, JSON. , , JSON .@EnableConfigurationProperties
, . @Configuration @EnableConfigurationProperties(RavenProperties.class) public class IronConfiguration { @Bean @ConditionalOnProduction public RavenListener ravenListener() { return new RavenListener(); } }
@EnableConfigurationProperties
, , ;@ConfigurationalProperties
, , . { "hints": [], "groups": [ { "sourceType": "com.ironbank.RavenProperties", "name": "", "type": "com.ironbankRavenProperties" } ], "properties": [ { "sourceType": "com.ironbank.RavenProperties", "name": ".", "type": "java.util.List<java.lang.String>" } ] }
@Configuration @EnableConfigurationProperties(RavenProperties.class) public class IronConfiguration { @Bean @ConditionalOnProduction @ConditionalOnProperty(".") public RavenListener ravenListener() { return new RavenListener(); } }
spring: application.name: money-raven jpa.hibernate.ddl-auto: validate ironbank: ---: - : -: , : true
@Autowired
, reflection. , Spring: @RequiredArgsConstructor public class RavenListener implements ApplicationListener<ContextRefreshedEvent>{ private final RavenProperties ravenProperties; @Override public void onApplicationEvent(ContextRefreshedEvent event) { ravenProperties.get().forEach(s -> { System.out.println(" β¦ " + s); }); } }
@Configuration @EnableConfigurationProperties(RavenProperties.class) public class IronConfiguration { @Bean @ConditionalOnProduction @ConditionalOnProperty(".") public RavenListener ravenListener(RavenProperties r) { return new RavenListener(r); } }
@Aurowired
, Spring 4.3 . , @Aurowired
. @RequiredArgsConstructor
, . : public class RavenListener implements ApplicationListener<ContextRefreshedEvent>{ private final RavenProperties ravenProperties; public RavenListener(RavenProperties ravenProperties) { this.ravenProperties = ravenProperties; } public void onApplicationEvent(ContextRefreshedEvent event) { ravenProperties.get().forEach(s -> { System.out.println(" β¦ " + s); }); } }
@Aurowired
, ( ). public class RavenListener implements ApplicationListener<ContextRefreshedEvent>{ private final RavenProperties ravenProperties; @Aurowired public RavenListener(RavenProperties ravenProperties) { this.ravenProperties = ravenProperties; } public void onApplicationEvent(ContextRefreshedEvent event) { ravenProperties.get().forEach(s -> { System.out.println(" β¦ " + s); }); } }
RavenProperties
Java-. @Aurowired
, . @ConditionalOnBean @ConditionalOnClass @ConditionalOnCloudPlatform @ConditionalOnExpression @ConditionalOnJava @ConditionalOnJndi @ConditionalOnMissingBean @ConditionalOnMissingClass @ConditionalOnNotWebApplication @ConditionalOnProperty @ConditionalOnResource @ConditionalOnSingleCandidate @ConditionalOnWebApplication ...
@ConditionalOnMissingBean
, . , , , . @Configuration @EnableConfigurationProperties(RavenProperties.class) public class IronConfiguration { @Bean @ConditionalOnProduction @ConditionalOnProperty(".") @ConditionalOnMissingBean</b> public RavenListener ravenListener(RavenProperties r) { return new RavenListener(r); } }
MyRavenListener
. @Component public class MyRavenListener implements ApplicationListener { public MyRavenListener(RavenProperties ravenProperties) { super(ravenProperties); } @Override public void onApplicationEvent(ContextRefreshedEvent event) { ravenProperties.get().forEach(s -> { System.out.println("event = " + event); }); } }
extends
- application listener, @ConditionalOnMissingBean
. But since , ravenListener
β . , Java- . , ravenListener
.@Bean
, dataSource @Bean
.@ConditionalOnClass
, @ConditionalOnMissingBean
, . . @Configuration public class { @Bean @ConditionalOnClass({.class, .class}) @ConditionalOnMissingBean({.class}) public () { return new ("..."); } @Bean @ConditionalOnClass({.class, .class}) @ConditionalOnMissingBean({.class}) public c() { return new (" "); } @Bean @ConditionalOnClass({.class, .class}) @ConditionalOnMissingBean({.class}) public () { return new (" "); } }
@ConditionalOnMissingClass
?ClassDefNotFound
.@Conditional
, . . ASM β , , . , , .OnMissingClass
, (String). , , ASM . , , .@ConditionalOnProperty(".")
. @Configuration @EnableConfigurationProperties(RavenProperties.class) public class IronConfiguration { @Bean @ConditionalOnProduction @ConditionalOnProperty(".") @ConditionalOnProperty(".") public RavenListener ravenListener(RavenProperties r) { return new RavenListener(r); } }
@Conditional(OnPropertyCondition.class) public @interface ConditionalOnProperty { String[] value() default {}; String prefix() default ""; String[] name() default {}; String havingValue() default ""; boolean matchIfMissing() default false; boolean relaxedNames() default true; }
, false
- property, string
. property . @ConditionalOnProduction @ConditionalOnProperty(name = ".", havingValue="true") @ConditionalOnProperty(name = ".", havingValue="true") @ConditionalOnProperty(name = ".",havingValue="false") public IronBankApplicationListener applicationListener() { ... }
@ConditionalOnProduction @ConditionalOnProperty( name = { ".", ".", "." }, havingValue = "true" ) public IronBankApplicationListener applicationListener() { ... }
AllNestedConditions
AnyNestedCondition
..
.
. @Configuration @EnableConfigurationProperties(RavenProperties.class) public class IronConfiguration { @Bean @ConditionalOnProduction @ConditionalOnProperty(".") @ConditionalOnRaven public RavenListener ravenListener(RavenProperties r) { return new RavenListener(r); } }
@Conditional()
- . @Retention(RUNTIME) @Conditional({OnRavenCondional.class}) public @interface CondionalOnRaven { }
public class OnRavenCondional implements Condition { }
public class CompositeCondition extends AllNestedConditions { @ConditionalOnProperty( name = ".", havingValue = "false") public static class OnRavenProperty { } @ConditionalOnProperty( name = ".enabled", havingValue = "true", matchIfMissing = true) public static class OnRavenEnabled { } ... }
Conditional
, β AllNestedConditions
, AnyNestedCondition
β , . Those. @Condition
: public class OnRavenCondional extends AllNestedConditions { public OnRavenCondional() { super(ConfigurationPhase.REGISTER_BEAN); } }
public class OnRavenCondional extends AllNestedConditions { public OnRavenCondional() { super(ConfigurationPhase.REGISTER_BEAN); } public static class R {} }
( true
). public class OnRavenCondional extends AllNestedConditions { public OnRavenCondional() { super(ConfigurationPhase.REGISTER_BEAN); } @ConditionalOnProperty(".") public static class R {} @ConditionalOnProperty(value= ".", havingValue = "true") public static class C {} }
@ConditionalOnRaven
. , @ConditionalOnProduction
, @ConditionalOnMissingBean
, . , . @Configuration @EnableConfigurationProperties(RavenProperties.class) public class IronConfiguration { @Bean @ConditionalOnProduction @ConditionalOnRaven @ConditionalOnMissingBean public RavenListener ravenListener(RavenProperties r) { return new RavenListener(r); } }
. .
, β . @Data @ConfigurationalProperties("") public class RavenProperties { List<String> ; boolean ; }
false
, true
jpa.hibernate.ddl-auto: validate ironbank: ---: - : : , : true
Source: https://habr.com/ru/post/424503/
All Articles