深圳幻海软件技术有限公司 欢迎您!

基于BeanPostProcessor接口+自定义注解玩转策略模式

2023-02-28

前言有人说不要用业务类实现InitializingBean接口,可以借助自定义的注解来实现类似的逻辑。那我们换这种思路实现下。定义注解PayType复制/***消息通知类型注解*@authorfrancis**/@Target(ElementType.TYPE)@Retention(Retentio

前言

有人说不要用业务类实现InitializingBean接口,可以借助自定义的注解来实现类似的逻辑。那我们换这种思路实现下。

定义注解PayType

/**
* 消息通知类型注解
* @author francis
*
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface PayType {
  /**
  * 支付类型
  * @return
  */
  PayTypeEnum value();
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

其中PayTypeEnum枚举

@Getter
@AllArgsConstructor
public enum PayTypeEnum {
    WX("WX", "微信"),
    ZFB("A","支付支付"),;
    private String type;
    private String desc;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

BeanPostProcessor(Bean后置处理器)

功能:它是Spring中定义的接口,在Spring容器的创建过程中(具体为Bean初始化前后)会回调BeanPostProcessor中定义的两个方法。

  • postProcessBeforeInitialization方法

会在每一个bean对象的初始化方法调用之前回调

  • postProcessAfterInitialization方法

会在每个bean对象的初始化方法调用之后被回调

源码如下:

package org.springframework.beans.factory.config;

import org.springframework.beans.BeansException;
import org.springframework.lang.Nullable;

public interface BeanPostProcessor {
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

两个方法入参说明:

bean:容器正在创建的那个bean的引用beanName:容器正在创建的那个bean的名称

策略工厂实现BeanPostProcessor接口

getClass() 返回此 Object 的运行时该对象的类. 该方法返回一个Class对象, 可以通过该对象可以获取某个类的相关信息, 如构造方法 属性 方法 等

import com.example.demo.celuemoshi.PayService;
import com.example.demo.celuemoshi.PayTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
@Slf4j
public class StrategyFactory2 implements BeanPostProcessor {
    private static final Map<PayTypeEnum, PayService> serviceMap = new ConcurrentHashMap<>();
    /**
     * @param bean 实例化bean的引用
     * @param beanName 实例化bean的名字
     * @return
     * @throws
    @Nullable
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 只对实现了PayService的类做操作
        if (bean instanceof PayService) {
            //获取对象运行时该对象的类
            Class<?> clazz = bean.getClass();
            //获取自定义的注解
            PayType annotation = clazz.getAnnotation(PayType.class);
            //绑定对应关系
            serviceMap.put(annotation.value(), (PayService) bean);
        }
        return bean;
    }
    /**
     * 寻找对应得策略处理器
     */
    public PayService getHandler(PayTypeEnum type){
        return serviceMap.get(type);
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.

业务类加上@PayType

@Service
@Slf4j
@PayType(PayTypeEnum.ZFB)
public class AliService implements PayService {

    public Boolean pay(String type) {
        log.info("调用阿里支付={}",type);
        return true;
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
import com.example.demo.strategy2.PayType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Service
@Slf4j
@PayType(PayTypeEnum.WX)
public class WxServiceA implements PayService {


    @Override
    public Boolean pay(String type) {
        log.info("调用微信支付={}",type);
        return true;
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

定义一个控制器测试

import com.example.demo.celuemoshi.StrategyFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class PayController {

    @GetMapping("pay/{type}")
    public boolean pay(@PathVariable("type") String type){
        StrategyFactory.getService(type);
       return true;
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

测试结果

测试微信支付:http://localhost:10001/pay/wx

测试阿里支付:http://localhost:10001/pay/zfb