详解Java事件编程的使用

Java事件编程

当前在线网店很多,很涉及商品管理和销售的问题,比如:

一,在商品库存管理的商品增加时,我们主要业务时编辑保持商品信息,

同时因商品增加而附带有一些“非主要业务”,如:

1,应商品的库存数量等更新,
2,热销产品的推广处理等

二,在商品产生订单时,我们的主要业务(对买家而言)是建立订单业务,

同时因产生订单而附带有一些不是买家关心的“非主要业务”,如:

1,库存和已售数量的更新
2,发货的准备处理事宜
3,物流的处理事宜

非主要业务我们可以让程序使用多线程异步执行,这样主要业务和非主要业务就完全解耦,
主要业务可以快速完成响应,非主要业务多线程异步执行,提高程序的吞吐量即高处理能力;
同时使用自定义的线程池,有比较好的把控;

下面我们就根据上面的场景需求编写一个例子,看看在Springboot中如何Java的事件编程,
对比一下常规逻辑的编程,和采用Java事件编程的差异。

//常规逻辑的编程
@GetMapping(value="/add")
@ResponseBody
public String addProduct(Product product) {

	//增加产品

	//应商品的库存数量等更新

	//是否为热销产品的推广处理

	//其它处理

	return "产品增加完成";
}

主要业务是增加产品信息,但是可能会因产品库存或热销产品等其它问题处理而收到影响,
耦合性比较强,如果以后还有其它需求又需要改动程序,问题暴露出来了;

同样,下单也是一样问题,主要业务是买家下单时建立订单,

//常规逻辑的编程
@GetMapping(value="/createOrder")
@ResponseBody
public String createProductOrder(ProductOrder productOrder) {

	//收集产品订单信息,保持建立订单

	//库存和已售数量的更新

	//订单备货处理

	//物流处理

	return "产品订单建立完成";
}

对买家来说,主要业务是产品下单,后续的库存和已售数量的更新,备货处理,物流处理等不是买家关心的,但是可能会因这些问题处理而受到影响,可能下单失败,耦合性比较强,如果以后还有其它需求又需要改动程序,同样问题暴露出来了;

那怎么建立主次分明的处理逻辑呢,这里用Java事件编程就很好处理这些问题,主次分明,完全解耦,程序改动比较小,程序吞吐量也强,
相关注释在程序非常清楚,所以主要看代码吧;

三,使用Java事件编程,Springboot例子

1,项目结构如下图

2,自定义异步执行使用的线程池,参考如下代码:

package com.shenzhennba.pro06.eventSource.asyncConfig;

import java.io.Serializable;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

/**
 * 配置异步任务线程池,然后注入springIOC容器,提供异步任务使用;
 * @author shenzhenNBA
 * @since 2021/06/14
 */
@Configuration
public class AsyncThreadPoolConfig implements Serializable {

	private static final long serialVersionUID = 20210606010060L;

	private static final int MAX_POOL_SIZE = 100;
    private static final int CORE_POOL_SIZE = 20;
    private static final String THREAD_NAME_PREFIX = "async_task_";

    //创建线程池,并指定实例名称
    @Bean("asyncTaskExecutor")
    public AsyncTaskExecutor asyncTaskExecutor() {
		ThreadPoolTaskExecutor asyncTaskExecutor = new ThreadPoolTaskExecutor();
		asyncTaskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
		asyncTaskExecutor.setCorePoolSize(CORE_POOL_SIZE);
		asyncTaskExecutor.setThreadNamePrefix(THREAD_NAME_PREFIX);
		asyncTaskExecutor.initialize();
		return asyncTaskExecutor;
	}

}

3,定义业务相关需要的实体或model,参考如下代码:

package com.shenzhennba.pro06.eventSource.model;

import java.io.Serializable;

import org.apache.commons.lang.builder.ReflectionToStringBuilder;

/**
 * 商品实体类
 * @author shenzhenNBA
 * @since 2021/06/14
 */
public class Product implements Serializable {

