spring boot源码-自定义初始化器的三种方式

本文详细介绍了三种在Spring应用中进行初始化的方法:通过spring.factories文件注册、在SpringApplication启动时手动添加初始化器以及通过环境变量指定初始化器类。每种方法都提供了具体的实现步骤和代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第一种:定义在spring.factories中被SpringFactoriesLoader发现注册

通过模仿源码实现,代码如下:


import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.UrlResource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.util.*;

/**
 * @Auth : HUANG GUOYE.
 * @Date : 2020/3/22
 * @Desc : mooc-study
 */
public class Test01 {


    public static void main(String[] args) {
        Test01 test01 = new Test01();
        List<Object> list = test01.test001(ApplicationContextInitializer.class);
        test01.action(list);
    }
    /**
     *  获取系统初始化器的实例demo
     * 1.获得类加载器的reference
     * 2.获得接口系统初始化器接口(ApplicationContextInitializer)名称
     * 3.取文件classLoader.getResources("META-INF/spring.factories")
META-INF/spring.factories:org.springframework.context.ApplicationContextInitializer=com.mooc.study.initializer.FirstInitializer
     * 4.转properties,
     * 5.取值进集合
     * 6.反射实例
     * 7.排序
     */
    private <T>  List<Object> test001(Class<T> type){
        List<Object> instances = new ArrayList<>();
        Set<String> result = new HashSet<>();
        //1.获得类加载器的reference
        ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
        //2.获得接口系统初始化器接口(ApplicationContextInitializer)名称
//        Class<ApplicationContextInitializer> applicationContextInitializerClass = ApplicationContextInitializer.class;
        String clazzName = type.getName();
        //3.取文件classLoader.getResources("META-INF/spring.factories")
        try {
            Enumeration<URL> resources = classLoader.getResources("META-INF/spring.factories");
            while (resources.hasMoreElements()) {
                //4.转properties,
                URL url = resources.nextElement();
                UrlResource resource = new UrlResource(url);
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                Iterator<Map.Entry<Object, Object>> iterator = properties.entrySet().iterator();
                //5.取值进集合
                while (iterator.hasNext()) {
                    Map.Entry<Object, Object> entry = iterator.next();
                    //只要自己的配置,其余的不要
                    if (clazzName.equals(entry.getKey())) {
                        String[] arr = String.valueOf(entry.getValue()).trim().split(",");
                        for (String str : arr) {
                            result.add(str);
                        }
                    }
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
            throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", e);
        }
        //6.反射实例
        for (String e : result) {
            try {
                Class<?> aClass = Class.forName(e);
                //判断配置的对还是错,是不是该接口的实现类
                Assert.isAssignable(type, aClass);
                Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
                Object instance = BeanUtils.instantiateClass(declaredConstructor,  new Class[0]);
                instances.add(instance) ;
            } catch (ClassNotFoundException e1  ) {
                throw new IllegalArgumentException("Cannot instantiate " + clazzName + " : " + e, e1);
            } catch (NoSuchMethodException e1) {
                e1.printStackTrace();
            }
        }

        //7.排序
        instances.sort((o1,o2)->{
            int i1 = Integer.MAX_VALUE ;
            Order order1 = o1.getClass().getAnnotation(Order.class);
            if(null != order1){
                i1 = order1.value();
            }
            int i2 = Integer.MAX_VALUE ;
            Order order2 = o2.getClass().getAnnotation(Order.class);
            if(null != order2){
                i2 = order2.value();
            }
            return i1 - i2;
        });
        return instances ;
    }

    /**
     *  8.调用实例方法
     * @param list
     */
    private void action(List<Object> list ){
        ConfigurableApplicationContext context = null ;
        try {
            Class<?> aClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
            Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
            Object instance = BeanUtils.instantiateClass(declaredConstructor,  new Class[0]);
            context = (ConfigurableApplicationContext) instance;
        } catch (ClassNotFoundException | NoSuchMethodException e) {
            e.printStackTrace();
        }


        for (Object o : list) {
            ApplicationContextInitializer initializer = (ApplicationContextInitializer)o ;
            Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class);
            Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
            initializer.initialize(context);
        }
        ConfigurableEnvironment environment = context.getEnvironment();
        String value = environment.getProperty("key1");
        System.out.println("value="+value);

    }

}

第二种:SpringApplication初始化完毕后,手动添加

1.启动springboot项目

/**
 *  配置自定系统初始化器
 *  springapp
 */
SpringApplication springApplication = new SpringApplication(Application.class);
//手动添加自定义初始化器
springApplication.addInitializers(new SecondInitializer());
springApplication.run(args);

2.硬编码,手动添加实例

/**
 * Add {@link ApplicationContextInitializer}s to be applied to the Spring
 * {@link ApplicationContext}.
 * @param initializers the initializers to add
 */
public void addInitializers(ApplicationContextInitializer<?>... initializers) {
        //硬编码,手动添加实例
      this.initializers.addAll(Arrays.asList(initializers));
}

3.调用实例的initialize方法


/**
 * Apply any {@link ApplicationContextInitializer}s to the context before it is
 * refreshed.
 * @param context the configured ApplicationContext (not refreshed yet)
 * @see ConfigurableApplicationContext#refresh()
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
protected void applyInitializers(ConfigurableApplicationContext context) {
   for (ApplicationContextInitializer initializer : getInitializers()) {
       //获取泛型类,判断是否是需要的类    
      Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
            ApplicationContextInitializer.class);
      Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
      //调用实现方法
      initializer.initialize(context);
   }
 }

第三种:定义成环境变量,被DelegatingApplicationContextInitializer发现注册

1.调用DelegatingApplicationContextInitializer的initialize方法,获取环境变量(

context.initializer.classes=com.mooc.study.initializer.ThirdInitializer

)-class-instance-initialize

@Override
public void initialize(ConfigurableApplicationContext context) {
    //获取环境变量
   ConfigurableEnvironment environment = context.getEnvironment();
   //获取context.initializer.classes定义的类,反射->class
   List<Class<?>> initializerClasses = getInitializerClasses(environment);
   if (!initializerClasses.isEmpty()) {
      applyInitializerClasses(context, initializerClasses);
   }
}

 

2.通过反射获得class

private List<Class<?>> getInitializerClasses(ConfigurableEnvironment env) {
   String classNames = env.getProperty(PROPERTY_NAME);
   List<Class<?>> classes = new ArrayList<>();
   if (StringUtils.hasLength(classNames)) {
      for (String className : StringUtils.tokenizeToStringArray(classNames, ",")) {
          //反射
         classes.add(getInitializerClass(className));
      }
   }
   return classes;
}

3.通过反射获得实例

private void applyInitializerClasses(ConfigurableApplicationContext context, List<Class<?>> initializerClasses) {
   Class<?> contextClass = context.getClass();
   List<ApplicationContextInitializer<?>> initializers = new ArrayList<>();
   for (Class<?> initializerClass : initializerClasses) {
       //反射进集合
      initializers.add(instantiateInitializer(contextClass, initializerClass));
   }
   applyInitializers(context, initializers);
}

4.调用实现方法

private void applyInitializers(ConfigurableApplicationContext context,
      List<ApplicationContextInitializer<?>> initializers) {
   initializers.sort(new AnnotationAwareOrderComparator());
   for (ApplicationContextInitializer initializer : initializers) {
       //调用实现方法
      initializer.initialize(context);
   }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值