Spring 源码涉及到的重要设计模式

 

2.1 通过xxxProcessor 实现对bean地增强/修饰/处理

BPP(BeanPostProcessor) 基本流程:

所需要的武器: 一个bean容器 装着所有你要的对象, 并且可以按照一定规则来取出你要的对象并执行

这里的规则可以是: 实现了指定接口的类 这些类的特征都是服务于do sth而做的增强/修饰处理 spring正好是这样的容器 并且可以按这个规则调用实例

ApplicationContextUtil.getApplicationContext().getBeansOfType(xxxClass)

应用场景

我有一个request 要请求DB来获取文本内容, 上线后, +需求:

0.如果用户不在特定名单里 做拦截处理

1.如果用户属于A组 做特定的字符替换渲染

2.如果用户属于B组 做特定的字符替换渲染

3.如果用户属于黑名单 做内容截取 只允许看前十个字符

Key:

这些需求不可枚举完全, 后续很可能还会增加 如果我在业务处理逻辑中通过if-else 后续都要更改这些代码 容易出事

对内容增强/修饰, 会有一定的顺序, 所以在调用这些处理接口时 给一个属性来排序

核心样例代码

核心代码



java
@Service
@Slf4j
public class TextServiceImpl implements TextService {

    @Autowired
    private TextMapper textMapper;

    @Override
    public ServerResponse<String> getText(String user, String textKey) {
        PostProcessorContainer bppContainer = PostProcessorContainer.getInstance(TextRenderPostProcessor.class);


        RenderBo renderBo = new RenderBo();
        renderBo.setLoginUsername(user);
        renderBo.setTextKey(textKey);

        PostContext<RenderBo> context = new PostContext<>();  //作为载体 串联整条处理线
        context.setBizData(renderBo);
        //handle before  权限策略
        boolean isContinue = bppContainer.handleBefore(context);
        if(!isContinue){
            return ServerResponse.success(renderBo.getText());
        }
        //get data from DB
        String result = textMapper.get(textKey);
        renderBo.setText(result);
        //handler after  //按需 渲染
        bppContainer.handleAfter(context);
        return ServerResponse.success(renderBo.getText());
    }
}
java

import com.example.soldierspringboot.utils.ApplicationContextUtil;
import lombok.Data;


import java.util.*;


@Data
public class PostProcessorContainer<T> {
    private Class<BasePostProcessor> monitorPostProcessorClass;


    public static <T> PostProcessorContainer getInstance(Class<T> monitorPostProcessorClass) {
        PostProcessorContainer postProcessorContainer = new PostProcessorContainer();
        postProcessorContainer.setMonitorPostProcessorClass(monitorPostProcessorClass);
        return postProcessorContainer;
    }


    public boolean handleBefore(PostContext<T> postContext) {
        Map<String, BasePostProcessor> processors = ApplicationContextUtil.getApplicationContext().getBeansOfType(monitorPostProcessorClass);
        List<BasePostProcessor> list = new ArrayList<>();
        for (BasePostProcessor bpp : processors.values()) {
            list.add(bpp);
        }
        if (list.size() == 0) return true;//skip handle before
        //sort
        Collections.sort(list,
                (Comparator<BasePostProcessor>) (o1, o2)
                        -> Integer.valueOf(o1.getPriority()).compareTo(Integer.valueOf(o2.getPriority()))
        );
        //handle
        for (BasePostProcessor bpp : list) {
           boolean isContinue = bpp.handleBefore(postContext);
           if(!isContinue) return false;
        }
        return true;
    }




    public void handleAfter(PostContext<T> postContext) {
        Map<String, BasePostProcessor> processors = ApplicationContextUtil.getApplicationContext().getBeansOfType(monitorPostProcessorClass);
        List<BasePostProcessor> list = new ArrayList<>();
        for (BasePostProcessor bpp : processors.values()) {
            list.add(bpp);
        }
        if (list.size() == 0) return ;//skip handle
        //sort
        Collections.sort(list,
                (Comparator<BasePostProcessor>) (o1, o2)
                        -> Integer.valueOf(o2.getPriority()).compareTo(Integer.valueOf(o1.getPriority()))
        );
        //handle
        for (BasePostProcessor bpp : list) {
            bpp.handleAfter(postContext);
        }


    }
}
java
@Service
public class ApplicationContextUtil implements ApplicationContextAware {
    // Spring应用上下文环境
    private static ApplicationContext applicationContext;


    public static <T> List<T> getBeansOfType(Class<T> type) {
        Map<String, T> beans = applicationContext.getBeansOfType(type);
        List<T> list = new ArrayList<>();
        if(beans == null) return list;
        for (T bpp : beans.values()) {
            list.add(bpp);
        }
        return list;
    }


    /**
     * 实现ApplicationContextAware接口的回调方法,设置上下文环境
     *
     * @param applicationContext
     */
    public void setApplicationContext(ApplicationContext applicationContext) {
        ApplicationContextUtil.applicationContext = applicationContext;
    }


    /**
     * @return ApplicationContext
     */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }


    /**
     * 获取对象
     *
     * @param name
     * @return Object
     * @throws BeansException
     */
    public static Object getBean(String name) throws BeansException {
        return applicationContext.getBean(name);
    }


    public static <T> T getBean(Class<T> clazz) throws BeansException {
        return (T)applicationContext.getBean(clazz);
    }


    public static <T> T getBean(String name, Class<T> clazz) {
        return applicationContext.getBean(name, clazz);
    }




}

Spring中实现细节

看##处

java
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
 // 如果安全管理器不为空
 if (System.getSecurityManager() != null) {
  // 以特权的方式执行回调bean中的Aware接口方法
  AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
   invokeAwareMethods(beanName, bean);
   return null;
  }, getAccessControlContext());
 }
 else {
  // Aware接口处理器,调用BeanNameAware、BeanClassLoaderAware、beanFactoryAware
  invokeAwareMethods(beanName, bean);
 }


 Object wrappedBean = bean;
 //如果mdb不为null || mbd不是"synthetic"。一般是指只有AOP相关的prointCut配置或者Advice配置才会将 synthetic设置为true
 if (mbd == null || !mbd.isSynthetic()) {
  // 将BeanPostProcessors应用到给定的现有Bean实例,调用它们的postProcessBeforeInitialization初始化方法。
  // 返回的Bean实例可能是原始Bean包装器
  wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);/// before   ##
 }


 try {
  //调用初始化方法,先调用bean的InitializingBean接口方法,后调用bean的自定义初始化方法
  invokeInitMethods(beanName, wrappedBean, mbd); ///##
 }
 catch (Throwable ex) {
  //捕捉调用初始化方法时抛出的异常,重新抛出Bean创建异常:调用初始化方法失败
  throw new BeanCreationException(
    (mbd != null ? mbd.getResourceDeion() : null),
    beanName, "Invocation of init method failed", ex);
 }
 //如果mbd为null || mbd不是"synthetic"
 if (mbd == null || !mbd.isSynthetic()) {
  // 将BeanPostProcessors应用到给定的现有Bean实例,调用它们的postProcessAfterInitialization方法。
  // 返回的Bean实例可能是原始Bean包装器
  wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); ///after  ##
 }


 //返回包装后的Bean
 return wrappedBean;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值