	private static final long serialVersionUID = 20210606010010L;
	private String categoryCode;//商品类别代码
	private String productName;	//商品名称
	private String productCode;	//商品代码
	private Double price;		//商品单价
	private Long addNum;		//增加数量
	private Long isHotSell=0L;	//是否促销,0=不是,1=是
	private String createTime;	//商品入库时间

	public Product() {
		super();
	}

	//getter / setter 省略...

	@Override
    public String toString() {
        return ReflectionToStringBuilder.toString(this);
    }

}
package com.shenzhennba.pro06.eventSource.model;

import java.io.Serializable;

import org.apache.commons.lang.builder.ReflectionToStringBuilder;

/**
 * 商品的数量和积分相关实体类
 * @author shenzhenNBA
 * @since 2021/06/14
 */
public class ProductNumber implements Serializable {
	private static final long serialVersionUID = 20210606010020L;
	private String productCode;	//商品代码
	private Long storageNum;	//商品库存
	private Long soldNum;		//已收数量
	private Long scoreNum;		//单个购买赠送积分数

	public ProductNumber() {
		super();
	}

	// getter / setter 省略...

	@Override
    public String toString() {
        return ReflectionToStringBuilder.toString(this);
    }
}
package com.shenzhennba.pro06.eventSource.model;

import java.io.Serializable;
import java.util.Date;

import org.apache.commons.lang.builder.ReflectionToStringBuilder;

/**
 * 商品订单实体类
 * @author shenzhenNBA
 * @since 2021/06/14
 */
public class ProductOrder implements Serializable {

	private static final long serialVersionUID = 20210606010030L;
	private String orderCode;	//订单代码
	private String productName;	//商品名称
	private String productCode;	//商品代码
	private Double price;		//商品单价
	private String createTime;	//下单时间
	private Long scoreNum;		//购买赠送积分数
	private Long buyNum;		//订单购买数量
	private Integer isPrepared = 0;//发货准备状态,默认0=未准备好,1=已准备好
	private Integer isSendOut = 0;//是否已发货,默认0=未发,1=已发
	private String warehouseCode ;//发货仓库代码
	private String senderCode ;	//物流处理商家代码
	private Date planSendTime ;	//计划发货时间
	private Date recieveTime ;	//收货时间
	private String recieveAddress;//收货地址

	public ProductOrder() {
		super();
	}

	// getter / setter 省略...

