SpringBoot中四種常用的條件裝配技術(shù)詳解
Spring Boot提供了多種條件裝配技術(shù),允許開(kāi)發(fā)者根據(jù)不同條件動(dòng)態(tài)配置應(yīng)用程序,大大提高了應(yīng)用的靈活性,本文將介紹Spring Boot中四種常用的條件裝配技術(shù)。
一、@Conditional注解及派生注解
1. 基本原理
@Conditional
注解是Spring 4引入的核心條件裝配機(jī)制,它允許開(kāi)發(fā)者根據(jù)特定條件來(lái)決定是否創(chuàng)建某個(gè)Bean或啟用某個(gè)配置。
@Conditional
的基本工作原理是:當(dāng)Spring容器處理帶有@Conditional
注解的Bean定義時(shí),會(huì)先評(píng)估指定的條件是否滿足,只有當(dāng)條件滿足時(shí),才會(huì)創(chuàng)建Bean或應(yīng)用配置。
2. @Conditional基本用法
使用@Conditional
注解時(shí),需要指定一個(gè)實(shí)現(xiàn)了Condition
接口的條件類:
public interface Condition { boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata); }
自定義條件類示例:
public class LinuxCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Environment env = context.getEnvironment(); String os = env.getProperty("os.name"); return os != null && os.toLowerCase().contains("linux"); } } public class WindowsCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Environment env = context.getEnvironment(); String os = env.getProperty("os.name"); return os != null && os.toLowerCase().contains("windows"); } }
然后,使用這些條件類來(lái)決定Bean的創(chuàng)建:
@Configuration public class OperatingSystemConfig { @Bean @Conditional(LinuxCondition.class) public CommandService linuxCommandService() { return new LinuxCommandService(); } @Bean @Conditional(WindowsCondition.class) public CommandService windowsCommandService() { return new WindowsCommandService(); } }
上面的配置會(huì)根據(jù)運(yùn)行環(huán)境的操作系統(tǒng)類型,創(chuàng)建不同的CommandService
實(shí)現(xiàn)。
3. 常用派生注解
Spring Boot提供了一系列基于@Conditional
的派生注解,簡(jiǎn)化了常見(jiàn)條件判斷的配置:
@ConditionalOnClass/@ConditionalOnMissingClass
根據(jù)類路徑中是否存在特定類來(lái)決定配置:
@Configuration public class JpaConfig { @Bean @ConditionalOnClass(name = "javax.persistence.EntityManager") public LocalContainerEntityManagerFactoryBean entityManagerFactory() { // 只有當(dāng)類路徑中存在JPA相關(guān)類時(shí),才創(chuàng)建此Bean return new LocalContainerEntityManagerFactoryBean(); } @Bean @ConditionalOnMissingClass("javax.persistence.EntityManager") public JdbcTemplate jdbcTemplate() { // 當(dāng)類路徑中不存在JPA相關(guān)類時(shí),采用JdbcTemplate return new JdbcTemplate(); } }
@ConditionalOnBean/@ConditionalOnMissingBean
根據(jù)容器中是否存在特定Bean來(lái)決定配置:
@Configuration public class DataSourceConfig { @Bean @ConditionalOnMissingBean public DataSource defaultDataSource() { // 當(dāng)容器中沒(méi)有DataSource類型的Bean時(shí),創(chuàng)建默認(rèn)數(shù)據(jù)源 return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .build(); } @Bean @ConditionalOnBean(name = "customDataSourceProperties") public DataSource customDataSource(CustomDataSourceProperties properties) { // 當(dāng)存在名為customDataSourceProperties的Bean時(shí),創(chuàng)建自定義數(shù)據(jù)源 HikariDataSource dataSource = new HikariDataSource(); dataSource.setJdbcUrl(properties.getUrl()); dataSource.setUsername(properties.getUsername()); dataSource.setPassword(properties.getPassword()); return dataSource; } }
@ConditionalOnProperty
根據(jù)配置屬性的值來(lái)決定配置:
@Configuration public class CacheConfig { @Bean @ConditionalOnProperty(name = "cache.type", havingValue = "redis") public CacheManager redisCacheManager() { // 當(dāng)cache.type屬性值為redis時(shí),配置Redis緩存管理器 return new RedisCacheManager(); } @Bean @ConditionalOnProperty(name = "cache.type", havingValue = "ehcache") public CacheManager ehCacheManager() { // 當(dāng)cache.type屬性值為ehcache時(shí),配置EhCache緩存管理器 return new EhCacheCacheManager(); } @Bean @ConditionalOnProperty(name = "cache.enabled", havingValue = "false", matchIfMissing = true) public CacheManager noOpCacheManager() { // 當(dāng)cache.enabled為false或未設(shè)置時(shí),使用空操作緩存管理器 return new NoOpCacheManager(); } }
@ConditionalOnExpression
根據(jù)SpEL表達(dá)式的結(jié)果來(lái)決定配置:
@Configuration public class SecurityConfig { @Bean @ConditionalOnExpression("${security.enabled:true} and ${security.type:basic} == 'oauth2'") public SecurityFilterChain oauth2SecurityFilterChain(HttpSecurity http) throws Exception { // 當(dāng)security.enabled為true且security.type為oauth2時(shí)生效 return http .oauth2Login() .and() .build(); } @Bean @ConditionalOnExpression("${security.enabled:true} and ${security.type:basic} == 'basic'") public SecurityFilterChain basicSecurityFilterChain(HttpSecurity http) throws Exception { // 當(dāng)security.enabled為true且security.type為basic時(shí)生效 return http .httpBasic() .and() .build(); } }
@ConditionalOnWebApplication/@ConditionalOnNotWebApplication
根據(jù)應(yīng)用是否為Web應(yīng)用來(lái)決定配置:
@Configuration public class ServerConfig { @Bean @ConditionalOnWebApplication public ServletWebServerFactory servletWebServerFactory() { // 只有在Web應(yīng)用中才創(chuàng)建此Bean return new TomcatServletWebServerFactory(); } @Bean @ConditionalOnNotWebApplication public ApplicationRunner consoleRunner() { // 只有在非Web應(yīng)用中才創(chuàng)建此Bean return args -> System.out.println("Running as a console application"); } }
4. 實(shí)戰(zhàn)示例:構(gòu)建適應(yīng)不同緩存環(huán)境的應(yīng)用
下面通過(guò)一個(gè)實(shí)際例子,展示如何使用@Conditional
系列注解構(gòu)建一個(gè)能夠適應(yīng)不同緩存環(huán)境的應(yīng)用:
@Configuration public class FlexibleCacheConfiguration { @Bean @ConditionalOnClass(name = "org.springframework.data.redis.core.RedisTemplate") @ConditionalOnProperty(name = "cache.type", havingValue = "redis") @ConditionalOnMissingBean(CacheManager.class) public CacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) { RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(redisConnectionFactory); return builder.build(); } @Bean @ConditionalOnClass(name = "org.ehcache.jsr107.EhcacheCachingProvider") @ConditionalOnProperty(name = "cache.type", havingValue = "ehcache") @ConditionalOnMissingBean(CacheManager.class) public CacheManager ehCacheCacheManager() { return new JCacheCacheManager(getJCacheCacheManager()); } @Bean @ConditionalOnProperty( name = "cache.type", havingValue = "simple", matchIfMissing = true ) @ConditionalOnMissingBean(CacheManager.class) public CacheManager simpleCacheManager() { SimpleCacheManager cacheManager = new SimpleCacheManager(); cacheManager.setCaches(Arrays.asList( new ConcurrentMapCache("users"), new ConcurrentMapCache("transactions"), new ConcurrentMapCache("products") )); return cacheManager; } @Bean @ConditionalOnProperty(name = "cache.enabled", havingValue = "false") @ConditionalOnMissingBean(CacheManager.class) public CacheManager noOpCacheManager() { return new NoOpCacheManager(); } private javax.cache.CacheManager getJCacheCacheManager() { // 創(chuàng)建JCache CacheManager的邏輯... return null; // 實(shí)際代碼需要返回真實(shí)的CacheManager } }
在上面的配置中:
- 如果類路徑中有Redis相關(guān)類,且配置了
cache.type=redis
,則使用Redis緩存 - 如果類路徑中有EhCache相關(guān)類,且配置了
cache.type=ehcache
,則使用EhCache - 如果配置了
cache.type=simple
或未指定類型,則使用簡(jiǎn)單的內(nèi)存緩存 - 如果配置了
cache.enabled=false
,則使用不執(zhí)行任何緩存操作的NoOpCacheManager
5. 優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn):
- 靈活強(qiáng)大,能適應(yīng)幾乎所有條件判斷場(chǎng)景
- 與Spring生態(tài)系統(tǒng)無(wú)縫集成
- 派生注解簡(jiǎn)化了常見(jiàn)場(chǎng)景的配置
- 條件判斷邏輯與業(yè)務(wù)邏輯分離,保持代碼清晰
缺點(diǎn):
- 復(fù)雜條件可能導(dǎo)致配置難以理解和調(diào)試
- 條件裝配的順序可能影響最終的Bean定義
二、Profile條件配置
1. 基本原理
Profile是Spring提供的另一種條件裝配機(jī)制,主要用于按環(huán)境(如開(kāi)發(fā)、測(cè)試、生產(chǎn))管理Bean的創(chuàng)建。與@Conditional
相比,Profile更專注于環(huán)境區(qū)分,配置更簡(jiǎn)單。
2. @Profile注解用法
使用@Profile
注解標(biāo)記Bean或配置類,指定它們?cè)谀男㏄rofile激活時(shí)才會(huì)被創(chuàng)建:
@Configuration public class DataSourceConfig { @Bean @Profile("development") public DataSource developmentDataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .build(); } @Bean @Profile("production") public DataSource productionDataSource() { HikariDataSource dataSource = new HikariDataSource(); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/proddb"); dataSource.setUsername("produser"); dataSource.setPassword("prodpass"); return dataSource; } }
也可以在配置類級(jí)別應(yīng)用@Profile
注解,控制整個(gè)配置類的激活:
@Configuration @Profile("development") public class DevelopmentConfig { // 開(kāi)發(fā)環(huán)境特有的Bean定義... } @Configuration @Profile("production") public class ProductionConfig { // 生產(chǎn)環(huán)境特有的Bean定義... }
3. 激活Profile的方式
有多種方式可以激活指定的Profile:
通過(guò)配置文件
在application.properties
或application.yml
中:
# application.properties spring.profiles.active=development
或
# application.yml spring: profiles: active: development
通過(guò)命令行參數(shù)
java -jar myapp.jar --spring.profiles.active=production
通過(guò)環(huán)境變量
export SPRING_PROFILES_ACTIVE=production java -jar myapp.jar
通過(guò)代碼激活
@SpringBootApplication public class MyApplication { public static void main(String[] args) { SpringApplication app = new SpringApplication(MyApplication.class); app.setAdditionalProfiles("production"); app.run(args); } }
4. Profile組合與否定
Spring Boot 2.4及以上版本提供了更靈活的Profile表達(dá)式:
使用Profile組
# application.properties spring.profiles.group.production=proddb,prodmq spring.profiles.group.development=devdb,devmq
上面的配置定義了兩個(gè)Profile組:當(dāng)激活"production"時(shí),會(huì)同時(shí)激活"proddb"和"prodmq";當(dāng)激活"development"時(shí),會(huì)同時(shí)激活"devdb"和"devmq"。
使用否定表達(dá)式
@Bean @Profile("!development") public MonitoringService productionMonitoringService() { return new DetailedMonitoringService(); }
上面的配置表示,除了"development"之外的所有Profile都會(huì)創(chuàng)建這個(gè)Bean。
5. 實(shí)戰(zhàn)示例:基于Profile的消息隊(duì)列配置
下面通過(guò)一個(gè)實(shí)際例子,展示如何使用Profile來(lái)配置不同環(huán)境的消息隊(duì)列連接:
@Configuration public class MessagingConfig { @Bean @Profile("local") public ConnectionFactory localConnectionFactory() { // 本地開(kāi)發(fā)使用內(nèi)嵌的ActiveMQ return new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false"); } @Bean @Profile("dev") public ConnectionFactory devConnectionFactory() { // 開(kāi)發(fā)環(huán)境使用開(kāi)發(fā)服務(wù)器上的RabbitMQ CachingConnectionFactory connectionFactory = new CachingConnectionFactory(); connectionFactory.setHost("dev-rabbitmq.example.com"); connectionFactory.setUsername("dev_user"); connectionFactory.setPassword("dev_pass"); return connectionFactory; } @Bean @Profile("prod") public ConnectionFactory prodConnectionFactory() { // 生產(chǎn)環(huán)境使用生產(chǎn)級(jí)RabbitMQ集群 CachingConnectionFactory connectionFactory = new CachingConnectionFactory(); connectionFactory.setAddresses("prod-rabbitmq-1.example.com,prod-rabbitmq-2.example.com"); connectionFactory.setUsername("prod_user"); connectionFactory.setPassword("prod_pass"); // 生產(chǎn)環(huán)境增加額外配置 connectionFactory.setPublisherConfirms(true); connectionFactory.setPublisherReturns(true); return connectionFactory; } @Bean public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) { // 通用的RabbitTemplate配置,使用當(dāng)前Profile對(duì)應(yīng)的ConnectionFactory return new RabbitTemplate(connectionFactory); } }
結(jié)合特定環(huán)境的配置文件:
# application-local.yml spring: rabbitmq: listener: simple: concurrency: 1 max-concurrency: 5 # application-dev.yml spring: rabbitmq: listener: simple: concurrency: 5 max-concurrency: 10 # application-prod.yml spring: rabbitmq: listener: simple: concurrency: 10 max-concurrency: 50 retry: enabled: true initial-interval: 5000 max-attempts: 3
6. 優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn):
- 使用簡(jiǎn)單直觀,專門為環(huán)境區(qū)分設(shè)計(jì)
- 與Spring Boot配置系統(tǒng)完美集成
- 支持組合和否定表達(dá)式,增強(qiáng)表達(dá)能力
- 可以通過(guò)多種方式切換Profile,適應(yīng)不同部署場(chǎng)景
缺點(diǎn):
- 表達(dá)能力有限,不如
@Conditional
注解靈活 - 主要基于預(yù)定義的命名環(huán)境,處理動(dòng)態(tài)條件能力較弱
三、自動(dòng)配置條件
1. 基本原理
自動(dòng)配置是Spring Boot的核心特性之一,它允許框架根據(jù)類路徑、已有Bean和配置屬性等條件,自動(dòng)配置應(yīng)用程序。自動(dòng)配置條件是實(shí)現(xiàn)這一功能的基礎(chǔ),它通過(guò)組合使用多種條件注解,實(shí)現(xiàn)復(fù)雜的條件判斷邏輯。
2. 常用自動(dòng)配置條件組合
在Spring Boot的自動(dòng)配置類中,經(jīng)??梢钥吹蕉喾N條件注解的組合使用:
@Configuration @ConditionalOnClass(DataSource.class) @ConditionalOnMissingBean(DataSource.class) @ConditionalOnProperty(prefix = "spring.datasource", name = "enabled", matchIfMissing = true) public class DataSourceAutoConfiguration { // 數(shù)據(jù)源自動(dòng)配置... }
上面的配置表示:
- 只有當(dāng)類路徑中存在
DataSource
類 - 且容器中沒(méi)有
DataSource
類型的Bean - 且
spring.datasource.enabled
屬性不存在或?yàn)閠rue時(shí) - 才會(huì)啟用這個(gè)自動(dòng)配置類
3. 自定義自動(dòng)配置類
開(kāi)發(fā)者可以創(chuàng)建自己的自動(dòng)配置類,使用條件注解控制其激活條件:
@Configuration @ConditionalOnClass(RedisTemplate.class) @ConditionalOnMissingBean(CacheManager.class) @ConditionalOnProperty(prefix = "mycache", name = "type", havingValue = "redis") @EnableConfigurationProperties(MyCacheProperties.class) public class RedisCacheAutoConfiguration { @Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory, MyCacheProperties properties) { RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(redisConnectionFactory); if (properties.getExpireTime() > 0) { builder.cacheDefaults(RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofSeconds(properties.getExpireTime()))); } return builder.build(); } }
配置屬性類:
@ConfigurationProperties(prefix = "mycache") public class MyCacheProperties { private String type; private int expireTime = 3600; // getters and setters }
4. 啟用自動(dòng)配置
要啟用自定義的自動(dòng)配置類,需要?jiǎng)?chuàng)建META-INF/spring.factories
文件:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.config.RedisCacheAutoConfiguration
或者在Spring Boot 2.7及以上版本,可以使用META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
文件:
com.example.config.RedisCacheAutoConfiguration
5. 自動(dòng)配置順序控制
在復(fù)雜系統(tǒng)中,可能需要控制自動(dòng)配置類的加載順序,這可以通過(guò)@AutoConfigureBefore
、@AutoConfigureAfter
和@AutoConfigureOrder
注解實(shí)現(xiàn):
@Configuration @ConditionalOnClass(DataSource.class) @AutoConfigureAfter(DataSourceAutoConfiguration.class) public class JdbcTemplateAutoConfiguration { // JDBC模板自動(dòng)配置,確保在數(shù)據(jù)源配置之后 } @Configuration @ConditionalOnClass(SecurityFilterChain.class) @AutoConfigureBefore(WebMvcAutoConfiguration.class) public class SecurityAutoConfiguration { // 安全配置應(yīng)該在Web MVC配置之前 } @Configuration @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) public class EarlyInitAutoConfiguration { // 需要最先初始化的配置 }
6. 實(shí)戰(zhàn)示例:自定義監(jiān)控系統(tǒng)自動(dòng)配置
下面通過(guò)一個(gè)實(shí)際例子,展示如何使用自動(dòng)配置條件創(chuàng)建一個(gè)可插拔的應(yīng)用監(jiān)控組件:
// 配置屬性類 @ConfigurationProperties(prefix = "app.monitoring") public class MonitoringProperties { private boolean enabled = true; private String type = "jmx"; private int sampleRate = 10; private boolean logMetrics = false; // getters and setters } // JMX監(jiān)控自動(dòng)配置 @Configuration @ConditionalOnProperty(prefix = "app.monitoring", name = "enabled", havingValue = "true", matchIfMissing = true) @ConditionalOnProperty(prefix = "app.monitoring", name = "type", havingValue = "jmx", matchIfMissing = true) @ConditionalOnClass(name = "javax.management.MBeanServer") @EnableConfigurationProperties(MonitoringProperties.class) public class JmxMonitoringAutoConfiguration { @Bean @ConditionalOnMissingBean public MetricsCollector metricsCollector(MonitoringProperties properties) { JmxMetricsCollector collector = new JmxMetricsCollector(); collector.setSampleRate(properties.getSampleRate()); return collector; } @Bean @ConditionalOnMissingBean public MetricsExporter metricsExporter(MonitoringProperties properties) { JmxMetricsExporter exporter = new JmxMetricsExporter(); exporter.setLogMetrics(properties.isLogMetrics()); return exporter; } } // Prometheus監(jiān)控自動(dòng)配置 @Configuration @ConditionalOnProperty(prefix = "app.monitoring", name = "enabled", havingValue = "true") @ConditionalOnProperty(prefix = "app.monitoring", name = "type", havingValue = "prometheus") @ConditionalOnClass(name = "io.prometheus.client.CollectorRegistry") @EnableConfigurationProperties(MonitoringProperties.class) public class PrometheusMonitoringAutoConfiguration { @Bean @ConditionalOnMissingBean public MetricsCollector metricsCollector(MonitoringProperties properties) { PrometheusMetricsCollector collector = new PrometheusMetricsCollector(); collector.setSampleRate(properties.getSampleRate()); return collector; } @Bean @ConditionalOnMissingBean public MetricsExporter metricsExporter(MonitoringProperties properties) { PrometheusMetricsExporter exporter = new PrometheusMetricsExporter(); exporter.setLogMetrics(properties.isLogMetrics()); return exporter; } @Bean public CollectorRegistry collectorRegistry() { return new CollectorRegistry(true); } @Bean public HttpHandler prometheusEndpoint(CollectorRegistry registry) { return new PrometheusHttpHandler(registry); } } // 日志監(jiān)控自動(dòng)配置 @Configuration @ConditionalOnProperty(prefix = "app.monitoring", name = "enabled", havingValue = "true") @ConditionalOnProperty(prefix = "app.monitoring", name = "type", havingValue = "log") @EnableConfigurationProperties(MonitoringProperties.class) public class LogMonitoringAutoConfiguration { @Bean @ConditionalOnMissingBean public MetricsCollector metricsCollector(MonitoringProperties properties) { LogMetricsCollector collector = new LogMetricsCollector(); collector.setSampleRate(properties.getSampleRate()); return collector; } @Bean @ConditionalOnMissingBean public MetricsExporter metricsExporter() { return new LogMetricsExporter(); } }
META-INF/spring.factories文件:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.monitoring.JmxMonitoringAutoConfiguration,\ com.example.monitoring.PrometheusMonitoringAutoConfiguration,\ com.example.monitoring.LogMonitoringAutoConfiguration
使用示例:
# 使用JMX監(jiān)控(默認(rèn)) app: monitoring: enabled: true type: jmx sample-rate: 5 log-metrics: true # 或使用Prometheus監(jiān)控 app: monitoring: enabled: true type: prometheus sample-rate: 10 # 或使用日志監(jiān)控 app: monitoring: enabled: true type: log sample-rate: 30 # 或完全禁用監(jiān)控 app: monitoring: enabled: false
7. 優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn):
- 實(shí)現(xiàn)真正的"約定優(yōu)于配置"原則
- 可以創(chuàng)建可插拔的組件,極大提高代碼復(fù)用性
- 與Spring Boot生態(tài)系統(tǒng)無(wú)縫集成
缺點(diǎn):
- 學(xué)習(xí)曲線陡峭,需要了解多種條件注解的組合使用
- 自動(dòng)配置類過(guò)多可能導(dǎo)致應(yīng)用啟動(dòng)時(shí)間增加
- 調(diào)試?yán)щy,排查問(wèn)題需要深入了解Spring Boot啟動(dòng)機(jī)制
八、總結(jié)
條件裝配技術(shù) | 核心特點(diǎn) | 主要應(yīng)用場(chǎng)景 | 復(fù)雜度 |
---|---|---|---|
@Conditional及派生注解 | 最靈活,支持自定義條件 | 需要復(fù)雜條件判斷的場(chǎng)景 | 中 |
Profile條件配置 | 專注于環(huán)境區(qū)分 | 多環(huán)境部署,環(huán)境特定配置 | 低 |
自動(dòng)配置條件 | 組合多種條件,實(shí)現(xiàn)自動(dòng)配置 | 可插拔組件,框架開(kāi)發(fā) | 高 |
通過(guò)合理利用Spring Boot提供的條件裝配技術(shù),開(kāi)發(fā)者可以構(gòu)建出靈活、可配置的應(yīng)用程序,滿足不同環(huán)境和業(yè)務(wù)場(chǎng)景的需求。
到此這篇關(guān)于SpringBoot中四種常用的條件裝配技術(shù)詳解的文章就介紹到這了,更多相關(guān)SpringBoot條件裝配技術(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java Gradle項(xiàng)目中的資源正確獲取方式
這篇文章主要介紹了Java Gradle項(xiàng)目中的資源正確獲取方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11詳解Java Callable接口實(shí)現(xiàn)多線程的方式
這篇文章主要介紹了詳解Java Callable接口實(shí)現(xiàn)多線程的方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04Springboot整合SpringSecurity實(shí)現(xiàn)登錄認(rèn)證和鑒權(quán)全過(guò)程
這篇文章主要介紹了Springboot整合SpringSecurity實(shí)現(xiàn)登錄認(rèn)證和鑒權(quán)全過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12詳解Java的Hibernate框架中的Interceptor和Collection
這篇文章主要介紹了Java的Hibernate框架中的Interceptor和Collection,Hibernate是Java的SSH三大web開(kāi)發(fā)框架之一,需要的朋友可以參考下2016-01-01Springboot傳輸數(shù)據(jù)時(shí)日期格式化問(wèn)題
這篇文章主要介紹了Springboot傳輸數(shù)據(jù)時(shí)日期格式化問(wèn)題,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09Springboot實(shí)現(xiàn)動(dòng)態(tài)定時(shí)任務(wù)流程詳解
通過(guò)重寫(xiě)SchedulingConfigurer方法實(shí)現(xiàn)對(duì)定時(shí)任務(wù)的操作,單次執(zhí)行、停止、啟動(dòng)三個(gè)主要的基本功能,動(dòng)態(tài)的從數(shù)據(jù)庫(kù)中獲取配置的定時(shí)任務(wù)cron信息,通過(guò)反射的方式靈活定位到具體的類與方法中2022-09-09代理角色java設(shè)計(jì)模式之靜態(tài)代理詳細(xì)介紹
查了好多資料,發(fā)現(xiàn)還是不全,干脆自己整理吧,至少保證在我的做法正確的,以免誤導(dǎo)讀者,也是給自己做個(gè)記錄吧!2013-05-05java對(duì)接微信支付SDK接口簡(jiǎn)單圖文教程
在微信支付接口對(duì)接過(guò)程中,開(kāi)發(fā)者需準(zhǔn)備多項(xiàng)關(guān)鍵參數(shù),如開(kāi)發(fā)者ID(appid)、商戶號(hào)等,并完成相關(guān)注冊(cè)與認(rèn)證流程,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2024-11-11