предисловие
После того, как была опубликована предыдущая статья «Эти методы, которые могут сублимировать код весной, могут заставить вас влюбиться в него», она была хорошо принята многими читателями, и многие читатели с нетерпением ждут продолжения. Я очень рад сообщить вам сегодня, что продолжение, которое вы хотите, грядет. Эта статья продолжает обобщать знания, которые я считаю полезными весной, и я надеюсь помочь вам.
1. Сила @Conditional
Я не знаю, сталкивались ли вы с этими проблемами:
- Функция должна определить, включать ли функцию в зависимости от того, есть ли в проекте jar.
- Создание экземпляра компонента должно сначала определить, создается ли экземпляр другого компонента, а затем определить, следует ли создавать экземпляр самого себя.
- Независимо от того, включена ли функция, в файле конфигурации есть параметр для управления ею.
Если вы столкнулись с какой-либо из вышеперечисленных проблем, поздравляем, этот раздел для вас.
@ConditionalOnClass
Вопрос 1 можно использовать с @ConditionalOnClass
Аннотация решена, код такой:
public class A {
}
public class B {
}
@ConditionalOnClass(B.class)
@Configuration
public class TestConfiguration {
@Bean
public A a() {
return new A();
}
}
Если в проекте существует класс B, будет создан экземпляр класса A. Если класс B не существует, класс A не будет создан.
Некоторые люди могут спросить: Разве это не оценка того, есть ли определенная банка? Как теперь судить класс?
Недавно я случайно получил заметку о чистке, написанную крупным производителем BAT, которая открыла мне сразу вторую линейку Ren и Du, и я все больше чувствую, что алгоритм не так сложен, как я себе представлял.Заметки о чистке, написанные боссом BAT, позвольте мне мягко получить предложение
Проще напрямую судить о том, есть ли под банкой ключевой класс.
Эта аннотация имеет модернизированный сценарий применения: например, инструмент класса mqTemplate для отправки сообщений написан в общем проекте, а бизнес-проект ссылается на общий проект. можно открыть Особенности. А если есть другой бизнес-проект, то обычно ссылаются на общий проект.Если не требуется функция отправки сообщений, то и jar-пакет RocketMQ не требуется.
Эта функция аннотации весьма полезна, верно?
@ConditionalOnBean
2 вопрос можно пропустить@ConditionalOnBean
Аннотация решена, код такой:
@Configuration
public class TestConfiguration {
@Bean
public B b() {
return new B();
}
@ConditionalOnBean(name="b")
@Bean
public A a() {
return new A();
}
}
Экземпляр A может быть создан только в том случае, если существует экземпляр B.
@ConditionalOnProperty
Вопрос 3 можно пропустить@ConditionalOnProperty
Аннотация решена, код такой:
@ConditionalOnProperty(prefix = "demo",name="enable", havingValue = "true",matchIfMissing=true )
@Configuration
public class TestConfiguration {
@Bean
public A a() {
return new A();
}
}
существуетapplicationContext.properties
Параметры конфигурации в файле:
demo.enable=false
Значение каждого параметра:
- префикс указывает префикс имени параметра, вот демо
- имя указывает имя параметра
- haveValue указывает указанное значение. Значение, указанное в параметре, необходимо сравнить с указанным значением, чтобы оно было равно для выполнения условия.
- matchIfMissing указывает, разрешать ли конфигурацию по умолчанию.
Эта функция может использоваться как переключатель, по сравнению сEnableXXX
Переключатель аннотации более элегантен, потому что его можно включить через настройку параметров, аEnableXXX
Переключатели аннотаций должны быть жестко запрограммированы в коде, чтобы включить или отключить их.
Другие условные аннотации
Конечно,spring
использовать большеConditional
Также есть аннотации: ConditionalOnMissingClass, ConditionalOnMissingBean, ConditionalOnWebApplication и т.д.
Давайте воспользуемся картинкой, чтобы понять семейство @Conditional в целом.
Пользовательское условное
Честно говоря, лично я думаюspringboot
СвояConditional
Серия уже может удовлетворить большинство наших потребностей. Но если у вас есть более особенная сцена, вы также можете настроить пользовательское условие.
Первый шаг — настроить аннотацию:
@Conditional(MyCondition.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
public @interface MyConditionOnProperty {
String name() default "";
String havingValue() default "";
}
Второй шаг – осознатьCondition
интерфейс:
public class MyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
System.out.println("实现自定义逻辑");
return false;
}
}
Третий шаг — использовать аннотацию @MyConditionOnProperty.
Conditional
Секрет скрыт вConfigurationClassParser
КатегорияprocessConfigurationClass
В методе:
Логика этого метода не сложна:
-
Сначала определите, используется ли условная аннотация, а если нет, верните false напрямую.
-
Собрать условия в коллекцию
-
Сортировать коллекцию по порядку
-
Пройдитесь по коллекции и вызовите метод match условия в цикле.
2. Как использовать @Import?
Иногда нам нужно ввести другие классы в класс конфигурации, и импортированные классы также добавляются вspring
в контейнере. В это время вы можете использовать@Import
Аннотация завершает эту функцию.
Если вы посмотрите на его исходный код, вы обнаружите, что импортированные классы поддерживают три различных типа.
Но я думаю, что лучше совместить нормальный класс и@Configuration
Классы конфигурации аннотаций объясняются отдельно, поэтому перечислены четыре разных типа:
общий класс
Этот метод импорта является самым простым, и экземпляр импортируемого класса будет создан объектом bean-компонента.
public class A {
}
@Import(A.class)
@Configuration
public class TestConfiguration {
}
пройти через@Import
Аннотация вводит класс A, Spring может автоматически создавать экземпляр объекта A, а затем передавать его там, где его нужно использовать.@Autowired
Аннотация может быть введена:
@Autowired
private A a;
Разве это не удивительно? нет необходимости добавлять@Bean
Аннотации также могут создавать экземпляры bean-компонентов.
Класс конфигурации с аннотацией @Configuration
Этот способ введения является наиболее сложным, т.к.@Configuration
Аннотации также поддерживают различные комбинированные аннотации, такие как:
- @Import
- @ImportResource
- @PropertySource и т. д.
public class A {
}
public class B {
}
@Import(B.class)
@Configuration
public class AConfiguration {
@Bean
public A a() {
return new A();
}
}
@Import(AConfiguration.class)
@Configuration
public class TestConfiguration {
}
пройти через@Import
Импорт аннотаций@Configuration
Класс конфигурации аннотации будет связан с классом конфигурации@Import
,@ImportResource
,@PropertySource
Классы, введенные аннотациями, вводятся рекурсивно, и все они вводятся одновременно.
Из-за ограниченного объема статьи я не буду вводить слишком много, здесь немного ожидания, а статья будет представлена позже.@Configuration
Аннотация, потому что это действительно слишком важно.
Класс, реализующий интерфейс ImportSelector.
Этот способ введения требуетImportSelector
интерфейс:
public class AImportSelector implements ImportSelector {
private static final String CLASS_NAME = "com.sue.cache.service.test13.A";
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{CLASS_NAME};
}
}
@Import(AImportSelector.class)
@Configuration
public class TestConfiguration {
}
Преимущество этого подхода в том, чтоselectImports
Метод возвращает массив, а значит, можно одновременно ввести несколько классов, что очень удобно.
Класс, реализующий интерфейс ImportBeanDefinitionRegistrar.
Этот способ введения требуетImportBeanDefinitionRegistrar
интерфейс:
public class AImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(A.class);
registry.registerBeanDefinition("a", rootBeanDefinition);
}
}
@Import(AImportBeanDefinitionRegistrar.class)
@Configuration
public class TestConfiguration {
}
Этот метод является наиболее гибким и может использоваться вregisterBeanDefinitions
полученный методомBeanDefinitionRegistry
Объект регистрации контейнера, которым можно управлять вручнуюBeanDefinition
создание и регистрация.
Конечно@import
Аннотации очень удобны для пользователя, а также поддерживают одновременное введение множества различных типов классов.
@Import({B.class,AImportBeanDefinitionRegistrar.class})
@Configuration
public class TestConfiguration {
}
Эти четыре способа введения классов имеют свои достоинства, которые можно резюмировать следующим образом:
- Общий класс для создания экземпляров компонентов без особых требований.
- Класс конфигурации с аннотацией @Configuration используется для сценариев, представленных слоями вложенности.
- Класс, реализующий интерфейс ImportSelector, используется для сценариев, в которых несколько классов вводятся одновременно, или сценариев, в которых можно импортировать разные классы в соответствии с разными конфигурациями.
- Класс, реализующий интерфейс ImportBeanDefinitionRegistrar, в основном используется в сценариях, где созданием и регистрацией BeanDefinitions можно управлять вручную, его методы могут получать объект-контейнер регистрации BeanDefinitionRegistry.
существуетConfigurationClassParser
КатегорияprocessImports
Логику обработки этих трех методов можно увидеть в методе:
Последний метод else фактически включает в себя две разные логики обработки: обычные классы и аннотированные классы конфигурации @Configuration.
3. Назначение @ConfigurationProperties
Мы часто используем параметры конфигурации в проекте.Например, когда мы настраиваем пул потоков, нам нужноapplicationContext.propeties
В файле определена следующая конфигурация:
thread.pool.corePoolSize=5
thread.pool.maxPoolSize=10
thread.pool.queueCapacity=200
thread.pool.keepAliveSeconds=30
Способ 1: пройти@Value
Аннотации читают эти конфигурации.
public class ThreadPoolConfig {
@Value("${thread.pool.corePoolSize:5}")
private int corePoolSize;
@Value("${thread.pool.maxPoolSize:10}")
private int maxPoolSize;
@Value("${thread.pool.queueCapacity:200}")
private int queueCapacity;
@Value("${thread.pool.keepAliveSeconds:30}")
private int keepAliveSeconds;
@Value("${thread.pool.threadNamePrefix:ASYNC_}")
private String threadNamePrefix;
@Bean
public Executor threadPoolExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds(keepAliveSeconds);
executor.setThreadNamePrefix(threadNamePrefix);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
Этот метод очень прост в использовании, но рекомендуется добавить:
,так как:
За которым следует значение по умолчанию, например: @Value("${thread.pool.corePoolSize:5}"), количество определенных основных потоков по умолчанию равно 5.
Предположим, есть такой сценарий: класс ThreadPoolConfig определен под бизнес-проектом, проект API ссылается на бизнес-проект, проект задания также ссылается на бизнес-проект, а класс ThreadPoolConfig используется только в проекте API. В настоящее время, если значение по умолчанию не настроено, при запуске проекта задания может быть сообщено об ошибке.
Если параметров меньше, то нормально, а если слишком много параметров, то надо к каждому параметру добавлять аннотацию @Value, немного хлопотно?
Кроме того, есть проблема, параметры, определенные аннотацией @Value, выглядят немного разбросанными, и бывает непросто различить, какие параметры являются группой.
В это время пригодится @ConfigurationProperties, это новая аннотация, добавленная в springboot.
Первым шагом является определение класса ThreadPoolProperties.
@Data @Component @ConfigurationProperties("thread.pool") public class ThreadPoolProperties {
private int corePoolSize;
private int maxPoolSize;
private int queueCapacity;
private int keepAliveSeconds;
private String threadNamePrefix;
} Второй шаг, используйте класс ThreadPoolProperties
@Configuration public class ThreadPoolConfig {
@Autowired
private ThreadPoolProperties threadPoolProperties;
@Bean
public Executor threadPoolExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(threadPoolProperties.getCorePoolSize());
executor.setMaxPoolSize(threadPoolProperties.getMaxPoolSize());
executor.setQueueCapacity(threadPoolProperties.getQueueCapacity());
executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds());
executor.setThreadNamePrefix(threadPoolProperties.getThreadNamePrefix());
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
использовать@ConfigurationProperties
обратите внимание, вы можетеthread.pool
Параметры в начале напрямую назначаютсяThreadPoolProperties
одноименный параметр класса, это устраняет необходимость в чем-то вроде@Value
Аннотируйте такой ручной процесс, чтобы соответствовать один за другим.
Этот способ явно намного удобнее, нужно только написатьxxxProperties
class, spring автоматически подключит параметры. Кроме того, разные серии параметров могут определять разные классы xxxProperties, которыми также легко управлять.Рекомендуется использовать этот метод в первую очередь.
Нижний слой его проходит через:ConfigurationPropertiesBindingPostProcessor
класс реализован, класс реализованBeanPostProcessor
интерфейс, вpostProcessBeforeInitialization
разбор в методе@ConfigurationProperties
Аннотируйте и привяжите данные к соответствующему объекту.
Связывание выполняется с помощью метода bindObject класса Binder:
Приведенный выше код будет рекурсивно связывать данные, главным образом, с учетом трех ситуаций:
- bindAggregate связывает класс коллекции
- Объект привязки bindBean
- Параметры привязки bindProperty Первые два случая в конечном итоге вызовут метод bindProperty.
"Кроме того, дружеское напоминание:"
использовать@ConfigurationProperties
Обратите внимание, что в некоторых сценах есть проблемы, например:apollo
Параметр изменяется в обычной ситуации, которая может быть динамически обновлена до@ConfigurationProperties
В объекте класса xxxProperties определена аннотация, но если есть более сложный объект, например:
private Map<String, Map<String,String>> urls;
Не может быть обновлен динамически.
Что нам делать в это время?
Ответ заключается в использованииApolloConfigChangeListener
Слушатель обрабатывает это сам:
@ConditionalOnClass(com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig.class)
public class ApolloConfigurationAutoRefresh implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@ApolloConfigChangeListener
private void onChange(ConfigChangeEvent changeEvent{
refreshConfig(changeEvent.changedKeys());
}
private void refreshConfig(Set<String> changedKeys){
System.out.println("将变更的参数更新到相应的对象中");
}
}
4. Как избежать подводных камней в весенних транзакциях?
Функции транзакций весной в основном делятся на:声明式事务
и编程式事务
.
декларативная сделка
В большинстве случаев мы используем при разработке скорее декларативные транзакции, т.е.@Transactional
Аннотация определяет транзакцию, потому что она проще и удобнее в использовании.
Просто добавьте метод транзакции, который необходимо выполнить@Transactional
Аннотация может автоматически запускать транзакцию:
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Transactional
public void add(UserModel userModel) {
userMapper.insertUser(userModel);
}
}
Эта декларативная транзакция работает, потому что в ее основе используетсяAOP
, создает прокси-объект, вызываетTransactionInterceptor
Перехватчики реализуют функциональность транзакций.
Транзакция Spring имеет особое место: получаемое ею соединение с базой данных помещается в ThreadLocal, а это означает, что одно и то же соединение с базой данных может быть получено от начала до конца в одном и том же потоке, что может гарантировать выполнение нескольких операций с базой данных в одном потоке в одном потоке. один и тот же поток выполняется за одну транзакцию.
При нормальных обстоятельствах проблем не возникает, но при неправильном использовании транзакция не состоится.Основные причины заключаются в следующем:
Помимо перечисленных выше проблем, из-за@Transactional
Минимальная степень детализации аннотаций должна быть определена для методов.Если существует несколько уровней вызовов методов транзакций, это может вызвать большие проблемы с транзакциями.Поэтому рекомендуется использовать меньше аннотаций @Transactional для запуска транзакций в реальной работе.
Программные транзакции
В общем, программные транзакции, которые мы можем передатьTransactionTemplate
Класс включает функциональные возможности транзакций. Хорошая новость заключается в том, чтоspringboot
Этот объект создан по умолчанию, и мы можем использовать его непосредственно в проекте.
@Service
public class UserService {
@Autowired
private TransactionTemplate transactionTemplate;
...
public void save(final User user) {
transactionTemplate.execute((status) => {
doSameThing...
return Boolean.TRUE;
})
}
}
использоватьTransactionTemplate
Программная транзакция@Transactional
Аннотации лучше.
V. Решения междоменных проблем
Что касается междоменной проблемы, то фронтенд и бэкенд решений еще достаточно много. Здесь я остановлюсь на решениях spring. На данный момент их три типа:
1. Используйте аннотацию @CrossOrigin
@RequestMapping("/user")
@RestController
public class UserController {
@CrossOrigin(origins = "http://localhost:8016")
@RequestMapping("/getUser")
public String getUser(@RequestParam("name") String name) {
System.out.println("name:" + name);
return "success";
}
}
Это решение необходимо добавить в интерфейс для междоменного доступа@CrossOrigin
Аннотацию, правила доступа можно контролировать с помощью параметров в аннотации, а степень детализации управления выше. Это решение можно использовать, если количество интерфейсов, к которым необходимо получить доступ через домены, невелико.
2. Увеличьте глобальную конфигурацию
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST")
.allowCredentials(true)
.maxAge(3600)
.allowedHeaders("*");
}
}
Программа должна быть реализованаWebMvcConfigurer
интерфейс, переопределениеaddCorsMappings
метод, в котором определяются правила междоменного доступа. Это глобальная конфигурация, которая применяется ко всем интерфейсам.
3. Пользовательские фильтры
@WebFilter("corsFilter")
@Configuration
public class CorsFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST, GET");
httpServletResponse.setHeader("Access-Control-Max-Age", "3600");
httpServletResponse.setHeader("Access-Control-Allow-Headers", "x-requested-with");
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
Программа передана по просьбеheader
увеличить вAccess-Control-Allow-Origin
и другие параметры для решения междоменных проблем.
Кстати, используйте@CrossOrigin
Аннотация и реализацияWebMvcConfigurer
Схема интерфейса, spring в конечном итоге вызовет нижний слойDefaultCorsProcessor
КатегорияhandleInternal
метод:
В конце концов, все три решения имеют одну и ту же цель, и все они будут добавлять междоменные обязательные параметры в заголовок, но формы реализации различаются.
6. Как настроить стартер
не использовался раньшеstarter
Когда нам нужно ввести новые функции в проект, шаги обычно следующие:
- Найдите пакет jar, необходимый для этой функции, в репозитории maven.
- Найдите другие пакеты jar, от которых зависит jar, в репозитории maven.
- Параметры, необходимые для настройки новых функций
При таком подходе есть три проблемы:
- Если зависимых пакетов много, то найти очень хлопотно, легко найти неправильный и занимает много времени.
- Могут быть проблемы с совместимостью версий между зависимыми пакетами.После того, как проект представит эти пакеты JAR, он может не запуститься нормально.
- Если некоторые параметры не настроены должным образом, при запуске службы будет сообщено об ошибке, а конфигурация по умолчанию отсутствует.
«Чтобы решить эти проблемы, появился стартовый механизм Springboot».
Пусковой механизм имеет следующие преимущества:
- Он запускает соответствующую конфигурацию по умолчанию.
- Он управляет необходимыми зависимостями и избавляет от необходимости искать зависимости и проблемы совместимости.
- Механизм автоматического обнаружения автоматически внедряет классы, настроенные в файле spring.factories, в контейнер Spring.
- Следуйте философии «конвенция важнее конфигурации».
Круто, что нужно только внедрить стартовый пакет в бизнес-проект, и можно пользоваться его функциями.
Ниже приведена картинка, на которой показаны несколько элементов стартера:
Далее, давайте бороться вместе и определить собственный стартер.
Первый шаг — создать проект id-generate-starter:один из них
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>
<version>1.3.1</version>
<groupId>com.sue</groupId>
<artifactId>id-generate-spring-boot-starter</artifactId>
<name>id-generate-spring-boot-starter</name>
<dependencies>
<dependency>
<groupId>com.sue</groupId>
<artifactId>id-generate-spring-boot-autoconfigure</artifactId>
<version>1.3.1</version>
</dependency>
</dependencies>
</project>
Второй шаг — создать проект id-generate-spring-boot-autoconfigure:Проект включает в себя:
- pom.xml
- spring.factories
- IdGenerateAutoConfiguration
- IdGenerateService
- IdProperties
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">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<version>1.3.1</version>
<groupId>com.sue</groupId>
<artifactId>id-generate-spring-boot-autoconfigure</artifactId>
<name>id-generate-spring-boot-autoconfigure</name>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
spring.factories
Конфигурация выглядит следующим образом:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.sue.IdGenerateAutoConfiguration
IdGenerateAutoConfiguration类:
@ConditionalOnClass(IdProperties.class)
@EnableConfigurationProperties(IdProperties.class)
@Configuration
public class IdGenerateAutoConfiguration {
@Autowired
private IdProperties properties;
@Bean
public IdGenerateService idGenerateService() {
return new IdGenerateService(properties.getWorkId());
}
}
Класс IdGenerateService:
public class IdGenerateService {
private Long workId;
public IdGenerateService(Long workId) {
this.workId = workId;
}
public Long generate() {
return new Random().nextInt(100) + this.workId;
}
}
Класс ИдПропертиес:
@ConfigurationProperties(prefix = IdProperties.PREFIX)
public class IdProperties {
public static final String PREFIX = "sue";
private Long workId;
public Long getWorkId() {
return workId;
}
public void setWorkId(Long workId) {
this.workId = workId;
}
}
Внесите соответствующие зависимости в бизнес-проект следующим образом:
<dependency>
<groupId>com.sue</groupId>
<artifactId>id-generate-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
Вы можете использовать функцию внедрения IdGenerateService
@Autowired
private IdGenerateService idGenerateService;
Идеально.
7. Дополнительные функции при запуске проекта
Иногда нам нужно настроить некоторые дополнительные функции при запуске проекта, такие как: загрузка некоторых системных параметров, завершение инициализации, прогрев локального кеша и т. д. Что нам делать?
Хорошая новостьspringboot
при условии:
- CommandLineRunner
- ApplicationRunner
Эти два интерфейса помогают нам достичь вышеуказанных требований.
Их использование довольно просто,ApplicationRunner
Интерфейс как пример:
@Component
public class TestRunner implements ApplicationRunner {
@Autowired
private LoadDataService loadDataService;
public void run(ApplicationArguments args) throws Exception {
loadDataService.load();
}
}
выполнитьApplicationRunner
интерфейс, переопределениеrun
метод, в котором вы можете реализовать свои собственные индивидуальные требования.
Если в проекте несколько классов, реализующихApplicationRunner
Интерфейс, как указать порядок их выполнения?
Ответ заключается в использовании@Order(n)
Обратите внимание, чем меньше значение n, тем быстрее оно будет выполнено. Конечно, вы также можете@Priority
Аннотации определяют порядок.
springboot
Основной процесс при запуске проекта выглядит следующим образом:
существуетSpringApplication
КатегорияcallRunners
В методе мы видим конкретные вызовы этих двух интерфейсов:
Последний вопрос: в чем разница между этими двумя интерфейсами?
CommandLineRunner
в интерфейсеrun
Параметры методаString数组
ApplicationRunner
серединаrun
Параметры методаApplicationArguments
, параметр содержитString数组参数
и一些可选参数
.
Недавно я случайно получил заметку о чистке, написанную крупным производителем BAT, которая открыла мне сразу вторую линейку Ren и Du, и я все больше чувствую, что алгоритм не так сложен, как я себе представлял.Заметки о чистке, написанные боссом BAT, позвольте мне мягко получить предложение
болтать
В письме так много слов, и, как обычно, чтобы избежать длины страницы, я напишу это сегодня здесь. Предупреждение: будут темы по основным темам знаний, таким как AOP, BeanPostProcessor и аннотации конфигурации.Каждая тема содержит много контента, так что вы можете с нетерпением ждать ее.
Последнее слово (пожалуйста, обратите внимание, не проституируйте меня по пустякам)
Если эта статья полезна или вдохновляет вас, пожалуйста, помогите обратить внимание, ваша поддержка является самой большой мотивацией для меня, чтобы продолжать писать.
Попросите в один клик три ссылки: лайк, вперед и смотреть.
Обратите внимание на официальный аккаунт: [Су Сан сказала технология], который содержит мои последние статьи, ответ в официальном аккаунте: интервью, артефакт кода, руководство по разработке, тайм-менеджмент, есть преимущества для фанатов, и ответ: добавить группу, вы можете следить за многими BAT Старшие на большом заводе обмениваются и учатся.