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;
}