Nạp Controller trong Spring MVC tại thời điểm runtime - How to load Controller in Spring MVC at runtime

Xin chào mọi người,
Hiện giờ mình đang gặp một vấn đề là không thể nạp controller trong Spring MVC tại thời điểm runtime. Bình thường khi phát triển một ứng dụng web trong java, ta chỉ cần build ra file .war sau đó tiến hành deploy lên server là xong, nhưng yêu cầu đặt ra là khi muốn nâng cấp chức năng ta phải undeploy file .war đó xuống và deploy file .war mới lên. Làm như vậy sẽ ta sẽ gây là downtime. Chính vì thế mình được yêu cầu là phải tiến hành chuyển dự án sang mô hình Dynamic Module OSGi.
Để tiến hành chuyển sang OSGi mình sử dụng Blueprint Gemini để register và reference các service. Bây giờ giả sử mình có 2 bundle tạm gọi là A và B.

  • Bundle A: sẽ chứa ứng dụng web viết bằng Spring MVC. và được tiến hành deploy trước

  • Bundle B: sẽ chứa các class Controller tương ứng với các chức năng ta muốn nâng cấp.
    Vấn đề đặt ra làm thế nào để các class Controller trong bundle B sẽ được bundle A sử dụng. Vì thế mình đã search cách làm thế nào để nạp controller bằng tay trong Spring MVC. Mình đã tìm thấy cách giải quyết tại ĐÂY.
    Sau đó tại bundle A, mình sẽ tiến hành register đối tượng này lên OSGi container để bundle B có thể reference về sử dụng và gọi phương thức thêm các class Controller tới bundle A như sau:

    @Component
    public class RegistryController implements BeanDefinitionRegistryPostProcessor {
    private BeanDefinitionRegistry registry;

      @Override
      public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    
      }
    
      @Override
      public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
      	this.registry = registry;
      }
    
      public void registryController(Class<?> clazz, String beanName) {
      	BeanDefinition bean = new RootBeanDefinition(clazz);
      	registry.registerBeanDefinition(beanName, bean);
      }
    

    }
    Sau đó tiến hành đăng ký đối tượng này để bundle B có thể reference và add class Controller vào
    <osgi:service interface="com.test.bundleA.config.RegistryController " ref="registryController " />

Tại bundle B mình sẽ reference đối tượng RegistryController về và add các class Controller vào

<osgi:reference id="registryController"
		interface="com.test.bundleA.config.RegistryController">
		<osgi:reference-listener ref="registryControllerListener"
			bind-method="bind" />
</osgi:reference>

@Component
public class RegistryControllerListener {
	public void bind(RegistryController registry) {
		System.out.println("Binding: " + registry);
		registry.registryController(TestController.class, "testController");
	}
}

@RestController
@RequestMapping("/test")
public class TestController {

	@GetMapping
	public String test() {
		return "TEST";
	}
}

Sau khi hoàn thành, deploy bundle A lên trước và bundle B lên sau, bean TestController trong Bundle B đã được tạo tới bundle A nhưng mình test tại đường dẫn /test lại không tìm thấy mặc dù bean TestController đã được tạo. Mình đoán là lúc này WebApplicationContext vẫn chưa refresh lại, mình tiến hành refresh lại ApplicationContext thì vẫn không được, nó chi refresh các bean trong file config do đó các bean được tạo lúc runtime sẽ biến mất. Hay một lý do khác là việc nạp controller lúc runtime là việc không khả thi ? Mình đã search nhiều bài về vấn đề này nhưng vẫn tìm thấy câu trả thời thích hợp. Hi vọng ai đó có thể giúp mình

1 Like

Gemini là phần mềm công ty yêu cầu hay là do bạn chọn.

do mình chọn bạn ạ, do nó có hỗ trợ spring

mấy cái này chắc lên stack hỏi mới ra được ở đây ít cao thủ về java lắm , có ông tây joe gì đó hỏi ổng thử nghe nói ổng trùm java…

83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?