spring: Implementar la inicialización de beans dinámicos | Obtener el archivo de configuración de matriz de objetos

0 Prefacio

Recientemente, tengo que completar el componente del kit de herramientas del middleware, que implica leer el archivo de configuración de la matriz de objetos y cargarlo como un bean. Debido a la spring 4.3.25.RELEASEversión utilizada, muchas características relacionadas con Springboot no pueden ser compatibles, por lo que esto se registra. Para facilitar el seguimiento estudiantes que tienen la misma situación para referirse

1. Obtenga el archivo de configuración de la matriz de objetos

Primero, el archivo de configuración de la matriz de objetos es el siguiente:

minio.clients[0].name=xxx
minio.clients[0].endpoint=http://ip1:9000
minio.clients[0].access.key=admin
minio.clients[0].secret.key=asd
minio.clients[0].default.bucket=wu
minio.clients[1].name=yyy
minio.clients[1].endpoint=http://ip2:9000
minio.clients[1].access.key=admin
minio.clients[1].secret.key=asd
minio.clients[1].default.bucket=wu

El formato convertido a yml es el siguiente:

minio:
  clients:
    - name: xxx
      endpoint: http://ip1:9000
      access:
        key: admin
      secret:
        key: asd
      default:
        bucket: wu
    - name: yyy
      endpoint: http://ip2:9000
        access:
          key: admin
        secret:
          key: asd
        default:
          bucket: wu

Si es un proyecto Springboot, podemos usar uno directamente @ConfigurationProperties(prefix="minio.clients")y luego configurar una clase de entidad para lograrlo. Sin embargo, debido a que aquí nos encontramos con una versión anterior del proyecto Spring, esta anotación no es compatible. Así que intenta implementarlo de otras maneras.


En primer lugar, el formulario @Value@Value puede ayudarnos a leer elementos de configuración, pero solo se puede usar para elementos de configuración de tipos básicos o matrices de tipos básicos. Para archivos de configuración de matrices de nuestros elementos de objetos, no es compatible. En primavera , Excepto por este método, también Environmentse puede implementar directamente mediante objetos operativos.

Formulario de entorno
Puede ver que podemos obtener los elementos de configuración que queremos a través del método Environment.getProperty, por lo que este método es obviamente factible.

Al mismo tiempo, cuando el entorno lee el elemento de configuración, necesita especificar el archivo de configuración, por lo que debe declararlo con ayuda. Al mismo tiempo, @PropertySourcedebido a que se trata de un conjunto de herramientas, significa que es posible que el archivo de configuración no esté disponible. . Si no, no hay necesidad de inicializar el bean. Si hay un archivo de configuración correspondiente, el bean se inicializará automáticamente. , esto es lo que queremos lograr

Haga clic en @PropertySourcela anotación y podremos ver un ignoreResourceNotFoundatributo. El nombre del atributo nos ha dicho su función. Al establecer su valor en verdadero, podemos leer el elemento de configuración cuando el archivo de configuración existe, y no se informará ningún error cuando no exista. .

Insertar descripción de la imagen aquí

El ejemplo completo es el siguiente:

@Configuration
@PropertySource(value = {
    
    "classpath:applicaiton.properties","classpath:minio.properties"}, ignoreResourceNotFound=true)
public class MinioMultiConfiguration {
    
    
 
    @Resource
    private Environment environment;
 	
 	...   
}    

¿Cómo obtener dinámicamente elementos de configuración de matriz de longitud no fija?
En segundo lugar, debemos observar los requisitos aquí, porque en realidad se pueden obtener múltiples configuraciones de minio.clients, aquí solo enumeramos dos, porque lo que se implementa es un conjunto de herramientas, y se pueden configurar muchas más en el futuro, por lo que la longitud es inesperado..

Luego necesitamos obtener la longitud de esta matriz. Si es Springboot, podemos List<配置实体类> listobtener la longitud de la colección directamente a través de la colección definida. Sin embargo, aquí en primavera, no podemos obtener directamente la longitud de la matriz, por lo que para Para satisfacer la demanda, solo podemos tomar una forma estúpida de definir directamente una configuración de longitud minio.clients.length=2. Si hay una forma mejor en el futuro, puede dejar un mensaje para discutir.

forLuego podemos obtener los elementos de configuración repitiendo el código.

2. Cómo registrar frijoles en el contenedor Spring

Al mismo tiempo, debido a que mis necesidades aquí también necesitan inicializar las correspondientes MinioClient, entonces los beans creados deben registrarse en el contenedor de primavera. Además de @Beanlas anotaciones, el registro en el contenedor es el siguiente:

@Configuration
public class MinioConfiguration {
    
    
    /**
     * 对象存储服务的url
     */
    @Value("${minio.endpoint:null}")
    private String endpoint;

    /**
     * 用户ID
     */
    @Value("${minio.access.key:null}")
    private String accessKey;

    /**
     * 账户密码
     */
    @Value("${minio.secret.key:null}")
    private String secretKey;