	@Override
    public String toString() {
        return ReflectionToStringBuilder.toString(this);
    }

4,定义业务的相关Java事件源,主要是编写继承 
org.springframework.context.ApplicationEvent 的类对象,
以及定义各事件相关的对象
,比如,商品对象,或订单对象,事件源的目的是存储事件相关的目标信息,参考如下代码:

package com.shenzhennba.pro06.eventSource.eventSource;

import java.io.Serializable;

import org.springframework.context.ApplicationEvent;

import com.shenzhennba.pro06.eventSource.model.Product;

/**
 * 商品添加事件源的定义,目的是用于存储事件的目标信息,即添加的商品对象;
 * 注意:是继承ApplicationEvent的普通Bean对象
 * @author shenzhenNBA
 * @since 2021/06/14
 */
public class ProductEventSource
	extends ApplicationEvent implements Serializable {

	private static final long serialVersionUID = 20210606010040L;

	//目的是用于存储事件的目标信息,即添加的商品对象
	private Product product;

	public ProductEventSource(Product source) {
		super(source);
		this.product = source;
	}

	public Product getProduct() {
		return product;
	}

	public void setProduct(Product product) {
		this.product = product;
	}

}
package com.shenzhennba.pro06.eventSource.eventSource;

import java.io.Serializable;

import org.springframework.context.ApplicationEvent;

import com.shenzhennba.pro06.eventSource.model.ProductOrder;

/**
 * 商品订单建立事件源的定义,目的是用于存储事件的目标信息,即建立的商品订单对象;
 * 注意:是继承ApplicationEvent的普通Bean对象
 * @author shenzhenNBA
 * @since 2021/06/14
 */
public class ProductOrderEventSource
	extends ApplicationEvent implements Serializable{

	private static final long serialVersionUID = 20210606010050L;

	//目的是用于存储事件的目标信息,即建立的商品订单对象
	private ProductOrder productOrder;

	public ProductOrderEventSource(ProductOrder source) {
		super(source);
		this.productOrder = source;
	}

	public ProductOrder getProductOrder() {
		return productOrder;
	}

	public void setProductOrder(ProductOrder productOrder) {
		this.productOrder = productOrder;
	}	

}

5,定义各种监听器和相关业务处理逻辑,并将其纳入SpringIOC容器管理
监听类方法加注解 @EventListener 使之变为一个监听器,加注解@Async("asyncTaskExecutor") 指定监听器异步执行,同时指定异步执行使用的线程池,加注解  @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
指定监听器事务的阶段, 一般为业务数据入库之后,再异步执行方法;加注解 @Order(1) 指定同一事件有多个监听器时执行顺序,值越小,执行顺序优先,类前加 @Component 注解,把各监听器交给SpringIOC容器管理,参考如下代码:

package com.shenzhennba.pro06.eventSource.listener;

import java.io.Serializable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;

import com.shenzhennba.pro06.eventSource.eventSource.ProductEventSource;
import com.shenzhennba.pro06.eventSource.eventSource.ProductOrderEventSource;
import com.shenzhennba.pro06.eventSource.model.ProductOrder;

/**
 * 定义各种事件监听器和其各自的业务处理逻辑,
 * 然后注入springIOC容器,并监听相应的事件,只要触发相应事件则用对应监听器处理;
 * 注意:各种监听器还是由spring容器管理
 * @author shenzhenNBA
 * @since 2021/06/14
 */

@Component
public class EventListeners implements Serializable {

	private static Logger logger = LoggerFactory.getLogger(EventListeners.class);

	private static final long serialVersionUID = 20210606010070L;

	//指定异步执行监听器,同时使用的自定义的异步线程池
	@Async("asyncTaskExecutor")
	//指定监听事务的阶段,多数情况下的业务操作会涉及数据库事务,确保主业务的数据入库后,再进行本方法的异步操作
	@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
	//注解定义本方法为一个监听器,处理因增加产品而引发的事件中有关产品库存等数量相关信息
	@EventListener
	//指定当同一个事件有多个监听器时执行顺序,值越小,执行顺序优先
	@Order(1)
	public void updateProductReferNumListener(ProductEventSource pes) {
		if (null == pes || null == pes.getProduct()) {
			return;
		}
		logger.info("");
		logger.info("产品增加事件监听器 1, 事件关联信息:{}", pes.getProduct());
		logger.info("");
		// TODO 有关产品数量的库存等更新操作
	}

	//指定异步执行监听器,同时使用的自定义的异步线程池
	@Async("asyncTaskExecutor")
	//指定监听事务的阶段,多数情况下的业务操作会涉及数据库事务,确保主业务的数据入库后,再进行本方法的异步操作
	@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
	//注解定义本方法为一个监听器,处理因增加产品而引发的事件中有关热销产品的相关促销事宜
	@EventListener
	//指定当同一个事件有多个监听器时执行顺序,值越小,执行顺序优先
	@Order(5)
	public void handleHotSellProductListener(ProductEventSource pes) {
		if (null == pes || null == pes.getProduct()) {
			return;
		}
		logger.info("");
		logger.info("产品增加事件监听器 2, 事件关联信息:{}", pes.getProduct());
		logger.info("");
		if (null == pes.getProduct()) {
			return;
		}
		if (1 != pes.getProduct().getIsHotSell().intValue()) {
			logger.info("产品增加事件监听器 2, 非热销产品");
			return;
		}
		// TODO 有关热销产品的相关促销事宜的处理
	}

