From 20dbcee88ba4703d7c31d0c1200c13951520e0eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=A9=AC=E5=93=A5=EF=BC=88mercyblitz=EF=BC=89?= Date: Mon, 22 Apr 2024 13:37:29 +0800 Subject: [PATCH] Refactor --- .../DelegatingServiceMessageSource.java | 1 - .../i18n/spring/annotation/EnableI18n.java | 34 +++++- .../I18nImportBeanDefinitionRegistrar.java | 115 ++++++++++++++++++ .../factory/config/I18nBeanPostProcessor.java | 16 ++- .../i18n/spring/constants/I18nConstants.java | 9 +- .../context/I18nApplicationListener.java | 71 +++++++++++ .../spring/context/I18nConfiguration.java | 2 + .../spring/annotation/EnableI18nTest.java | 59 +++++++++ 8 files changed, 299 insertions(+), 8 deletions(-) create mode 100644 microsphere-i18n-spring/src/main/java/io/microsphere/i18n/spring/annotation/I18nImportBeanDefinitionRegistrar.java create mode 100644 microsphere-i18n-spring/src/main/java/io/microsphere/i18n/spring/context/I18nApplicationListener.java create mode 100644 microsphere-i18n-spring/src/test/java/io/microsphere/i18n/spring/annotation/EnableI18nTest.java diff --git a/microsphere-i18n-spring/src/main/java/io/microsphere/i18n/spring/DelegatingServiceMessageSource.java b/microsphere-i18n-spring/src/main/java/io/microsphere/i18n/spring/DelegatingServiceMessageSource.java index 5142ed6..e4d9292 100644 --- a/microsphere-i18n-spring/src/main/java/io/microsphere/i18n/spring/DelegatingServiceMessageSource.java +++ b/microsphere-i18n-spring/src/main/java/io/microsphere/i18n/spring/DelegatingServiceMessageSource.java @@ -10,7 +10,6 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.ObjectProvider; -import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.lang.NonNull; import java.nio.charset.Charset; diff --git a/microsphere-i18n-spring/src/main/java/io/microsphere/i18n/spring/annotation/EnableI18n.java b/microsphere-i18n-spring/src/main/java/io/microsphere/i18n/spring/annotation/EnableI18n.java index 294f516..631be0c 100644 --- a/microsphere-i18n-spring/src/main/java/io/microsphere/i18n/spring/annotation/EnableI18n.java +++ b/microsphere-i18n-spring/src/main/java/io/microsphere/i18n/spring/annotation/EnableI18n.java @@ -16,8 +16,12 @@ */ package io.microsphere.i18n.spring.annotation; -import io.microsphere.i18n.spring.context.I18nConfiguration; +import io.microsphere.i18n.ServiceMessageSource; +import io.microsphere.i18n.spring.beans.factory.ServiceMessageSourceFactoryBean; +import io.microsphere.i18n.spring.constants.I18nConstants; +import org.springframework.context.MessageSource; import org.springframework.context.annotation.Import; +import org.springframework.context.support.AbstractApplicationContext; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; @@ -26,17 +30,41 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import static io.microsphere.i18n.ServiceMessageSource.COMMON_SOURCE; + /** * Enables the extension for Spring Internationalisation * * @author Mercy - * @see I18nConfiguration + * @see I18nImportBeanDefinitionRegistrar + * @see ServiceMessageSourceFactoryBean * @since 1.0.0 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE}) @Documented @Inherited -@Import(I18nConfiguration.class) +@Import(I18nImportBeanDefinitionRegistrar.class) public @interface EnableI18n { + + /** + * Declares the sources of the {@link ServiceMessageSource} as the {@link ServiceMessageSourceFactoryBean} Spring Beans + * to be registered. + *

+ * The attribute value will be merged from the Spring property whose name is {@link I18nConstants#SOURCES_PROPERTY_NAME} + * + * @return {@link ServiceMessageSource#COMMON_SOURCE} as the default + * @see I18nConstants#SOURCES_PROPERTY_NAME + */ + String[] sources() default {COMMON_SOURCE}; + + /** + * Whether to expose {@link I18nConstants#SERVICE_MESSAGE_SOURCE_BEAN_NAME the primary Spring Bean} + * {@link ServiceMessageSource} as the {@link MessageSource} + * + * @return true as default + * @see AbstractApplicationContext#MESSAGE_SOURCE_BEAN_NAME + * @see MessageSource + */ + boolean exposeMessageSource() default true; } diff --git a/microsphere-i18n-spring/src/main/java/io/microsphere/i18n/spring/annotation/I18nImportBeanDefinitionRegistrar.java b/microsphere-i18n-spring/src/main/java/io/microsphere/i18n/spring/annotation/I18nImportBeanDefinitionRegistrar.java new file mode 100644 index 0000000..d6aa5ad --- /dev/null +++ b/microsphere-i18n-spring/src/main/java/io/microsphere/i18n/spring/annotation/I18nImportBeanDefinitionRegistrar.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.microsphere.i18n.spring.annotation; + +import io.microsphere.i18n.spring.DelegatingServiceMessageSource; +import io.microsphere.i18n.spring.beans.factory.ServiceMessageSourceFactoryBean; +import io.microsphere.i18n.spring.beans.factory.config.I18nBeanPostProcessor; +import io.microsphere.i18n.spring.beans.factory.support.ServiceMessageSourceBeanLifecyclePostProcessor; +import io.microsphere.i18n.spring.context.I18nApplicationListener; +import io.microsphere.i18n.spring.context.MessageSourceAdapter; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.context.EnvironmentAware; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.core.env.Environment; +import org.springframework.core.type.AnnotationMetadata; + +import java.lang.annotation.Annotation; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.function.Supplier; + +import static io.microsphere.i18n.spring.constants.I18nConstants.SERVICE_MESSAGE_SOURCE_BEAN_NAME; +import static io.microsphere.i18n.spring.constants.I18nConstants.SOURCES_PROPERTY_NAME; +import static io.microsphere.spring.util.BeanRegistrar.registerBeanDefinition; +import static io.microsphere.util.ArrayUtils.EMPTY_STRING_ARRAY; +import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition; +import static org.springframework.context.support.AbstractApplicationContext.MESSAGE_SOURCE_BEAN_NAME; +import static org.springframework.core.annotation.AnnotationAttributes.fromMap; + +/** + * I18n {@link ImportBeanDefinitionRegistrar} + * + * @author Mercy + * @see ImportBeanDefinitionRegistrar + * @see EnableI18n + * @since 1.0.0 + */ +public class I18nImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware { + + private static final Class ANNOTATION_TYPE = EnableI18n.class; + + private Environment environment; + + @Override + public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { + AnnotationAttributes attributes = fromMap(metadata.getAnnotationAttributes(ANNOTATION_TYPE.getName())); + registerServiceMessageSourceBeanDefinitions(attributes, registry); + registerMessageSourceAdapterBeanDefinition(attributes, registry); + registerI18nApplicationListenerBeanDefinition(registry); + registerBeanPostProcessorBeanDefinitions(registry); + } + + private void registerServiceMessageSourceBeanDefinitions(AnnotationAttributes attributes, BeanDefinitionRegistry registry) { + Set sources = resolveSources(attributes); + + for (String source : sources) { + String beanName = source + "ServiceMessageSource"; + registerBeanDefinition(registry, beanName, ServiceMessageSourceFactoryBean.class, source); + } + + // Register DelegatingServiceMessageSource as the Spring Primary Bean + BeanDefinition primaryBeanDefinition = rootBeanDefinition(DelegatingServiceMessageSource.class).setPrimary(true).getBeanDefinition(); + registry.registerBeanDefinition(SERVICE_MESSAGE_SOURCE_BEAN_NAME, primaryBeanDefinition); + } + + private Set resolveSources(AnnotationAttributes attributes) { + Set sources = new LinkedHashSet<>(); + initSources(sources, () -> environment.getProperty(SOURCES_PROPERTY_NAME, String[].class, EMPTY_STRING_ARRAY)); + initSources(sources, () -> attributes.getStringArray("sources")); + return sources; + } + + private void initSources(Set sources, Supplier sourcesSupplier) { + for (String source : sourcesSupplier.get()) { + sources.add(environment.resolvePlaceholders(source)); + } + } + + private void registerMessageSourceAdapterBeanDefinition(AnnotationAttributes attributes, BeanDefinitionRegistry registry) { + boolean exposeMessageSource = attributes.getBoolean("exposeMessageSource"); + if (exposeMessageSource) { + registerBeanDefinition(registry, MESSAGE_SOURCE_BEAN_NAME, MessageSourceAdapter.class); + } + } + + private void registerI18nApplicationListenerBeanDefinition(BeanDefinitionRegistry registry) { + registerBeanDefinition(registry, I18nApplicationListener.class); + } + + private void registerBeanPostProcessorBeanDefinitions(BeanDefinitionRegistry registry) { + registerBeanDefinition(registry, I18nBeanPostProcessor.class); + registerBeanDefinition(registry, ServiceMessageSourceBeanLifecyclePostProcessor.class); + } + + @Override + public void setEnvironment(Environment environment) { + this.environment = environment; + } +} diff --git a/microsphere-i18n-spring/src/main/java/io/microsphere/i18n/spring/beans/factory/config/I18nBeanPostProcessor.java b/microsphere-i18n-spring/src/main/java/io/microsphere/i18n/spring/beans/factory/config/I18nBeanPostProcessor.java index 3b9cd5e..fa18e16 100644 --- a/microsphere-i18n-spring/src/main/java/io/microsphere/i18n/spring/beans/factory/config/I18nBeanPostProcessor.java +++ b/microsphere-i18n-spring/src/main/java/io/microsphere/i18n/spring/beans/factory/config/I18nBeanPostProcessor.java @@ -3,13 +3,16 @@ import io.microsphere.i18n.spring.context.MessageSourceAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.aop.support.AopUtils; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.MessageSource; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; +import static io.microsphere.util.ClassLoaderUtils.resolveClass; +import static org.springframework.aop.support.AopUtils.getTargetClass; + + /** * Internationalization {@link BeanPostProcessor}, Processing: *