1 概述
BeanPostProcessors可以在spring IoC容器初始化受管Bean前、属性设置后对该Bean先做一些预处理,或者在容器销毁受管Bean之前自己释放资源。《Spring中BeanPostProcessors【1】简单预处理》一文有实例说明。本文介绍一个具体案例,优雅实现业务分离。
2 基础类
设想一个系统中分很多模块,对于模块又有不同的操作命令,对于不同模块的不同命令场景,会有不同的处理。当然通过if else判断可以实现,但可读性和优雅性太差。下面采取注解+BeanPostProcessors的方式优雅实现。
2.1 注解类
package com.xy.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Module {
/**
* 模块号
*/
short moduleId();
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BizCommand {
/**
* 命令号
*/
short cmdId();
}
2.2 常量类
package com.xy.constants;
public interface ConstantCmd {
// 添加
public short ADD = 1;
// 删除
public short DELETE = 2;
}
public interface ConstantModule {
// 学生模块
public short STUDENT = 1;
// 教师模块
public short TEACHER = 2;
}
2.3 业务类
package com.xy.service;
import com.xy.annotation.BizCommand;
import com.xy.annotation.Module;
import com.xy.constants.ConstantCmd;
import com.xy.constants.ConstantModule;
@Module(moduleId = ConstantModule.STUDENT)
public interface StuService {
@BizCommand(cmdId = ConstantCmd.ADD)
public void add(String name);
@BizCommand(cmdId = ConstantCmd.DELETE)
public void delete(String name);
}
import org.springframework.stereotype.Component;
@Component // 该类需要被Spring托管
public class StuServiceImpl implements StuService {
public void add(String name) {
System.out.println("I am student add method.add name:" + name);
}
public void delete(String name) {
System.out.println("I am student delete method.delete name:" + name);
}
}
3 核心类
总体思路是利用模块号+命令号对应不同的方法和实现类,方法和实现类被存在对应列表中。
传入模块号和命令号,即可获取对应的方法名和实现类,执行即可。
package com.xy.scanner;
import java.lang.reflect.Method;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
import com.xy.annotation.BizCommand;
import com.xy.annotation.Module;
@Component // 该类也需要被Spring托管
public class BizScanner implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// 容器管理的类信息(stuServiceImpl)
Class<? extends Object> clazz = bean.getClass();
// 该类实现的接口(stuService)
Class<?>[] interfaces = clazz.getInterfaces();
if (null != interfaces && interfaces.length > 0) {
for (Class<?> interFace : interfaces) {
// 获取接口注解
// 模块信息
Module module = interFace.getAnnotation(Module.class);
if (null == module)
continue;
// 该接口所有方法
Method[] methods = interFace.getMethods();
if (null != methods && methods.length > 0) {
for (Method method : methods) {
// 命令信息
BizCommand bizCommand = method.getAnnotation(BizCommand.class);
if (null == bizCommand)
continue;
// 模块号
short moduleId = module.moduleId();
// 命令号
short cmdId = bizCommand.cmdId();
if (BizInvokerManager.getInvoker(moduleId, cmdId) == null) {
BizInvokerManager.addInvoker(moduleId, cmdId, BizInvoker.valueOf(method, bean));
} else {
System.out.println("重复命令:" + "module:" + moduleId + " " + "cmdId:" + cmdId);
}
}
}
}
}
return bean;
}
}
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 命令执行器
*/
public class BizInvoker {
/**
* 方法
*/
private Method method;
/**
* 目标对象(实现类)
*/
private Object target;
/**
* 封装执行器
*
* @param method 方法 com.xy.service.StuService.add
* @param target 目标 com.xy.service.StuServiceImpl@273e07bd
* @return 执行器
*/
public static BizInvoker valueOf(Method method, Object target) {
BizInvoker invoker = new BizInvoker();
invoker.setMethod(method);
invoker.setTarget(target);
return invoker;
}
/**
* 调用方法
*
* @param paramValues 参数
* @return 执行结果
*/
public Object invoke(Object... paramValues) {
try {
// method 方法 com.xy.service.StuService.add
// target 目标 com.xy.service.StuServiceImpl@273e07bd
return method.invoke(target, paramValues);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
}
import java.util.HashMap;
import java.util.Map;
/**
* 命令执行器管理者
*/
public class BizInvokerManager {
/**
* 命令调用器(第1个short是模块号,第2个short是命令号)
*/
private static Map<Short, Map<Short, BizInvoker>> invokers = new HashMap<Short, Map<Short, BizInvoker>>();
/**
* 添加命令调用
*
* @param module 模块号
* @param cmd 命令号
* @param invoker 调用器
*/
public static void addInvoker(short moduleId, short cmdId, BizInvoker invoker) {
Map<Short, BizInvoker> map = invokers.get(moduleId);
if (null == map) {
map = new HashMap<Short, BizInvoker>();
invokers.put(moduleId, map);
}
map.put(cmdId, invoker); // 改变引用,将命令号存入
}
/**
* 获取命令调用
*
* @param module 模块号
* @param cmd 命令号
*/
public static BizInvoker getInvoker(short moduleId, short cmdId) {
Map<Short, BizInvoker> map = invokers.get(moduleId);
if (map != null) {
return map.get(cmdId);
}
return null;
}
}
4 Spring文件
<context:component-scan base-package="com.xy.scanner" />
<context:component-scan base-package="com.xy.service" />
5 测试
package com.xy.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.xy.constants.ConstantCmd;
import com.xy.constants.ConstantModule;
import com.xy.scanner.BizInvoker;
import com.xy.scanner.BizInvokerManager;
public class TestBean {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println(ac);
BizInvoker invoker1 = BizInvokerManager.getInvoker(ConstantModule.STUDENT, ConstantCmd.ADD);
invoker1.invoke("xy1");
System.out.println("========================");
BizInvoker invoker2 = BizInvokerManager.getInvoker(ConstantModule.STUDENT, ConstantCmd.DELETE);
invoker2.invoke("xy2");
}
}