	//指定异步执行监听器,同时使用的自定义的异步线程池
	@Async("asyncTaskExecutor")
	//指定监听事务的阶段,多数情况下的业务操作会涉及数据库事务,确保主业务的数据入库后,再进行本方法的异步操作
	@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
	//注解定义本方法为一个监听器,处理因产品产生订单而引发的事件中有关产品库存和已售数量相关信息
	@EventListener
	//指定当同一个事件有多个监听器时执行顺序,值越小,执行顺序优先
	@Order(1)
	public void updateProductReferNumListener(ProductOrderEventSource poes) {
		if (null == poes || null == poes.getProductOrder()) {
			return;
		}
		logger.info("");
		logger.info("产品产生订单事件监听器 1, 事件关联信息:{}", poes.getProductOrder());
		logger.info("");
		// TODO 有关产品数量的库存和已售数量更新操作
	}

	//指定异步执行监听器,同时使用的自定义的异步线程池
	@Async("asyncTaskExecutor")
	//指定监听事务的阶段,多数情况下的业务操作会涉及数据库事务,确保主业务的数据入库后,再进行本方法的异步操作
	@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
	//注解定义本方法为一个监听器,处理因产品产生订单而引发的事件中有关产品发货的相关准备和处理事宜
	@EventListener
	//指定当同一个事件有多个监听器时执行顺序,值越小,执行顺序优先
	@Order(5)
	public void prepareSendProductListener(ProductOrderEventSource poes) {
		if (null == poes || null == poes.getProductOrder()) {
			return;
		}
		ProductOrder proOrder = poes.getProductOrder();
		logger.info("");
		logger.info("产品产生订单事件监听器 2, 事件关联信息:{}", proOrder);
		logger.info("");
		if (null != proOrder.getIsSendOut() &&
				1 == proOrder.getIsSendOut()) {
			logger.info("产品产生订单事件监听器 2, 订单已经发货,不用再处理");
			return;
		}
		if (null != proOrder.getIsPrepared() &&
				1 == proOrder.getIsPrepared()) {
			logger.info("产品产生订单事件监听器 2, 订单发货准备已经完成,不用再处理");
			return;
		}
		// TODO 有关产品订单发货的事宜
	}

	//指定异步执行监听器,同时使用的自定义的异步线程池
	@Async("asyncTaskExecutor")
	//指定监听事务的阶段,多数情况下的业务操作会涉及数据库事务,确保主业务的数据入库后,再进行本方法的异步操作
	@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
	//注解定义本方法为一个监听器,处理因产品产生订单而引发的事件中有关产品发货的物流事宜
	@EventListener
	//指定当同一个事件有多个监听器时执行顺序,值越小,执行顺序优先
	@Order(10)
	public void sendProductListener(ProductOrderEventSource poes) {
		if (null == poes || null == poes.getProductOrder()) {
			return;
		}
		ProductOrder proOrder = poes.getProductOrder();
		logger.info("");
		logger.info("产品产生订单事件监听器 3, 事件关联信息:{}", poes.getProductOrder());
		logger.info("");
		if (null != proOrder.getIsSendOut() &&
				1 == proOrder.getIsSendOut()) {
			logger.info("产品产生订单事件监听器 3, 订单已经发货,不用再处理");
			return;
		}
		if (null != proOrder.getIsPrepared() &&
				0 == proOrder.getIsPrepared().intValue()) {
			logger.info("产品产生订单事件监听器 3, 订单发货准备还未完成,先等备好货,再处理物流事宜");
		}
		// TODO 有关产品订单的物流事宜
	}	

}

6,定义业务接口,参考如下代码:

package com.shenzhennba.pro06.eventSource.service;

import java.io.Serializable;

import com.shenzhennba.pro06.eventSource.model.Product;

/**
 * 商品service层接口
 * @author shenzhenNBA
 * @since 2021/06/14
 */
public interface ProductService extends Serializable {

	/**
	 * 增加产品
	 * @author shenzhenNBA
	 * @param product
	 * @return
	 */
	Integer addProduct(Product product);

