關(guān)于SpringBoot自定義條件注解與自動(dòng)配置
Spring Boot的核心功能就是為整合第三方框架提供自動(dòng)配置,而本文則帶著大家實(shí)現(xiàn)了自己的自動(dòng)配置和Starter,一旦真正掌握了本文的內(nèi)容,就會(huì)對(duì)Spring Boot產(chǎn)生“一覽眾山小”的感覺(jué)。
自定義條件注解
在SpringBoot中,所有自定義條件注解其實(shí)都是基于@Conditional而來(lái)的,使用@Conditional定義新條件注解關(guān)鍵就是要有一個(gè)Condition實(shí)現(xiàn)類(lèi),該Condition實(shí)現(xiàn)類(lèi)就負(fù)責(zé)條件注解的處理邏輯,該實(shí)現(xiàn)類(lèi)所實(shí)現(xiàn)的matches()方法決定了條件注解的要求是否得到滿(mǎn)足。
下面是自定義條件注解的Condition實(shí)現(xiàn)類(lèi)的代碼。
- src/main/java/com/example/_003configtest/condition/MyCondition.java
package com.example._003configtest.condition; import com.example._003configtest.annotation.ConditionalCustom; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotatedTypeMetadata; import java.util.Map; public class MyCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { //獲取@ConditionalCustom注解的全部屬性,其中ConditionalCustom是自定義的注解 Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(ConditionalCustom.class.getName()); //獲取注解的value屬性值 String[] vals = (String[]) annotationAttributes.get("value"); //env是application.properties或application.yml中配置的屬性 Environment env = context.getEnvironment(); //遍歷每個(gè)value的每個(gè)屬性值 for (String val : vals) { //如果某個(gè)屬性值對(duì)應(yīng)的配置屬性不存在,則返回false if(env.getProperty(val.toString())== null){ return false; } } return true; } }
從上面的邏輯可以看到,自定義條件注解的處理邏輯比較簡(jiǎn)單:就是要求value屬性所指定的所有配置屬性必須存在,至于這些配置屬性的值是什么無(wú)所謂,這些配置屬性是否有值也無(wú)所謂。
有了上面的Condition實(shí)現(xiàn)類(lèi)之后,接下來(lái)即可基于@Conditional來(lái)定義自定義條件注解。下面是自定義條件注解的代碼。
- src/main/java/com/example/_003configtest/annotation/ConditionalCustom.java
package com.example._003configtest.annotation; import com.example._003configtest.condition.MyCondition; import org.springframework.context.annotation.Conditional; import java.lang.annotation.*; @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented //只要通過(guò)@Conditional指定Condition實(shí)現(xiàn)類(lèi)即可,該Condition實(shí)現(xiàn)類(lèi)就會(huì)負(fù)責(zé)該條件注解的判斷邏輯 @Conditional(MyCondition.class) public @interface ConditionalCustom { String[] value() default {}; }
下面的配置類(lèi)示范了如何使用該自定義的條件注解:
- src/main/java/com/example/_003configtest/config/MyConfigTest.java
// proxyBeanMethods = true :單例模式,保證每個(gè)@Bean方法被調(diào)用多少次返回的組件都是同一個(gè) // proxyBeanMethods = false :原型模式,每個(gè)@Bean方法被調(diào)用多少次返回的組件都是新創(chuàng)建的 @Configuration(proxyBeanMethods = true) public class MyConfigTest { @Bean //只有當(dāng)applicaion.properties或application.yml中org.test1,org.test2兩個(gè)配置屬性都存在時(shí)才生效 @ConditionalCustom({"org.test1","org.test2"}) public MyBean myBean(){ return new MyBean(); } }
在application.properties文件中添加如下配置:
org.test1 = 1 org.test2 = 2
運(yùn)行測(cè)試發(fā)現(xiàn)成功獲得了容器中對(duì)應(yīng)的類(lèi):
自定義自動(dòng)配置
開(kāi)發(fā)自己的自動(dòng)配置很簡(jiǎn)單,其實(shí)也就兩步:
- 使用@Configuration和條件注解定義自動(dòng)配置類(lèi)。
- 在META-INF/spring.factories文件中注冊(cè)自動(dòng)配置類(lèi)。
為了清楚地演示Spring Boot自動(dòng)配置的效果,避免引入第三方框架導(dǎo)致的額外復(fù)雜度,本例先自行開(kāi)發(fā)一個(gè)funny框架,該框架的功能是用文件或數(shù)據(jù)庫(kù)保存程序的輸出信息。
新建一個(gè)Maven項(xiàng)目funny(注意不是用SpringInitializr創(chuàng)建項(xiàng)目),為該項(xiàng)目添加mysql-connector-java和slf4j-api兩個(gè)依賴(lài)。由于該項(xiàng)目是我們自己開(kāi)發(fā)的框架,因此無(wú)須為該項(xiàng)目添加任何Spring Boot依賴(lài)。下面是該項(xiàng)目的pom.xml文件代碼。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>funny</artifactId> <version>1.0-SNAPSHOT</version> <!-- 定義所使用的Java版本和源代碼使用的字符集--> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <!-- MySQL數(shù)據(jù)庫(kù)驅(qū)動(dòng)依賴(lài) --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.27</version> </dependency> <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.36</version> </dependency> </dependencies> </project>
接下來(lái)為這個(gè)框架項(xiàng)目開(kāi)發(fā)如下類(lèi)。
- src/main/java/io/WriterTemplate.java
package io; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.charset.Charset; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Objects; import javax.sql.DataSource; public class WriterTemplate { Logger log = LoggerFactory.getLogger(this.getClass()); private final DataSource dataSource; private Connection conn; private File dest; private final Charset charset; private RandomAccessFile raf; public WriterTemplate(DataSource dataSource) throws SQLException { this.dataSource = dataSource; this.dest = null; this.charset = null; if(Objects.nonNull(this.dataSource)){ log.debug("========獲取數(shù)據(jù)庫(kù)連接========"); this.conn = dataSource.getConnection(); } } public WriterTemplate(File dest,Charset charset) throws FileNotFoundException{ this.dest = dest; this.charset = charset; this.dataSource = null; this.raf = new RandomAccessFile(this.dest,"rw"); } public void write(String message) throws IOException,SQLException{ if(Objects.nonNull(this.conn)){ //查詢(xún)當(dāng)前數(shù)據(jù)庫(kù)的fnny_message表是否存在 ResultSet rs = conn.getMetaData().getTables(conn.getCatalog(),null,"funny_message",null); //如果funy_message表不存在,需要?jiǎng)?chuàng)建表 if(!rs.next()){ log.debug("~~~~~~~~~創(chuàng)建funny_message表~~~~~~~~~"); conn.createStatement().execute("create table funny_message " + "(id int primary key auto_increment,message_text text)"); } log.debug("~~~~~~~~~輸出到數(shù)據(jù)表~~~~~~~~~"); //往數(shù)據(jù)庫(kù)中插入數(shù)據(jù) conn.createStatement().executeUpdate("insert into " + "funny_message values(null,'" + message + "')"); rs.close(); } else{ log.debug("~~~~~~~~~輸出到文件~~~~~~~~~"); raf.seek(this.dest.length()); raf.write((message + "\n").getBytes(this.charset)); } } //關(guān)閉資源 public void close() throws SQLException,IOException{ if(this.conn != null){ this.conn.close(); } if(this.raf != null){ this.raf.close(); } } }
該工具類(lèi)根據(jù)是否傳入 DataSource 來(lái)決定輸出目標(biāo):如果為該工具類(lèi)傳入了DataSource,它就會(huì)向該數(shù)據(jù)源所連接的數(shù)據(jù)庫(kù)中的funny_message表輸出內(nèi)容(如果該表不存在,該工具類(lèi)將會(huì)自動(dòng)建表);如果沒(méi)有為該工具類(lèi)傳入DataSource,它就會(huì)向指定文件輸出內(nèi)容。
接下來(lái)使用install打包到maven倉(cāng)庫(kù):
有了該框架之后,接下來(lái)為該框架開(kāi)發(fā)自動(dòng)配置。如果為整合現(xiàn)有的第三方框架開(kāi)發(fā)自動(dòng)配置,則可直接從這一步開(kāi)始(因?yàn)榭蚣芤呀?jīng)存在了,直接為框架開(kāi)發(fā)自動(dòng)配置即可)。
同樣新建一個(gè)Maven項(xiàng)目funny-spring-boot-starter(為了方便可以用SpringInitializr創(chuàng)建項(xiàng)目),這個(gè)項(xiàng)目是自定義Starter項(xiàng)目,因此必須要有Spring Boot支持,將前面Spring Boot項(xiàng)目中的pom.xml文件復(fù)制過(guò)來(lái),保留其中的spring-boot-starter依賴(lài),并添加剛剛開(kāi)發(fā)的funny框架的依賴(lài)。此外,由于該項(xiàng)目不是Spring Boot應(yīng)用,因此不需要主類(lèi),也不需要運(yùn)行,故刪除其中的spring-boot-maven-plugin插件。修改后的pom.xml文件內(nèi)容如下。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>funny-spring-boot-starter</artifactId> <version>0.0.1-SNAPSHOT</version> <name>funny-spring-boot-starter</name> <description>funny-spring-boot-starter</description> <properties> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-boot.version>2.3.7.RELEASE</spring-boot.version> </properties> <dependencies> <!-- Spring Boot Starter依賴(lài)--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!-- 依賴(lài)自定義的funny框架,如果正在為其他第三方框架開(kāi)發(fā)自動(dòng)配置,則此處應(yīng)該填寫(xiě)被整合的第三方框架的坐標(biāo)。--> <dependency> <groupId>org.example</groupId> <artifactId>funny</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> </project>
接下來(lái)定義如下自動(dòng)配置類(lèi)。
- src/main/java/com/example/funnyspringbootstarter/autoconfig/FunnyAutoConfiguration.java
package com.example.funnyspringbootstarter.autoconfig; import io.WriterTemplate; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureOrder; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.sql.DataSource; import javax.xml.crypto.Data; import java.io.File; import java.io.FileNotFoundException; import java.nio.charset.Charset; import java.sql.SQLException; @Configuration //當(dāng)WriteTemplate類(lèi)存在時(shí)配置生效 @ConditionalOnClass(WriterTemplate.class) //FunnyProperties是自定義的類(lèi),后面會(huì)定義,這里表示啟動(dòng)FunnyProperties @EnableConfigurationProperties(FunnyProperties.class) //讓該自動(dòng)配置類(lèi)位于DataSourceAutoConfiguration自動(dòng)配置類(lèi)之后處理 @AutoConfigureAfter(DataSourceAutoConfiguration.class) public class FunnyAutoConfiguration { private final FunnyProperties properties; //FunnyProperties類(lèi)負(fù)責(zé)加載配置屬性 public FunnyAutoConfiguration(FunnyProperties properties) { this.properties = properties; } @Bean(destroyMethod = "close") //當(dāng)單例的DataSource Bean存在時(shí)配置生效 @ConditionalOnSingleCandidate(DataSource.class) //只有當(dāng)容器中沒(méi)有WriterTemplate Bean時(shí),該配置才會(huì)生效 @ConditionalOnMissingBean //通過(guò)@AutoConfigureOrder注解指定該配置方法比下一個(gè)配置WriterTemplate的方法的優(yōu)先級(jí)更高 @AutoConfigureOrder(99) public WriterTemplate writerTemplate(DataSource dataSource) throws SQLException{ return new WriterTemplate(dataSource); } @Bean(destroyMethod = "close") //只有當(dāng)前面的WriteTemplate配置沒(méi)有生效時(shí),該方法的配置才會(huì)生效 @ConditionalOnMissingBean @AutoConfigureOrder(199) public WriterTemplate writerTemplate2() throws FileNotFoundException{ File f = new File(this.properties.getDest()); Charset charset = Charset.forName(this.properties.getCharset()); return new WriterTemplate(f,charset); } }
在FunnyAutoConfiguration 自動(dòng)配置類(lèi)中定義了兩個(gè)@Bean方法,這兩個(gè)@Bean 方法都用于自動(dòng)配置 WriterTemplate。為了指定它們的優(yōu)先級(jí),程序使用了@AutoConfigureOrder 注解修飾它們,該注解指定的數(shù)值越小,優(yōu)先級(jí)越高。
FunnyAutoConfiguration 自動(dòng)配置類(lèi)中的@Bean 方法同樣使用了@ConditionalOnMissingBean`@ConditionalOnSingleCandidate等條件注解修飾,從而保證只有當(dāng)容器中不存在WriterTemplate時(shí),該自動(dòng)配置類(lèi)才會(huì)配置WriterTemplate Bean,且優(yōu)先配置基于DataSource的WriterTemplate。
上面的自動(dòng)配置類(lèi)還用到了FunnyProperties屬性處理類(lèi),該類(lèi)的代碼如下:
package com.example.funnyspringbootstarter.autoconfig; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties(prefix = FunnyProperties.FUNNY_PREFIX) public class FunnyProperties { public static final String FUNNY_PREFIX = "org.test"; private String dest; private String charset; public String getDest() { return dest; } public void setDest(String dest) { this.dest = dest; } public String getCharset() { return charset; } public void setCharset(String charset) { this.charset = charset; } }
上面的屬性處理類(lèi)負(fù)責(zé)處理以“org.test”開(kāi)頭的屬性,這個(gè)“org.test”是必要的,它相當(dāng)于這一組配置屬性的“命名空間”,通過(guò)這個(gè)命名空間可以將這些配置屬性與其他框架的配置屬性區(qū)分開(kāi)。
有了上面的自動(dòng)配置類(lèi)之后,接下來(lái)使用如下META-INF/spring.factories文件來(lái)注冊(cè)自動(dòng)配置類(lèi)。
- src/main/resources/META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration = \ com.example.funnyspringbootstarter.autoconfig.FunnyAutoConfiguration
經(jīng)過(guò)上面步驟,自動(dòng)配置開(kāi)發(fā)完成,接下來(lái)使用install打包到maven倉(cāng)庫(kù):
有了自定義的Starter之后,接下來(lái)使用該Starter與使用Spring Boot官方Starter并沒(méi)有任何區(qū)別。首先新建一個(gè)Maven項(xiàng)目myfunnytest,在pom文件中引入該starter:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>myfunnytest</artifactId> <version>0.0.1-SNAPSHOT</version> <name>myfunnytest</name> <description>myfunnytest</description> <properties> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-boot.version>2.3.7.RELEASE</spring-boot.version> </properties> <dependencies> <dependency> <groupId>com.example</groupId> <artifactId>funny-spring-boot-starter</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <!-- <dependency>--> <!-- <groupId>org.springframework.boot</groupId>--> <!-- <artifactId>spring-boot-starter</artifactId>--> <!-- </dependency>--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>2.3.7.RELEASE</version> <configuration> <mainClass>com.example.myfunnytest.MyfunnytestApplication</mainClass> </configuration> <executions> <execution> <id>repackage</id> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
由于 funny-spring-boot-starter 本身需要依賴(lài) spring-boot-starter,因此不再需要顯式配置依賴(lài)spring-boot-starter。
在添加了上面的funny-spring-boot-starter依賴(lài)之后,該Starter包含的自動(dòng)配置生效,它會(huì)嘗試在容器中自動(dòng)配置WriterTemplate,并且還會(huì)讀取application.properties因此還需要在application.properties文件中進(jìn)行配置。
- src/main/resources/application.properties
# 應(yīng)用名稱(chēng) spring.application.name=myfunnytest org.test.dest = F:/abc-12345.txt org.test.charset=UTF-8 spring.datasource.url=jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDateTimeCode=false&serverTimezone=GMT%2B8 spring.datasource.username=root spring.datasource.password=root
該示例的主類(lèi)很簡(jiǎn)單,它直接獲取容器中的WriterTemplate Bean,并調(diào)用該Bean的write()方法執(zhí)行輸出。下面是該主類(lèi)的代碼:
package com.example.myfunnytest; import io.WriterTemplate; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; @SpringBootApplication public class MyfunnytestApplication { public static void main(String[] args) throws Exception{ ConfigurableApplicationContext run = SpringApplication.run(MyfunnytestApplication.class, args); WriterTemplate writerTemplate = run.getBean(WriterTemplate.class); System.out.println(writerTemplate); writerTemplate.write("自動(dòng)配置"); } }
運(yùn)行該程序,由于當(dāng)前Spring容器中沒(méi)有DataSource Bean,因此FunnyAutoConfiguration將會(huì)自動(dòng)配置輸出到文件的WriterTemplate。因此,運(yùn)行該程序,可以看到程序向“f:/abc-12345.txt”文件(由前面的org.test.dest屬性配置)輸出內(nèi)容:
運(yùn)行結(jié)果如下:
如果在項(xiàng)目的pom.xml文件中通過(guò)如下配置來(lái)添加依賴(lài)。
<!-- Spring Boot JDBC Starter依賴(lài)--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency>
此時(shí)為項(xiàng)目添加了spring-boot-starter-jdbc依賴(lài),該依賴(lài)將會(huì)在容器中自動(dòng)配置一個(gè)DataSource Bean,這個(gè)自動(dòng)配置的DataSource Bean將導(dǎo)致FunnyAutoConfiguration會(huì)自動(dòng)配置輸出到數(shù)據(jù)庫(kù)的WriterTemplate。因此,運(yùn)行該程序,可以看到程序向數(shù)據(jù)庫(kù)名為springboot數(shù)據(jù)庫(kù)的funny_message表輸出內(nèi)容:
Spring Boot的核心功能就是為整合第三方框架提供自動(dòng)配置,而本文則帶著大家實(shí)現(xiàn)了自己的自動(dòng)配置和Starter,一旦真正掌握了本文的內(nèi)容,就會(huì)對(duì)Spring Boot產(chǎn)生“一覽眾山小”的感覺(jué)。
到此這篇關(guān)于關(guān)于SpringBoot自定義條件注解與自動(dòng)配置的文章就介紹到這了,更多相關(guān)SpringBoot自定義注解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在Spring boot的項(xiàng)目中使用Junit進(jìn)行單體測(cè)試
今天小編就為大家分享一篇關(guān)于spring boot使用Junit進(jìn)行測(cè)試,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-12-12詳解Java類(lèi)動(dòng)態(tài)加載和熱替換
本文主要介紹類(lèi)加載器、自定義類(lèi)加載器及類(lèi)的加載和卸載等內(nèi)容,并舉例介紹了Java類(lèi)的熱替換。2021-05-05關(guān)于SpringBoot的異?;貪L和事務(wù)的使用詳解
這篇文章主要介紹了關(guān)于SpringBoot的異常回滾和事務(wù)的使用詳解,Spring中 @Transactional 注解,默認(rèn)情況下,只對(duì)拋出的RuntimeException 異常,才會(huì)事務(wù)回滾,需要的朋友可以參考下2023-05-05SpringBoot自定義注解驗(yàn)證枚舉的實(shí)現(xiàn)
本文主要介紹了SpringBoot自定義注解驗(yàn)證枚舉的實(shí)現(xiàn),數(shù)據(jù)校驗(yàn),需要對(duì)枚舉類(lèi)型的數(shù)據(jù)傳參,進(jìn)行數(shù)據(jù)校驗(yàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-01-01Java獲取當(dāng)前時(shí)間的時(shí)間戳方法總結(jié)
Java中獲取時(shí)間戳的方式有很多種,下面這篇文章主要給大家介紹了關(guān)于Java獲取當(dāng)前時(shí)間的時(shí)間戳的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用java具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2024-06-06spring如何實(shí)現(xiàn)兩個(gè)xml配置文件間的互調(diào)
這篇文章主要介紹了spring如何實(shí)現(xiàn)兩個(gè)xml配置文件間的互調(diào),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11非常全面的Java?SpringBoot點(diǎn)贊功能實(shí)現(xiàn)
但是這些功能再項(xiàng)目中是高頻出現(xiàn)的,如果直接操作數(shù)據(jù)庫(kù)的話,對(duì)數(shù)據(jù)庫(kù)壓力太大。那遇到這個(gè)問(wèn)題怎么解決?這篇文章主要給大家介紹了關(guān)于Java?SpringBoot點(diǎn)贊功能實(shí)現(xiàn)?的相關(guān)資料,需要的朋友可以參考下2022-01-01