详解使用Spring的BeanPostProcessor优雅的实现工厂模式

最近学习Spring的源码,发现一个利器BeanPostProcessor。这个后置处理器可以在bean初始化前后对bean进行操作。我们可以在初始化的时候对自己想要的bean进行缓存,进而实现自己需要处理的逻辑。

背景

当我们需要根据类型调用接口不同实现的时候,我们可以使用工厂模式实现。下面说下博主遇到过的两次需要使用工厂的场景。

场景一:
当有一个模块,我们需要根据数据库的类型实现不同的的sql。我们此时需要定义一个接口然后每一种数据库实现不同的sql。在调用时根据当前的数据库类型调用对应的实现类。

场景二:
我们业务需要对接不同的传感器设备,但是总体业务逻辑就是获取数据,发送心跳。每一种设备的数据协议又不一样。所以需要使用工厂,根据不同的设备调用对应的实现类。

工厂模式

静态工厂

/**
 * @Description
 * @Author Singh
 * @Date 2020-07-06 21:54
 * @Version
 **/
@Service
public class HandlerService1 {

  public <T> void handle(Constant.HandlerType handlerType, T dataDO) {
    IHandler handler = null;
    if(handlerType.getType().intValue() == Constant.HandlerType.HANDLE_TYEP_1.getType()){
      handler = new Type1Handler();
    }else if(handlerType.getType().intValue() == Constant.HandlerType.HANDLE_TYEP_2.getType()){
      handler = new Type2Handler();
    }else if(handlerType.getType().intValue() == Constant.HandlerType.HANDLE_TYEP_3.getType()){
      handler = new Type3Handler();
    }else if(handlerType.getType().intValue() == Constant.HandlerType.HANDLE_TYEP_4.getType()){
      handler = new Type4Handler();
    }else{
      throw new RuntimeException("类型错误");
    }
    handler.handle(dataDO);
  }
}

动态工厂,通过class实现

/**
 * @Description
 * @Author Singh
 * @Date 2020-07-06 21:54
 * @Version
 **/
@Service
public class HandlerService2 {

  public <T,H extends IHandler> void handle(Class<H> clzz, T dataDO) throws IllegalAccessException, InstantiationException {
    IHandler handler = clzz.newInstance();
    handler.handle(dataDO);
  }

}

进入主题

BeanPostProcessor实现相同接口的不同实现bean的工厂

首先定义一个注解,后续用来标示bean的处理类型

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Handler {

  @AliasFor(annotation = Component.class)
  String value() default "";

  /**
   * 业务处理类型
   * @return
   */
  Constant.HandlerType handlerType();

}

处理类型

/**
 * @Description
 * @Author Singh
 * @Date 2020-07-06 21:25
 * @Version
 **/

public class Constant {

  public enum HandlerType{
    HANDLE_TYEP_1(1),
    HANDLE_TYEP_2(2),
    HANDLE_TYEP_3(3),
    HANDLE_TYEP_4(4);
    private Integer type;

    HandlerType(Integer type) {
      this.type = type;
    }

    public Integer getType() {
      return type;
    }

  }
}

定义接口处理

/**
 * @Description
 * @Author Singh
 * @Date 2020-07-06 21:29
 * @Version
 **/
public interface IHandler<T> {

  void handle(T data);

}

BeanPostProcessor实现对bean后置处理。通过注解的类型缓存bean对象。

/**
 * @Description
 * @Author Singh
 * @Date 2020-07-06 21:29
 * @Version
 **/
@Service
public class HandleService implements BeanPostProcessor {

  private Map<Integer,IHandler> reportDataHandlerMap = new ConcurrentHashMap<>();

  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    if(bean instanceof IHandler){
      Handler[] reportHandlers = bean.getClass().getAnnotationsByType(Handler.class);
      if(reportHandlers == null || reportHandlers.length == 0){
        return bean;
      }
      Handler reportHandler = reportHandlers[0];
      reportDataHandlerMap.put(reportHandler.handlerType().getType(), (IHandler) bean);
    }
    return bean;
  }

  public <T> void handle(Constant.HandlerType handlerType, T dataDO) {
    IHandler reportDataHandler = reportDataHandlerMap.get(handlerType.getType());
    if(reportDataHandler == null){
      throw new RuntimeException("类型错误");
    }
    reportDataHandler.handle(dataDO);
  }
}

自定义处理器实现,每一种实现一次。

/**
 * @Description
 * @Author Singh
 * @Date 2020-07-06 21:32
 * @Version
 **/
@Handler(handlerType = Constant.HandlerType.HANDLE_TYEP_1 )
public class Type1Handler implements IHandler<String>{

  @Override
  public void handle(String data) {

  }
}