	/**
	 * 根据产品代码查询产品记录
	 * @author shenzhenNBA
	 * @param product
	 * @return
	 */
	Product getProduct(String productCode);

}
package com.shenzhennba.pro06.eventSource.service;

import java.io.Serializable;

import com.shenzhennba.pro06.eventSource.model.Product;
import com.shenzhennba.pro06.eventSource.model.ProductOrder;

/**
 * 商品订单service层接口
 * @author shenzhenNBA
 * @since 2021/06/14
 */
public interface ProductOrderService extends Serializable {

	/**
	 * 建立产品订单
	 * @author shenzhenNBA
	 * @param product
	 * @return
	 */
	Integer createProductOrder(ProductOrder productOrder);

	/**
	 * 根据产品订单代码查询产品订单记录
	 * @author shenzhenNBA
	 * @param product
	 * @return
	 */
	Product getProductOrder(String productOrderCode);

}

7,实现所定义的业务接口,参考如下代码:

package com.shenzhennba.pro06.eventSource.service.impl;

import org.springframework.stereotype.Service;

import com.shenzhennba.pro06.eventSource.model.Product;
import com.shenzhennba.pro06.eventSource.service.ProductService;

/**
 * 商品service接口实现类
 * @author shenzhenNBA
 * @since 2021/06/14
 */

@Service
public class ProductServiceImpl implements ProductService {

	private static final long serialVersionUID = 20210606010090L;

	/**
	 * 增加产品
	 */
	@Override
	public Integer addProduct(Product product) {
		// TODO more biz handle here
		return null;
	}

	/**
	 * 根据产品代码查询产品记录
	 */
	@Override
	public Product getProduct(String productCode) {
		// TODO more biz handle here
		return null;
	}

}
package com.shenzhennba.pro06.eventSource.service.impl;

import org.springframework.stereotype.Service;

import com.shenzhennba.pro06.eventSource.model.Product;
import com.shenzhennba.pro06.eventSource.model.ProductOrder;
import com.shenzhennba.pro06.eventSource.service.ProductOrderService;

/**
 * 商品订单service接口实现类
 * @author shenzhenNBA
 * @since 2021/06/14
 */
@Service
public class ProductOrderServiceImpl implements ProductOrderService {

	private static final long serialVersionUID = 20210606010100L;

	/**
	 * 建立产品订单
	 */
	@Override
	public Integer createProductOrder(ProductOrder productOrder) {
		// TODO more biz handle here
		return null;
	}

	/**
	 * 根据产品订单代码查询产品订单记录
	 */
	@Override
	public Product getProductOrder(String productOrderCode) {
		// TODO more biz handle here
		return null;
	}
}

8,在对外API(即controller层)接口中处理业务,同时使用 org.springframework.context.ApplicationEventPublisher 
实例发布相应的Java事件
,参考如下代码:

package com.shenzhennba.pro06.eventSource.controller;

import java.io.Serializable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.shenzhennba.pro06.eventSource.eventSource.ProductEventSource;
import com.shenzhennba.pro06.eventSource.listener.EventListeners;
import com.shenzhennba.pro06.eventSource.model.Product;
import com.shenzhennba.pro06.eventSource.service.ProductService;

/**
 * 使用Java事件编程方式实现,
 * 产品对外API接口,
 * @author shenzhenNBA
 * @since 2021/06/14
 */

@Controller
@RequestMapping("/product")
public class ProductController implements Serializable {

	private static Logger logger = LoggerFactory.getLogger(EventListeners.class);
	private static final long serialVersionUID = 20210606010080L;

	//Spring的事件发布器
	@Autowired
	private ApplicationEventPublisher appEventPublisher;

	@Autowired
	private ProductService productService;

