Skip to content

About

基于Springboot动态注册Bean

Resources

Stars

0 stars

Watchers

1 watching

Forks

Latest commit

 

History

8 Commits

Folders and files

Repository files navigation

springboot-dynamic-register-bean

为什么要动态注册Bean? 在大部分业务系统开发中,都是基于Spring框架开发,由于Spring默认会扫描@Service、@Component等注解的Class注册到IoC容器中,但是这种注册是静态写死的,很多场景下需要基于条件注册Bean,或者需要在运行时动态注册Bean。比较经典的场景就是:

  • 多种数据源,通过配置动态注册对应的数据源Class。
  • 桥接模式的实现,在桥接模式中,Abstraction抽象角色注入的是Implemention实现接口,由于注入的是接口,只能在运行期间通过参数动态注入Implemention的实现类,所以只能动态动态注册实现。
  • 多环境加载不同Bean,很多中间件比如RocketMQ有开源版和商业版,通常在开发与测试环境使用的是开源版本,在生产环境使用商业版本。而开源版与商业版由于有不同,通过会通过不同Class来实现,所以需要动态注册到IoC容器中。

在Spring框架内使用桥接模式实现动态支付:

@Controller
@RequestMapping("v1/pay")
public class PayController {

    @Autowired
    private PayChannelFactory payChannelFactory;
  
    /**
     * 桥接模式实现
     * @param uId       用户ID
     * @param amount    订单金额
     * @param channel   支付渠道:weixin/alipay
     * @param mode      支付方式:h5/scanface
     * @return
     */
    @ResponseBody
    @PostMapping("dopay")
    public String pay(@RequestParam String uId, @RequestParam BigDecimal amount, @RequestParam String channel, @RequestParam String mode) {
        return payChannelFactory.getChannelService(channel, mode).doPay(uId, amount);
    }
}
@Component
public class PayChannelFactory {

    private ApplicationContext context;

    private static Map<String, Class> channelMap = new HashMap<>();

    static {
        Reflections reflections = new Reflections("com.leo.springboot.dynamic.register.bean.bridgepattern.channel");
        reflections.getSubTypesOf(AbstractChannelService.class).stream().forEach(item -> {
            Name annotation = item.getDeclaredAnnotation(Name.class);
            channelMap.put(annotation.value(), item);
        });
    }

    public PayChannelFactory(ApplicationContext applicationContext) {
        this.context = applicationContext;
    }

    /**
     * 简单工厂获取对应支付渠道对象
     * @param channel
     * @param mode
     * @return
     */
    public AbstractChannelService getChannelService(String channel, String mode) {
        //简单工厂获取支付方式对象
        PayModeService modeService = PayModeFactory.getPayMode(mode);
        String beanName = new StringBuffer(channel).append(mode).toString();

        //动态注册AbstractChannelService&并返回对应的Bean
        AbstractChannelService channelService = (AbstractChannelService) ManualRegistBeanUtil.registerBean
                ((ConfigurableApplicationContext) context, beanName, channelMap.get(channel), modeService);
        return channelService;
    }

}

About

基于Springboot动态注册Bean

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages