Spring中BeanPostProcessors【2】优雅实现业务分离

来源:互联网 发布:淘宝山鸡批发 编辑:程序博客网 时间:2024/05/17 23:37
1 概述
BeanPostProcessors可以在spring IoC容器初始化受管Bean前、属性设置后对该Bean先做一些预处理,或者在容器销毁受管Bean之前自己释放资源。《Spring中BeanPostProcessors【1】简单预处理》一文有实例说明。本文介绍一个具体案例,优雅实现业务分离。


2 基础类

设想一个系统中分很多模块,对于模块又有不同的操作命令,对于不同模块的不同命令场景,会有不同的处理。当然通过if else判断可以实现,但可读性和优雅性太差。下面采取注解+BeanPostProcessors的方式优雅实现。

【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】常量类

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

【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@273e07bdreturn 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");}}


2 0