	@GetMapping(value="/add")
	@ResponseBody
	public String addProduct(Product product) {
		logger.info("controller ProductController.addProduct(), add product");

		//主要业务,增加产品
		productService.addProduct(product);

		//?categoryCode=c01&productName=productName001&productCode=pc001&price=20.5&addNum=2&isHotSell=1
		//因增加产品而发布与其相关的事件,处理与之相关的非主要业务,
		//首先执行EventListeners.updateProductReferNumListener()监听器,处理相关业务
		//其次执行EventListeners.handleHotSellProductListener()监听器,处理相关业务
		//应用Spring事件,可以让非主要业务和主要业务解耦,使用异步处理非主要业务,让程序吞吐量即处理能力更强
		appEventPublisher.publishEvent(new ProductEventSource(product));

		return "产品增加完成";
	}
}
package com.shenzhennba.pro06.eventSource.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.shenzhennba.pro06.eventSource.eventSource.ProductOrderEventSource;
import com.shenzhennba.pro06.eventSource.listener.EventListeners;
import com.shenzhennba.pro06.eventSource.model.ProductOrder;
import com.shenzhennba.pro06.eventSource.service.ProductOrderService;

/**
 * 使用Java事件编程方式实现,
 * 产品订单对外API接口,
 * @author shenzhenNBA
 * @since 2021/06/14
 */
@Controller
@RequestMapping("/productOrder")
public class ProductOrderController {

	private static Logger logger = LoggerFactory.getLogger(EventListeners.class);
	private static final long serialVersionUID = 20210606010080L;

	//Spring的事件发布器
	@Autowired
	private ApplicationEventPublisher appEventPublisher;

	@Autowired
	private ProductOrderService productOrderService;

	@GetMapping(value="/createOrder")
	@ResponseBody
	public String createProductOrder(ProductOrder productOrder) {
		logger.info("controller ProductOrderController.createProductOrder(), create product order");

		//主要业务,增加产品
		productOrderService.createProductOrder(productOrder);

		//?productCode=pc001&productName=productName001&price=20.5&buyNum=3&
		//scoreNum=0&warehouseCode=house01&recieveAddress=add001
		//因增加产品而发布与其相关的事件,处理与之相关的非主要业务,
		//首先执行EventListeners.updateProductReferNumListener()监听器,处理相关业务
		//其次执行EventListeners.prepareSendProductListener()监听器,处理相关业务
		//再次执行EventListeners.sendProductListener()监听器,处理相关业务
		//应用Spring事件,可以让非主要业务和主要业务解耦,使用异步处理非主要业务,让程序吞吐量即处理能力更强
		appEventPublisher.publishEvent(new ProductOrderEventSource(productOrder));

		return "产品订单建立完成";
	}
}

9,在启动类中启用异步处理功能,参考如下代码:

package com.shenzhennba.pro06.eventSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.scheduling.annotation.EnableAsync;

//启动异步处理功能
@EnableAsync
//启动springboot但不用排除DB功能
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class EventSourceApp {

	private static Logger logger = LoggerFactory.getLogger(EventSourceApp.class);

	public static void main(String[] args) {
		SpringApplication.run(EventSourceApp.class, args);

		logger.info("");
		logger.info("----------- Server is running... -----------");
		logger.info("");
	}

}

10,工程配置文件,参考如下代码:

spring.application.name=eventSourceApp01

server.port=8080

11,启动工程,模拟增加一个商品,相关截图如下,可见商品增加事件已经触发,

http://localhost:8080/product/add?categoryCode=c01&productName=productName001&productCode=pc001&price=20.5&addNum=2&isHotSell=1

12,启动工程,模拟建立一个订单,相关截图如下,可见订单相关事件已经触发

http://localhost:8080/productOrder/createOrder?productCode=pc001&productName=productName001&price=20.5&buyNum=3&scoreNum=0&wa
rehouseCode=house01&recieveAddress=add001

13,工程 pom.xml 文件,参见如下代码:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
	https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.5.0</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.shenzhennba.pro06</groupId>
	<artifactId>eventSource</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>eventSource</name>
	<description>Demo event source</description>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-rest</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<!-- apache的依赖 -->
		<dependency>
		    <groupId>commons-lang</groupId>
		    <artifactId>commons-lang</artifactId>
		    <version>2.6</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

后记

Java的事件编程可以应用到很多的地方,合理应用可以使代码主次业务分清,业务解耦,提高程序吞吐量,但需要开发人员掌握更多的知识,只要学习应该不是很难,习惯一种编程逻辑多一种开发思路,欢迎拍砖讨论...

到此这篇关于详解Java事件编程的使用的文章就介绍到这了,更多相关Java事件编程内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java编程GUI中的事件绑定代码示例

