本网站(662p.com)打包出售,且带程序代码数据,662p.com域名,程序内核采用TP框架开发,需要联系扣扣:2360248666 /wx:lianweikj
精品域名一口价出售:1y1m.com(350元) ,6b7b.com(400元) , 5k5j.com(380元) , yayj.com(1800元), jiongzhun.com(1000元) , niuzen.com(2800元) , zennei.com(5000元)
需要联系扣扣:2360248666 /wx:lianweikj
Springboot使用SPI注册bean到spring容器的示例代码
yuanzun168 · 238浏览 · 发布于2022-10-10 +关注

这篇文章主要介绍了Springboot使用SPI注册bean到spring容器,主要包括mydriver接口,mysqldriver实现过程,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下


新建resources/META-INF/spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.ExtensionLoader

新建META-INF/vtest/全路径接口名

mysqlDriver=com.MysqlDriver
oracleDriver=com.OracleDriver

 MyDriver接口

public interface MyDriver {
    void getConnect();
}

MysqlDriver实现

public class MysqlDriver implements MyDriver{
    @Override
    public void getConnect() {
        System.out.println("connect");
    }
}

OracleDriver实现

public class OracleDriver implements MyDriver{
    @Override
    public void getConnect() {
        System.out.println("connect");
    }
}
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.StringUtils;
  import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
  public class ExtensionLoader implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware {
      ApplicationContext context;
      BeanDefinitionRegistry beanDefinitionRegistry;
      ConcurrentHashMap<Class<?>, Map<String, Object>> EXTENSIONS = new ConcurrentHashMap<>();
      private static final String SPI_DIRECTORY = "META-INF/vtest/";
      @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
          ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) context;
        beanDefinitionRegistry = (DefaultListableBeanFactory) configurableApplicationContext.getBeanFactory();
    }
      @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        try {
            ClassLoader classLoader = DefaultListableBeanFactory.class.getClassLoader();
            URL resource;
            File[] files;
              if (classLoader != null) {
                resource = classLoader.getResource(this.SPI_DIRECTORY);
            } else {
                resource = ClassLoader.getSystemResource(this.SPI_DIRECTORY);
            }
              files = new File(resource.getFile()).listFiles();
              for (int i = 0; i < files.length; i++) {
                Class<?> clazz = Class.forName(files[i].getName(), true, classLoader);
                EXTENSIONS.putIfAbsent(clazz, loadExtensionClass(clazz.getName()));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
      @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
      }
      /**
     * 获取某个接口类型对应的实现
     *
     * @param type
     * @return
     */
    public Map<String, Object> getExtensions(Class type) {
        if (null == type) {
            throw new IllegalArgumentException("Extension Class is null");
        }
          if (!type.isInterface()) {
            throw new IllegalArgumentException("Extension Class is not an interface");
        }
          Map<String, Object> loader = EXTENSIONS.get(type);
        if (loader == null) {
            synchronized (ExtensionLoader.class) {
                loader = EXTENSIONS.get(type);
                if (loader == null) {
                    EXTENSIONS.putIfAbsent(type, loadExtensionClass(type.getName()));
                    loader = EXTENSIONS.get(type);
                }
            }
        }
        return loader;
    }
      /**
     * 从扩展文件中加载类
     *
     * @param type
     * @return
     */
    private Map<String, Object> loadExtensionClass(String type) {
        Map<String, Object> extensionClasses = new HashMap<>();
        loadDirectory(extensionClasses, SPI_DIRECTORY, type);
        return extensionClasses;
    }
      /**
     * 加载文件夹
     *
     * @param extensionClasses
     * @param dir
     * @param type
     */
    private void loadDirectory(Map<String, Object> extensionClasses, String dir, String type) {
        String fileName = dir + type;
        try {
            Enumeration<URL> urls;
            ClassLoader classLoader = DefaultListableBeanFactory.class.getClassLoader();
            if (classLoader != null) {
                urls = classLoader.getResources(fileName);
            } else {
                urls = ClassLoader.getSystemResources(fileName);
            }
            if (urls != null) {
                while (urls.hasMoreElements()) {
                    URL resourcesURL = urls.nextElement();
                    loadResources(extensionClasses, classLoader, resourcesURL);
                }
            }
        } catch (Throwable t) {
        }
    }
      private void loadResources(Map<String, Object> extensionClasses, ClassLoader classLoader, URL resourceURL) {
        try {
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    final int ci = line.indexOf('#');
                    if (ci >= 0) {
                        line = line.substring(0, ci);
                    }
                    line = line.trim();
                    if (line.length() > 0) {
                        try {
                            String name = null;
                            int i = line.indexOf('=');
                            if (i > 0) {
                                name = line.substring(0, i).trim();
                                line = line.substring(i + 1).trim();
                            }
                            if (line.length() > 0) {
                                loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name);
                            }
                        } catch (Throwable t) {
                            IllegalStateException e = new IllegalStateException("Failed to load extension class (class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
                        }
                    }
                }
            }
        } catch (Throwable t) {
        }
    }
      private void loadClass(Map<String, Object> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) {
        if (StringUtils.isEmpty(name)) {
            throw new IllegalStateException("No such extension name for the class " + name + " in the config " + resourceURL);
        }
        Object o = extensionClasses.get(name);
        if (o == null) {
            Object bean = injectBeanToSpring(name, clazz);
            extensionClasses.put(name, bean);
        } else {
            throw new IllegalStateException("Duplicate extension name " + name + " on " + clazz.getName() + " and " + clazz.getName());
        }
    }
      /**
     * 动态注入bean到spring容器
     *
     * @param name
     * @param obj
     * @return
     */
    private Object injectBeanToSpring(String name, Class<?> obj) {
        String beanName = name;
          BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(obj);
        GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition();
        definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_NAME);
        beanDefinitionRegistry.registerBeanDefinition(beanName, definition);
          // TODO: 2020/1/9  这里动态注入的bean并未将内部的@Autowired的bean依赖注入进去,如何解决?
          // 通过反射设置@Autowired标记的字段的值
          Object bean = context.getBean(beanName);
          Field[] declaredFields = obj.getDeclaredFields();
        for (Field field : declaredFields) {
            if (field.isAnnotationPresent(Autowired.class)) {
                Object aClass = context.getBean(field.getType());
                  ReflectHelper.setFieldValue(bean, field.getName(), aClass);
            }
        }
          return bean;
    }
}
public class ReflectHelper {
      /**
     * 利用反射获取指定对象的指定属性
     *
     * @param obj       目标对象
     * @param fieldName 目标属性
     * @return 目标属性的值
     */
    public static Object getFieldValue(Object obj, String fieldName) {
        Object result = null;
        Field field = ReflectHelper.getField(obj, fieldName);
        if (field != null) {
            field.setAccessible(true);
            try {
                result = field.get(obj);
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return result;
    }
      /**
     * 利用反射获取指定对象里面的指定属性
     *
     * @param obj       目标对象
     * @param fieldName 目标属性
     * @return 目标字段
     */
    private static Field getField(Object obj, String fieldName) {
        Field field = null;
        for (Class<?> clazz = obj.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
            try {
                field = clazz.getDeclaredField(fieldName);
                break;
            } catch (NoSuchFieldException e) {
                //这里不用做处理,子类没有该字段可能对应的父类有,都没有就返回null。
            }
        }
        return field;
    }
      /**
     * 利用反射设置指定对象的指定属性为指定的值
     *
     * @param obj        目标对象
     * @param fieldName  目标属性
     * @param fieldValue 目标值
     */
    public static void setFieldValue(Object obj, String fieldName,
                                     Object fieldValue) {
        Field field = ReflectHelper.getField(obj, fieldName);
        if (field != null) {
            try {
                field.setAccessible(true);
                field.set(obj, fieldValue);
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
}

Controller:

@RestController
@RequestMapping("/t")
@Api(value = "测试服务", description = "")
public class TestController {
      // 切换不同的服务
    @Autowired
    @Qualifier("mysqlDriver")
    private MyDriver myDriver;
      @ApiOperation(value = "测试", notes = "基于SPRING BOOT实现的JAVA SPI机制的DEMO")
    @GetMapping("/spi")
    public String test() {
        myDriver.getConnect();
          return "ok";
    }
}

到此这篇关于Springboot使用SPI注册bean到spring容器的文章就介绍到这了


相关推荐

PHP实现部分字符隐藏

沙雕mars · 1322浏览 · 2019-04-28 09:47:56
Java中ArrayList和LinkedList区别

kenrry1992 · 906浏览 · 2019-05-08 21:14:54
Tomcat 下载及安装配置

manongba · 966浏览 · 2019-05-13 21:03:56
JAVA变量介绍

manongba · 960浏览 · 2019-05-13 21:05:52
什么是SpringBoot

iamitnan · 1084浏览 · 2019-05-14 22:20:36
加载中

0评论

评论
欢迎大家关注我的个人主页!!!
分类专栏
小鸟云服务器
扫码进入手机网页