    /**
     * 默认桶名
     */
    @Value("${minio.default.bucket:null}")
    private String defaultBucketName = "wu";

    @Bean
    public MinioClient minioClient() throws Exception{
    
    
        MinioProperties minioProperties = new MinioProperties(endpoint, accessKey, secretKey, defaultBucketName);
        if(StringUtils.isEmpty(minioProperties.getEndpoint())){
    
    
            return null;
        }
        return new MinioClient(minioProperties.getEndpoint(), minioProperties.getAccessKey(), minioProperties.getSecretKey());
    }
}

También puedes BeanFactoryregistrarte a través de, como se muestra a continuación.

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerSingleton("beanName", new MinioClient());

Puede ver que debido a que necesitamos leer elementos de configuración en un bucle, la cantidad de beans es variable, por lo que el @Beanformulario fijo definitivamente no funcionará. Solo podemos registrarnos a través de beanFactory.

Tiempo de registro de beans
Sabemos que los beans deben registrarse cuando se inicia el proyecto, pero hay muchas etapas durante el inicio. Por ejemplo, los beans que inicializamos en realidad deben pasarse @Autowiredo @Resourcereferenciarse, por lo que definitivamente debemos registrar estos dos. Regístrelo antes de hacer referencia. de lo contrario obtendrá un error que indica que no se puede encontrar el bean.

Hay varias formas de ejecutar el método cuando el proyecto comienza en primavera. El método más utilizado @PostConstructes el método anotado, pero el orden de ejecución de este método es @Bean>> , por lo que definitivamente no funcionará.@Autowired@PostConstruct

Así que intentamos otra forma BeanFactoryPostProcessorde lograrlo declarando la interfaz postProcessBeanFactory方法, lo que puede realizar algunas modificaciones personalizadas en beanFactory y podemos registrar los beans en estas modificaciones.

Al mismo tiempo, debido a que necesitamos obtener elementos de configuración a través del Medio Ambiente, también debemos declarar y registrar el Medio Ambiente EnvironmentAwarea través de métodos. Por supuesto, también puede optar por obtenerlos a través desetEnvironmentbeanFactory.getBean("environment")

El código de muestra completo es el siguiente:

public class MinioMultiBeanFactoryPostProcessor implements BeanFactoryPostProcessor, EnvironmentAware {
    
    
    private final static Logger log = LogManager.getLogger(MinioMultiBeanFactoryPostProcessor.class);

    private Environment environment;

    @Override
    public void setEnvironment(Environment environment) {
    
    
        this.environment = environment;
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    
    
        if(!environment.containsProperty("minio.clients.length")){
    
    
            log.error("未识别到minio.clients.length,取消配置多个minioClient");
            return;
        }
        Integer length = 0;
        try {
    
    
            length = environment.getProperty("minio.clients.length", Integer.class);
        }catch (Exception e){
    
    
            throw new RuntimeException("minioClient初始化失败,minio.clients.length数据类型为Int");
        }
        for (int i = 0; length != null && i < length; i++) {
    
    
            String name = environment.getProperty("minio.clients["+i+"].name");
            String endpoint = environment.getProperty("minio.clients["+i+"].endpoint");
            String access = environment.getProperty("minio.clients["+i+"].access.key");
            String secret = environment.getProperty("minio.clients["+i+"].secret.key");
            String bucket = environment.getProperty("minio.clients["+i+"].default.bucket");
            try{
    
    
                // 自定义对象
                MinioProperties minioProperties = new MinioProperties(endpoint, access, secret, bucket);
                // 创建client
                MinioClient minioClient = new MinioClient(minioProperties.getEndpoint(), minioProperties.getAccessKey(), minioProperties.getSecretKey());
                beanFactory.registerSingleton(name+"MinioClient", minioClient);
            }catch (Exception e){
    
    
                log.error(String.format("minioClient初始化失败:%s", ExceptionUtil.getErrorInfo(e)));
            }
        }
    }
}

Luego necesitamos combinar la secuencia @Bean> mencionada anteriormente @Autowired, porque lo que personalizamos BeanFactoryPostProcessorahora es solo una clase simple, y también necesitamos declararla como un bean para lograr el propósito de modificar BeanFactory, por lo que @Beanla inicializamos a través de

@Configuration
@PropertySource(value = {
    
    "classpath:application.properties","classpath:minio.properties"}, ignoreResourceNotFound=true)
public class MinioMultiConfiguration {
    
    

    @Bean
    public MinioMultiBeanFactoryPostProcessor minioMultiBeanFactoryPostProcessor(){
    
    
        return new MinioMultiBeanFactoryPostProcessor();
    }

}

En este punto, hemos completado la operación de inicialización de beans dinámicos. El método anterior es aplicable a cualquier proyecto de Spring y es más adecuado para proyectos que necesitan construir paquetes intermedios. Puede consultarlo de forma selectiva.

Supongo que te gusta

Origin blog.csdn.net/qq_24950043/article/details/133011128
Recomendado
Clasificación