到此这篇关于详解使用Spring的BeanPostProcessor优雅的实现工厂模式的文章就介绍到这了,更多相关Spring BeanPostProcessor 工厂模式内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 如何基于Spring使用工厂模式实现程序解耦

    这篇文章主要介绍了如何基于Spring使用工厂模式实现程序解耦,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1. 啥是耦合.解耦? 既然是程序解耦,那我们必须要先知道啥是耦合,耦合简单来说就是程序的依赖关系,而依赖关系则主要包括 1. 类之间的依赖 2. 方法间的依赖 比如下面这段代码: public class A{ public int i; } public class B{ public void put(A a){ System.o

  • 详解使用Spring的BeanPostProcessor优雅的实现工厂模式

    最近学习Spring的源码,发现一个利器BeanPostProcessor.这个后置处理器可以在bean初始化前后对bean进行操作.我们可以在初始化的时候对自己想要的bean进行缓存,进而实现自己需要处理的逻辑. 背景 当我们需要根据类型调用接口不同实现的时候,我们可以使用工厂模式实现.下面说下博主遇到过的两次需要使用工厂的场景. 场景一: 当有一个模块,我们需要根据数据库的类型实现不同的的sql.我们此时需要定义一个接口然后每一种数据库实现不同的sql.在调用时根据当前的数据库类型调用对应的

  • 详解基于Spring Data的领域事件发布

    领域事件发布是一个领域对象为了让其它对象知道自己已经处理完成某个操作时发出的一个通知,事件发布力求从代码层面让自身对象与外部对象解耦,并减少技术代码入侵. 一. 手动发布事件 // 实体定义 @Entity public class Department implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer departmentId; @Enumerate

  • 详解在Spring MVC或Spring Boot中使用Filter打印请求参数问题

    使用Spring MVC或Spring Boot中打印或记录日志一般使用AOP记录Request请求和Response响应参数,在不使用AOP的前提下,如果在Filter中打印日志,在打印或消费请求类型为Content-Type:application/json的请求时,会出现严重的问题. 在Spring体系中,过滤器的定义我们一般采用继承OncePerRequestFilter的方式,当然也可以使用原始的Filter. 错误写法一: 如果不对request和response进行处理,使用伪代码

  • 详解在spring中使用JdbcTemplate操作数据库的几种方式

    使用JdbcTemplate的步骤 1.设置spring-jdbc和spring-tx的坐标(也就是导入依赖) <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.7.RELEASE</version> </dependency> <dependency&

  • 详解JAVA Spring 中的事件机制

    说到事件机制,可能脑海中最先浮现的就是日常使用的各种 listener,listener去监听事件源,如果被监听的事件有变化就会通知listener,从而针对变化做相应的动作.这些listener是怎么实现的呢?说listener之前,我们先从设计模式开始讲起. 观察者模式 观察者模式一般包含以下几个对象: Subject:被观察的对象.它提供一系列方法来增加和删除观察者对象,同时它定义了通知方法notify().目标类可以是接口,也可以是抽象类或具体类. ConcreteSubject:具体的

  • 详解用Spring Boot Admin来监控我们的微服务

    1.概述 Spring Boot Admin是一个Web应用程序,用于管理和监视Spring Boot应用程序.每个应用程序都被视为客户端,并注册到管理服务器.底层能力是由Spring Boot Actuator端点提供的. 在本文中,我们将介绍配置Spring Boot Admin服务器的步骤以及应用程序如何集成客户端. 2.管理服务器配置 由于Spring Boot Admin Server可以作为servlet或webflux应用程序运行,根据需要,选择一种并添加相应的Spring Boo

  • SpringBoot详解整合Spring Boot Admin实现监控功能

    目录 监控 监控的意义 可视化监控平台 监控原理 自定义监控指标 监控 ​ 在说监控之前,需要回顾一下软件业的发展史.最早的软件完成一些非常简单的功能,代码不多,错误也少.随着软件功能的逐步完善,软件的功能变得越来越复杂,功能不能得到有效的保障,这个阶段出现了针对软件功能的检测,也就是软件测试.伴随着计算机操作系统的逐步升级,软件的运行状态也变得开始让人捉摸不透,出现了不稳定的状况.伴随着计算机网络的发展,程序也从单机状态切换成基于计算机网络的程序,应用于网络的程序开始出现,由于网络的不稳定性,

  • 详解Javascript 中的 class、构造函数、工厂函数

    到了ES6时代,我们创建对象的手段又增加了,在不同的场景下我们可以选择不同的方法来建立.现在就主要有三种方法来构建对象,class关键字,构造函数,工厂函数.他们都是创建对象的手段,但是却又有不同的地方,平时开发时,也需要针对这不同来选择. 首先我们来看一下,这三种方法是怎样的 // class 关键字,ES6新特性 class ClassCar { drive () { console.log('Vroom!'); } } const car1 = new ClassCar(); consol

  • 详解Python 实现 ZeroMQ 的三种基本工作模式

    简介 引用官方说法:ZMQ(以下 ZeroMQ 简称 ZMQ)是一个简单好用的传输层,像框架一样的一个 socket library,他使得 Socket 编程更加简单.简洁和性能更高. 是一个消息处理队列库,可在多个线程.内核和主机盒之间弹性伸缩. ZMQ 的明确目标是"成为标准网络协议栈的一部分,之后进入 Linux 内核".现在还未看到它们的成功.但是,它无疑是极具前景的.并且是人们更加需要的"传统" BSD 套接字之上的一 层封装.ZMQ 让编写高性能网络应

  • 详解matplotlib中pyplot和面向对象两种绘图模式之间的关系

    matplotlib有两种绘图方式,一种是依托matplotlib.pyplot模块实现类似matlab绘图指令的绘图方式,一种是面向对象式绘图,依靠FigureCanvas(画布). Figure (图像). Axes (轴域) 等对象绘图. 这两种方式之间并不是完全独立的,而是通过某种机制进行了联结,pylot绘图模式其实隐式创建了面向对象模式的相关对象,其中的关键是matplotlib._pylab_helpers模块中的单例类Gcf,它的作用是追踪当前活动的画布及图像. 因此,可以说ma

随机推荐