    程序绑定的概念: 绑定指的是一个方法的调用与方法所在的类(方法主体)关联起来.对java来说,绑定分为静态绑定和动态绑定:或者叫做前期绑定和后期绑定 静态绑定: 在程序执行前方法已经被绑定,此时由编译器或其它连接程序实现.例如:C. 针对java简单的可以理解为程序编译期的绑定:这里特别说明一点,java当中的方法只有final,static,private和构造方法是前期绑定 动态绑定 后期绑定:在运行时根据具体对象的类型进行绑定. 若一种语言实现了后期绑定,同时必须提供一些机制,可在运行期间

  • Java图形化编程中的键盘事件设计简介

    键盘事件的事件源一般丐组件相关,当一个组件处于激活状态时,按下.释放或敲击键盘上的某个键时就会发生键盘事件.键盘事件的接口是KeyListener,注册键盘事件监视器的方法是addKeyListener(监视器).实现KeyListener接口有3个: keyPressed(KeyEvent e):键盘上某个键被按下: keyReleased(KeyEvent e):键盘上某个键被按下,又释放: keyTyped(KeyEvent e):keyPressed和keyReleased两个方法的组合

  • 详解Java图形化编程中的鼠标事件设计

    鼠标事件的事件源往往与容器相关,当鼠标进入容器.离开容器,或者在容器中单击鼠标.拖动鼠标时都会发生鼠标事件.java语言为处理鼠标事件提供两个接口:MouseListener,MouseMotionListener接口. MouseListener接口 MouseListener接口能处理5种鼠标事件:按下鼠标,释放鼠标,点击鼠标.鼠标进入.鼠标退出.相应的方法有: (1) getX():鼠标的X坐标 (2) getY():鼠标的Y坐标 (3) getModifiers():获取鼠标的左键或右键

  • 详解Java事件编程的使用

    Java事件编程 当前在线网店很多,很涉及商品管理和销售的问题,比如: 一,在商品库存管理的商品增加时,我们主要业务时编辑保持商品信息, 同时因商品增加而附带有一些"非主要业务",如: 1,应商品的库存数量等更新, 2,热销产品的推广处理等 二,在商品产生订单时,我们的主要业务(对买家而言)是建立订单业务, 同时因产生订单而附带有一些不是买家关心的"非主要业务",如: 1,库存和已售数量的更新 2,发货的准备处理事宜 3,物流的处理事宜 非主要业务我们可以让程序使用

  • 详解JAVA 函数式编程

