Зарегистрировать BeanFactory в SpringBoot - PullRequest
1 голос
/ 16 октября 2019

Во-первых, я не уверен, стоит ли делать все это.

Цель состоит в том, чтобы создать несколько интерфейсов с аннотациями, чтобы скрыть устаревший доступ к строкам на основе позиции из базы данных конфигурации, без реализации каждого интерфейса. .

Декларативно настроенный интерфейс:

  public interface LegacyConfigItem extends ConfigDbAccess{

  @Subfield(length=3)
  String BWHG();

  @Subfield(start = 3, length=1)
  int BNKST();

  @Subfield(start = 4, length=1)
  int BEINH();
  :
  }

Базовый интерфейс для идентификации во время выполнения

  public interface ConfigDbAccess{

  }

Пустая реализация без функциональности, может измениться.

  public class EmptyImpl {

  }

Перехватчик Beanfactory и MethodInvocation, для обработки нереализованных методов.

@Component
public class InterfaceBeanFactory extends DefaultListableBeanFactory {

  protected static final int TEXT_MAX = 400;

  @Autowired
  private EntityRepo entityRepo;

   public <T> T getInstance(Class<T> legacyInterface, String key) {
    ProxyFactory factory = new ProxyFactory(new EmptyImpl());
    factory.setInterfaces(legacyInterface);
    factory.setExposeProxy(true);
    factory.addAdvice(new MethodInterceptor() {

      @Override
      public Object invoke(MethodInvocation invocation) throws Throwable {
        KEY keyAnnotation = invocation.getThis().getClass().getAnnotation(Key.class);
        String key= keyAnnotation.key().toUpperCase();
        String ptart = invocation.getMethod().getDeclaringClass().getSimpleName();        
        Vpt result = entityRepo.getOne(new EntityId(ptart.toUpperCase(), schl.toUpperCase()));
        Subfield sub = invocation.getMethod().getAnnotation(Subfield.class);
        //TODO: Raise missing Subfield annotation
        int start = sub.start();
        int length = sub.length();
        if (start + length > TEXT_MAX) {
          //TODO: Raise invalid Subfield config
        }
        String value = result.getTextField().substring(start,start+length);
        return value;
      }
    });
    return (T) factory.getProxy();
  }

  @Override
  protected Map<String, Object> findAutowireCandidates(String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
      Map<String, Object> map = super.findAutowireCandidates(beanName, requiredType, descriptor);
      if (ConfigDbAccess.class.isAssignableFrom(requiredType )) {
        :
@SpringBootApplication
public class JpaDemoApplication {

  @Autowired
  private ApplicationContext context;
    public static void main(String[] args) {
      SpringApplication app = new SpringApplication(JpaDemoApplication.class);
//    app.setApplicationContextClass(InterfaceInjectionContext .class);
      app.run(args);
    }

public class InterfaceInjectionContext extends AnnotationConfigApplicationContext {

  public VptInjectionContext () {
    super (new InterfaceBeanFactory ());
  }
}

Пока все это работает, за исключением случаев, когда я пытаюсь установить класс приложения для класса DefaultListableBeanFactory,Я убиваю стартовую сеть Spring. Приложение запускается, внедряет поля Autowired с моей перехваченной псевдо-реализацией - и заканчивается.

Я думаю, что я делаю что-то не так с регистрацией DefaultListableBeanFactory, но я понятия не имею, как это сделать правильно.

1 Ответ

1 голос
/ 17 октября 2019

Чтобы получить ответ: М. Дейнм указал мне на гораздо более простое решение: вместо создания BeanFactory я установил BeanPostProcessor с этой функциональностью.

@RestController
public class DemoRestController {
   @Autowired
   VptService vptService;

   @ConfigItem(key="KS001")
   private PrgmParm prgmKs001;

   @ConfigItem(key="KS002")
   private PrgmParm prgmKs002;

   public DemoRestController() {
     super();
   }

Где аннотация ConfigItem определяет точку внедрения.

Далее я создал CustomBeanPostProcessor, который сканирует все входящие bean-компоненты для полей, имеющих аннотацию ConfigItem

@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {


  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    for (Field field : bean.getClass().getDeclaredFields()) {
      SHL cfgDef = field.getAnnotation(ConfigItem.class);
      if (cfgDef != null) {
        Object instance = getlInstance(field.getType(), cfgDef.key());
        boolean accessible = field.isAccessible();
        field.setAccessible(true);
        try {
          field.set(bean, instance);
        } catch (IllegalArgumentException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        } catch (IllegalAccessException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
        field.setAccessible(accessible);
      }
    }
    return bean;
  }

getInstnce (field.getType (), cfgDef.key ()) создает прокси сMethodInterceptor, который выполняет эту работу.

Есть много вещей, которые нужно доработать, но в целом это выглядит хорошо для меня.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...