后端简易实验框架

引子

后端开发时,常常需要启动应用,将应用中所需的 bean 实例化并注入依赖 OK,而后验证一些新功能。一般的做法是,启动应用后,通过工具或 Curl 命令发送请求来触发 API 接口。有时,要验证的功能不一定通过 API 接口透漏出去,而是内部的业务逻辑。此时,要验证这些业务逻辑,不得不额外开发一些接口来触发调用。这样不够经济。

可以采用一些方法,在 Spring 容器正常启动,且将 bean 实例化并注入依赖 OK 后,自动运行一些实验代码,在实验代码里调用所要验证的服务业务逻辑。

实验框架

定义实验接口

定义实验接口: IExperiment.java

public interface IExperiment {
    void test();
}

编写一个实验类

InsertOrderExperiment.java

@Component
public class InsertOrderExperiment implements IExperiment {

    private static Log log = LogFactory.getLog(InsertOrderExperiment.class);

    @Resource
    OrderMapper orderMapper;

    @Override
    public void test() {

        OrderDO orderDO = new OrderDO();
        orderDO.setOrderNo("E202009010000001234000003");
        orderDO.setUserId(123245L);
        orderDO.setShopId(654321L);
        orderDO.setState(1);
        orderDO.setDeliveryType(DeliveryType.express.getCode());
        orderDO.setPrice(100L);
        orderDO.setPayWay(PayWay.wxpay.getCode());
        orderDO.setBookTime(1609556430L);
        Map map = new HashMap<>();
        map.put("expressFee", 10L);
        orderDO.setExtend(JSON.toJSONString(map));
        Integer insertId = orderMapper.insert(orderDO);
        log.info("Order InsertId: " + insertId);


    }
}

自动加载实验

Experiments.java


@Component
public class Experiments implements ApplicationListener<ContextRefreshedEvent>, ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        doExperiments();
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    private void doExperiments() {
        Map<String, IExperiment> experiments = applicationContext.getBeansOfType(IExperiment.class);
        experiments.forEach(
                (key, value) -> {
                    value.test();
                }
        );
    }
}


ContextRefreshedEvent原理

为什么实现了 ApplicationListener<ContextRefreshedEvent> 会在 context freshed 之后自动调用 onApplicationEvent 方法呢?

ContextRefreshedEvent发布

在 AbstractApplicationContext.java 的 refresh 方法中调用了 finishRefresh 方法:


        protected void finishRefresh() {
		// Initialize lifecycle processor for this context.
		initLifecycleProcessor();

		// Propagate refresh to lifecycle processor first.
		getLifecycleProcessor().onRefresh();

		// Publish the final event.
		publishEvent(new ContextRefreshedEvent(this));

		// Participate in LiveBeansView MBean, if active.
		LiveBeansView.registerApplicationContext(this);
	}

        protected void publishEvent(Object event, ResolvableType eventType) {
		Assert.notNull(event, "Event must not be null");
		if (logger.isTraceEnabled()) {
			logger.trace("Publishing event in " + getDisplayName() + ": " + event);
		}

		// Decorate event as an ApplicationEvent if necessary
		ApplicationEvent applicationEvent;
		if (event instanceof ApplicationEvent) {
			applicationEvent = (ApplicationEvent) event;
		}
		else {
			applicationEvent = new PayloadApplicationEvent<Object>(this, event);
			if (eventType == null) {
				eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();
			}
		}

		// Multicast right now if possible - or lazily once the multicaster is initialized
		if (this.earlyApplicationEvents != null) {
			this.earlyApplicationEvents.add(applicationEvent);
		}
		else {
			getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
		}

		// Publish event via parent context as well...
		if (this.parent != null) {
			if (this.parent instanceof AbstractApplicationContext) {
				((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
			}
			else {
				this.parent.publishEvent(event);
			}
		}
	}


触发监听器


        @Override
	public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			Executor executor = getTaskExecutor();
			if (executor != null) {
				executor.execute(new Runnable() {
					@Override
					public void run() {
						invokeListener(listener, event);
					}
				});
			}
			else {
				invokeListener(listener, event);
			}
		}
	}

        private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
			listener.onApplicationEvent(event);    // 调用 onApplicationEvent 方法
		}
		catch (ClassCastException ex) {
			// code for handling exception
		}
	}


posted @ 2021-01-04 22:13  琴水玉  阅读(415)  评论(0编辑  收藏  举报