    1.函数式接口 1.1概念: java中有且只有一个抽象方法的接口. 1.2格式: 修饰符 interface 接口名称 { public abstract 返回值类型 方法名称(可选参数信息); // 其他非抽象方法内容 } //或者 public interface MyFunctionalInterface { void myMethod(); } 1.3@FunctionalInterface注解: 与 @Override 注解的作用类似,Java 8中专门为函数式接口引入了一个新的注解

  • 详解Java函数式编程和lambda表达式

    为什么要使用函数式编程 函数式编程更多时候是一种编程的思维方式,是种方法论.函数式与命令式编程的区别主要在于:函数式编程是告诉代码你要做什么,而命令式编程则是告诉代码要怎么做.说白了,函数式编程是基于某种语法或调用API去进行编程.例如,我们现在需要从一组数字中,找出最小的那个数字,若使用用命令式编程实现这个需求的话,那么所编写的代码如下: public static void main(String[] args) { int[] nums = new int[]{1, 2, 3, 4, 5,

  • 详解Java网络编程

    一.网络编程 1.1.概述 1.计算机网络是通过传输介质.通信设施和网络通信协议,把分散在不同地点的计算机设备互连起来,实现资源共享和数据传输的系统.网络编程就就是编写程序使联网的两个(或多个)设备(例如计算机)之间进行数据传输.Java语言对网络编程提供了良好的支持,通过其提供的接口我们可以很方便地进行网络编程. 2.Java是 Internet 上的语言,它从语言级上提供了对网络应用程 序的支持,程序员能够很容易开发常见的网络应用程序. 3.Java提供的网络类库,可以实现无痛的网络连接,联

  • 详解Java并发编程基础之volatile

    目录 一.volatile的定义和实现原理 1.Java并发模型采用的方式 2.volatile的定义 3.volatile的底层实现原理 二.volatile的内存语义 1.volatile的特性 2.volatile写-读建立的happens-before关系 3.volatile的写/读内存语义 三.volatile内存语义的实现 1.volatile重排序规则 2.内存屏障 3.内存屏障示例 四.volatile与死循环问题 五.volatile对于复合操作非原子性问题 一.volati

  • 详解Java并发编程之原子类

    目录 原子数组 AtomicIntegerArray 原子更新器 AtomicIntegerFieldUpdater 原子累加器 LongAdder 原子数组 原子数组有AtomicIntegerArray.AtomicLongArray.AtomicReferenceArray,主要是用来对数组中的某个元素进行原子操作.三个类的方法基本类似,这里只介绍一下AtomicIntegerArray的方法. AtomicIntegerArray 两个构造方法,第一个构造方法传入数组长度初始化一个所有值

  • 详解java并发编程(2) --Synchronized与Volatile区别

    1 Synchronized 在多线程并发中synchronized一直是元老级别的角色.利用synchronized来实现同步具体有一下三种表现形式: 对于普通的同步方法,锁是当前实例对象. 对于静态同步方法,锁是当前类的class对象. 对于同步方法块,锁是synchronized括号里配置的对象. 当一个代码,方法或者类被synchronized修饰以后.当一个线程试图访问同步代码块的时候,它首先必须得到锁,退出或抛出异常的时候必须释放锁.那么这样做有什么好处呢? 它主要确保多个线程在同一

  • 详解Java并发编程之内置锁(synchronized)

    简介 synchronized在JDK5.0的早期版本中是重量级锁,效率很低,但从JDK6.0开始,JDK在关键字synchronized上做了大量的优化,如偏向锁.轻量级锁等,使它的效率有了很大的提升. synchronized的作用是实现线程间的同步,当多个线程都需要访问共享代码区域时,对共享代码区域进行加锁,使得每一次只能有一个线程访问共享代码区域,从而保证线程间的安全性. 因为没有显式的加锁和解锁过程,所以称之为隐式锁,也叫作内置锁.监视器锁. 如下实例,在没有使用synchronize

  • 详解Java设计模式编程中的依赖倒置原则

    定义: 高层模块不应该依赖低层模块,二者都应该依赖其抽象:抽象不应该依赖细节:细节应该依赖抽象. 问题由来:类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成.这种场景下,类A一般是高层模块,负责复杂的业务逻辑:类B和类C是低层模块,负责基本的原子操作:假如修改类A,会给程序带来不必要的风险. 解决方案:将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率.          依赖倒置原则基于这样一个事实:

  • 详解Java多线程编程中的线程同步方法

    1.多线程的同步: 1.1.同步机制: 在多线程中,可能有多个线程试图访问一个有限的资源,必须预防这种情况的发生.所以引入了同步机制:在线程使用一个资源时为其加锁,这样其他的线程便不能访问那个资源了,直到解锁后才可以访问. 1.2.共享成员变量的例子: 成员变量与局部变量: 成员变量: 如果一个变量是成员变量,那么多个线程对同一个对象的成员变量进行操作,这多个线程是共享一个成员变量的. 局部变量: 如果一个变量是局部变量,那么多个线程对同一个对象进行操作,每个线程都会有一个该局部变量的拷贝.他们

随机推荐