springboot自动装配原理简言之,springboot装配机制
00-1010I:需求背景II:设计思路III:用法IV:注释解析器(核心代码)V:需要考虑的技术点
00-1010业务拓展中经常有这种场景。数据的创建者将被记录在A(业务表)表中。通常情况下,我们会用userId字段记录这个数据的创建者,但是数据的用户会要求显示这个数据的创建者的名字,所以我们会关联user表来获取这个用户的名字。还有一些枚举值的意义展示给前端。单个表的原始sql要写成多个表的关联sql,还有枚举意义的转换,真恶心。
例如:业务对象BusinessEntity.java
类业务实体{/* * * creator id */private Long create userid;*创建者名称(需要关联用户表)私有字符串用户名;*数据状态(03360有效,1无效)私有字符串状态;*数据状态含义(需要向前端解析0或1的含义)私有字符串statusName*数据集privatelistbusinesslist}
00-1010就像@JsonFormat注释,可以指定返回日期格式。是不是也可以定义一个注释,通过它可以自动填写需要与表关联的数据用户名,如何通过枚举解析数据状态名?
因此,枚举@ autowireAttribute定义如下
/* * * Auto-assembly property */@ target({ method,field,annotation _ type,constructor,parameter,Type _ use })@ retention(runtime)@ documented public @ interfaceautowwireattribute {/* *为默认值时,表示该属性为javaBean,javaBean需要自动注入该属性*否则为指向属性* * @ return */string param()default“”;*默认值为BaseEnum。类,* redis缓存时默认为注入的数据源,*否则为枚举类型类?扩展BaseEnum enumClass()默认base enum . class;*数据源data source enum data source()defaultdatasourceenum . empty;}定义了公共枚举继承接口BaseEnum。
公共接口base enum { String getCode();string getMsg();}定义数据源枚举如下dataSource
枚举数据源枚举实现base enum { system _ dict( sys 3360 dict 3360 ,系统字典值, sys _ dict _ value , name ),user _ name (user3360name3360 ,用户id和名称的映射, sys _ user , user _ name ),user _ role (user3360role 3360 ,角色id到角色名称的映射, sys _ role , name ),dept _ name (dept3360name3360)部门id和部门的映射DataSourceEnum(String code,String msg,String tableName,String table column){ this . code=code;this.msg=msgthis.tableName=tableNamethis . table column=table column;}私有字符串代码;私有字符串msg/* * *表示*/私有字符串tableName*私有字符串table表的column;@覆盖公共字符串getCode()
{ return code; public String getMsg() { return msg; public String getTableName() { return tableName; public String getTableColumn() { return tableColumn;}
三:使用方法
对比原对象:通过新增注解,就避免的关联查询和数据解析
public class BusinessEntity { /** * 创建者id */ private Long createUserId; * 创建者名称 (需要关联用户表) @AutowiredAttribute(param = "createUserId", dataSource = DataSourceEnum.USER_NAME) private String userName; * 数据状态(0:有效,1失效) private String status; * 数据状态含义(需要解析0或1的含义给前端) @AutowiredAttribute(param = "status", enumClass = StatusEnum.class) private String statusName; * 数据集合 @AutowiredAttribute private List<BusinessEntity> list;}
四:注解解析器(核心代码)
/** * 填充相应体 */@Component@ControllerAdvice()public class FillResponseBodyAdvice implements ResponseBodyAdvice { @Autowired RedissonClient redissonClient; JdbcTemplate jdbcTemplate; private static String GET_CODE_METHOD_NAME = "getCode"; private static String GET_MSG_METHOD_NAME = "getMsg"; @Override public boolean supports(MethodParameter returnType, Class converterType) { if (ResponseResult.class.getName().equals(returnType.getMethod().getReturnType().getName())) { return true; } return false; } public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { if (((ResponseResult<?>) body).getCode() == 200) {//仅仅对相应为200结果处理 Object data = ((ResponseResult<?>) body).getData(); Class<?> aClass = data.getClass(); if (data instanceof List) { //集合对象设置属性 setForListBeanArr((List) data); } else { //判断是否为自定义java对象 if (aClass.getSuperclass() instanceof Object) { setForJavaBeanArr(data, aClass); } } return body; /** * 为集合对象设置属性 * * @param list */ void setForListBeanArr(List<Object> list) { for (Object object : list) { Class<?> aClass = object.getClass(); setForJavaBeanArr(object, aClass); * 为自定义javaBean对象设置值 private void setForJavaBeanArr(Object data, Class<?> aClass) { Field[] declaredFields = aClass.getDeclaredFields(); for (Field field : declaredFields) { AutowiredAttribute annotation = field.getAnnotation(AutowiredAttribute.class); if (annotation == null) { continue; //通过枚举注入 String param = annotation.param(); try { field.setAccessible(true); if (param.equals("")) {//注解表明该对象时javaBean对象 //获取该javaBean对象 Object data2 = field.get(data); if (data2 == null) { continue; } //属性是list对象 if (data2 instanceof List) { setForListBeanArr((List) data2); } else if (data2.getClass().getSuperclass() instanceof Object) { setForJavaBeanArr(data2, data2.getClass()); } else { //反射获取值 Field field1 = aClass.getDeclaredField(param); field1.setAccessible(true); Object o = field1.get(data); if (annotation.enumClass().getName().equals(BaseEnum.class.getName())) { //通过redis注入 injectByEnum(o, field, data); } else { //通过枚举注入 injectByRedis(o, field, data); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { private void injectByEnum(Object param, Field field, Object data) throws IllegalAccessException { AutowiredAttribute annotationAutowiredAttribute = field.getAnnotation(AutowiredAttribute.class); DataSourceEnum dataSourceEnum = annotationAutowiredAttribute.dataSource(); if (dataSourceEnum.equals(DataSourceEnum.EMPTY)) { //不规范的 } else if (dataSourceEnum.equals(DataSourceEnum.SYSTEM_DICT)) { Object o = redissonClient.getMap(DataSourceEnum.SYSTEM_DICT.getCode()).get(param); if (o == null) { o = getDictAndSetRedis(DataSourceEnum.SYSTEM_DICT, param); field.set(data, o); private void injectByRedis(Object param, Field field, Object data) throws IllegalAccessException { AutowiredAttribute annotation = field.getAnnotation(AutowiredAttribute.class); Class<? extends BaseEnum> aClass = annotation.enumClass(); try { // 获取所有常量 Object[] objects = aClass.getEnumConstants(); //获取指定方法 Method getMsg = aClass.getMethod(GET_MSG_METHOD_NAME); Method getCode = aClass.getMethod(GET_CODE_METHOD_NAME); for (Object obj : objects) { if (getCode.invoke(obj).equals(param.toString())) { field.set(data, getMsg.invoke(obj)); System.out.println(getMsg.invoke(obj)); } catch (Exception e) { System.out.println(e.getMessage()); // Object getDictAndSetRedis(DataSourceEnum dataSourceEnum, Object value) { String sql = "select name from " + dataSourceEnum.getTableName() + " where id = " + value; String s = jdbcTemplate.queryForObject(sql, String.class); RMap<Object, Object> map = redissonClient.getMap(dataSourceEnum.getCode()); map.put(value, s); return s;}
实现了从数据库(mysql)自动查询,并把结果缓冲到数据库。
五:需要思考的技术点
1.为什么注解要用到枚举和泛型class
2.注解解析器,为什么用ResponseBodyAdvice这里解析?不在Filter,Interceptors?
3.对于对象里面嵌套对象,或对象里面嵌套集合,怎么解决注入?递归
到此这篇关于基于SpringBoot实现自动装配返回属性的文章就介绍到这了,更多相关SpringBoot自动装配返回属性内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。