2012_11月总结分享

2023-11-19

     11月份下旬,我在技术上主要看了看spring的IoC容器实现相关的内容。但是这次来不及写了(这是一个很长的故事),就分享了一下11月份遇到的值得记录的东西吧,中间也穿插2篇文章分享,无缝对接。总结如下:

(1)   代码规范问题

(2)   Tair批量读取使用一个问题及其相关

(3)   ttm配置文件的一个问题

1.    代码规范问题

最近两周遇到的代码规范问题,主要是DAO、Manager、Service的规范和日志处理规范。

(1)   DAO、Manager、Service规范

之前@南八分享了一下这个规范,我还有ppt。我觉得挺好的。如下:

a.    DAO

DAO实现读取数据库基本操作,CURD;封装BaseDAO,添加DBRoute支持,增强扩展性 ;配置添加TDDL支持;基于淘宝的common-dao;统一抛出DAOException;入口参数无需验证;尽量原子操作,避免复杂逻辑。

我代码不规范之处为红色部分。在IbatisBrandDAO的updateMyBrands等方法中,不规范如下:

1.写了大量的业务逻辑;

2.读取了Tair;

3.没有统一抛出DAOException;

后面我会改正,大家现在还可以上主干去看看,当反面教材看。

b.  Manager

统一异常抛出ManagerException;注解注入DAO,Hsf Consumer Service;如果单个操作执行多条sql,采用Spring事务进行处理;入口参数进行验证;

c.    Service

返回结果明确泛型类型;入口参数要求进行验证;不要抛出异常;错误要打印日志;

我代码犯错如下:

1.    BrandService接口规范:publicList<BrandDO> getAllBrandWithLogo() throws BrandException

2.    抛出了异常BrandException

3.    结果没有封装

后续我把这个getAllBrandWithLogo会改造。

接下来,我自己对于Deptcenter-common包中对外接口规范要求初步如下:

a.brandService所有的方法均不抛出异常,客户端不用catch异常(只要你相信我,后面我会专门谈到这个问题),只需要查看结果码即可。

b.brandService返回的结果使用result<T>来封装,T为结果类型,并携带结果码。每一种结果码对应一种情况,比如处理成功、参数不合法、数据库异常、错误、hsf服务调用超时等等。每一种错误对应的错误码也要对应起来。

BrandConstants对应了至少7种错误情况。

public final static int ERROR_PARAM_INVALID = -10;                  //user_id <= 0 or pageSisze <= 0 or brandId <= 0类似情况
		public final static int ERROR_BRANDID_NOT_IN_EXTDB = -11;           //brandId不在收藏品牌表中
		public final static int ERROR_BRANDID_NOT_MANUAL = -12;             //brandId在收藏表中,但是该品牌本身不能收藏
		public final static int ERROR_ADD_BRAND = -13;                      //关注品牌逻辑错误:用户之前已经关注过该品牌
		public final static int ERROR_DELETE_BRAND = -14;                   //用户取消关注品牌辑错误:用户之前并未关注过该品牌
		public final static int ERROR_BRANDID_NOT_IN_INFODB = -15;           //brandId不在品牌基本表中
		public final static int ERROR_BRANDID_NOT_IN_TAIR = -16;            //brandId对应的信息在Tair中没有

我看了看Tair client处理源码,和这个类似,提供大量的错误码供客户端判断。

以后至少deptcenter-common包会严格按照这个规范来做。

2.异常处理的问题

a.首先分享一下异常处理

异常处理的最佳实践http://blog.jobbole.com/18291/

记录异常日志的7条规则http://www.importnew.com/518.html

分别都提到了不要记录后又重新向外抛出或者为仅记录exception一次,理由是对同一个错误的栈回溯(stack trace)记录多次的话,会让程序员搞不清楚错误的原始来源。所以仅仅记录一次就够了。

代码不规范之处:

DefaultMyBrandsManager的isMyBrandExit方法:

public boolean isMyBrandExit(Long userId, Long brandId)
			throws MyBrandsServiceException {
		try {
			return this.myBrandsDAO.isMyBrandExit(userId, brandId);
		} catch (DAOException e) {
			this.logger.error("查询用户是否收藏品牌时出错,数据库错误,用户:"+ userId+" 品牌id"+brandId,e);
			throw new MyBrandsServiceException(e);
		}
	}

记录了日志,又抛出了ManagerException异常。

在上层DefaultMyBrandsAO.isMyBrandExit()方法再次catch了这个managerException,并打印同样错误地信息。

public Result isMyBrandExit(Long userId, Long brandId) {
        Result result = initResult();
        try {
            boolean isExit = myBrandsManager.isMyBrandExit(userId, brandId);
            result.setDefaultModel(isExit);
            result.setSuccess(true);
        } catch (ManagerException e) {
            log.error("取得az页面详细信息失败,原因为:", e);
            result.setSuccess(false);
        }
        return result;
    }

而且错误的中文原因也写错了。这样在日志中会至少同时记录两处一样的错误堆栈信息。

另外在deptcenter-core-client包中的MyBrandsServiceClient每一个方法,都有如下类似如下的处理:如果参数为空,会抛出IllegalArgumentException

 public boolean isMyBrandExit(Long userId, Long brandId)
            throws MyBrandsServiceException {
        if(null==userId || null == brandId){
            throw new IllegalArgumentException("MyBrandsServiceException@ condition erro: userId or brandId is null");
        }
        return myBrandsService.isMyBrandExit(userId, brandId);
    }


我认为这样不太好:

IllegalArgumentException继承了RuntimeException,是一种RuntimeException。这样就会导致调用MyBrandsServiceClient的客户端必须要在外层catch Exception。而事实上很多客户端使用完全忘记了这一点,相当危险!举例如下:

DefaultMyBrandsManager的isMyBrandExit()实现如下:

public boolean isMyBrandExit(Long userId, Long brandId)
			throws MyBrandsServiceException {
		try {
			return this.myBrandsDAO.isMyBrandExit(userId, brandId);
		} catch (DAOException e) {
			this.logger.error("查询用户是否收藏品牌时出错,数据库错误,用户:"+ userId+" 品牌id"+brandId,e);
			throw new MyBrandsServiceException(e);
		}
	}

可以看出来,并没有catch Exception,也就是说,如果userId或者brandId为空,isMyBrandExit会抛出IllegalArgumentException,但是代码并没有catch住,所以这个IllegalArgumentException会继续传播到上一层,到DefaultMyBrandsAO对于isMyBrandExit的处理如下:

 public Result isMyBrandExit(Long userId, Long brandId) {
        Result result = initResult();
        try {
            boolean isExit = myBrandsManager.isMyBrandExit(userId, brandId);
            result.setDefaultModel(isExit);
            result.setSuccess(true);
        } catch (ManagerException e) {
            log.error("取得az页面详细信息失败,原因为:", e);
            result.setSuccess(false);
        }
        return result;
    }

可以看出,这里还是没有catch Exception。可以想像,这个AO的该方法会有可能抛出RuntimeException,很危险。建议:要么在MyBrandsServiceClient别抛出IllegalArgumentException,不然上层客户端都要catchRuntimeException。

就在写这篇文章的时候的当天,我突然想起的对外提供的hsf服务犯了一个低级错误,这里写出来让大家看看,拉出来示众。

public BrandResult<Integer> isFavBrand(Long userId, Long brandId) {
		// TODO Auto-generated method stub
		if(userId <= 0 || brandId <= 0){
			BrandResult<Integer> brandResult = new BrandResult<Integer>();
			brandResult.setSuccess(false);
			brandResult.setResultCode(BrandConstants.Result.ERROR_PARAM_INVALID);
			brandResult.setErrorMsg("参数非法");
			return brandResult;
		}else{
			return brandService.isFavBrand(userId, brandId);
		}
	}

对外服务BrandService的每一个接口都没有申明抛出异常。但是在BrandServiceClient实现的时候,我仅对参数做了大小判断,没有做非空判断。如果此时客户端调用的时候,传过来一个null,那么这里就会抛出NullPointerException,客户端就会出错。修改后,增加了非空判断。

上述案例我都会放在品牌街wiki里面codereiew的记录

1.   Tair批量读接口使用一个问题

问题:漏掉了潜在出现的部分成功的处理。

原处理代码:

DefaultBrandTairManager

批量读取Tair的时候,代码如下:

try {
			Result<List<DataEntry>> result = defaultMyBrandsTairManager.mget(namespace,getMKeys(brandIdList));
			if (result != null) {
				if (result.isSuccess()) {
					if (result.getValue() != null) {

						for(DataEntry dataEntry: result.getValue()) {
							list.add((ForTagValueIndexDO)dataEntry.getValue());
						}
						return list;
					}
				} else {
					log.warn("getBrandForTagValueIndexFromTair get error;" + result.getRc()+ ";key=" + brandIdList);
				}
			}
		} catch (Exception e) {
			log.error("getBrandForTagValueIndexFromTair", e);
		}
		return list;

其实Tair的QuickStart已经写好示例了:

http://baike.corp.taobao.com/index.php/QuickStartWithJavaClient

List<Object> keys = new ArrayList<Object>();
keys.add(key1);
keys.add(key2);
// 更多key……

Result<List<DataEntry>> result = tm.mget(namespace, keys);
if (result.isSuccess() || ResultCode.PARTSUCC.equals(result.getRc())) { // 部分成功时会返回成功的值
	for (DataEntry de : result.getValue()) {
		// 返回的处理代码
	}
} else {
	// 你的出错处理代码
}

批量读取Tair的时候,应该加上部分成功的逻辑(只要业务能够接受)。即:

if(result.isSuccess() || ResultCode.PARTSUCC.equals(result.getRc()))

这个批量读取Tair的方法在品牌街的应用场景是在我的关注品牌页面:首先通过userId查询List<Long BrandId>,然后将这个brandIdList去批量查询Tair,得到品牌详情并展示。原先有个隐藏的bug:如果用户收藏了Nike和Adidas,且恰好Nike品牌详情不在Tair中,那么之前的代码没有加上部分成功的判断,直接返回空数据,用户在我的关注品牌页面啥都没有。其实业务逻辑应该是,就算nike不在,应该返回Adidas的品牌详情。所以,原来那样写是有问题的。

Tair使用还有一个坑,就是批量读取的顺序问题。比如用list<k1,k2,k3>去Tair去数据,返回结果不保证是list<V1,V2,V3>,顺序是乱序的。如果业务需要,那么要手动调整。

      另外还有一个问题就是:到底要不要相信我们调用的服务的申明。比如TairManager方法申明中中,都没有抛出异常。

Tair使用示例:

http://baike.corp.taobao.com/index.php/QuickStartWithJavaClient

get方法并没有加上catch Exception。

我们读取Tair代码都是加了一层try catch,catch Exception

try {
			Result<List<DataEntry>> result = defaultMyBrandsTairManager.mget(namespace,getMKeys(brandIdList));
			if (result != null) {
				if (result.isSuccess()) {
					if (result.getValue() != null) {

						for(DataEntry dataEntry: result.getValue()) {
							list.add((ForTagValueIndexDO)dataEntry.getValue());
						}
						return list;
					}
				} else {
					log.warn("getBrandForTagValueIndexFromTair get error;" + result.getRc()+ ";key=" + brandIdList);
				}
			}
		} catch (Exception e) {
			log.error("getBrandForTagValueIndexFromTair", e);
		}
		return list;

这个问题我问了问@兆文和@战枫,答复是都一定要在外层catchException,因为我们不能完全相信Tair:他说不抛出异常,就不抛出异常。

之所以有这个疑问,是effective java的第57条说,只针对异常情况才使用异常,而Tair读取的各个方法都没有申明异常。。。这点大家怎么看?

还有对此相似的问题就是,在sqlMapDAO的类似executeQueryForList申明会抛出DAOException,我们代码中还有无必要在使用的时候,在catchDAOException的基础上,有必要catch Exception?


附:Tair答疑的回复

墨合  (2012-11-29 11:50:03):
想咨询一下,是否可以不在外层catch Exception?
tair答疑  (13:16:33):
这个接口不抛异常,不需要try catch


最终我的想法是:

反正我们外面加上,保证世界和平


3.   SchedulerFactoryBean的autoStartup属性

定时程序配置文件ttm-biz-timetask.xml中的SchedulerFactoryBean类,有一个配置项如下:

<propertyname="autoStartup" value="false"/>

问题产生:舒俊在本地的自测定时程序的时候,定时程序一直跑不起来,发现autoStartup配置为false。

1.    autoStartup如何起作用?

这个autoStartup属性我看了看,无论是线上、预发、日常,配置值都是false。这个属性是用来确定是否自动启动定时任务:即在Ioc容器初始化在生成这个SchedulerFactoryBean的时候,自动启动定时任务。看了看SchedulerFactoryBean这个类的实现,autoStartup这个boolean变量是这样起作用的:

SchedulerFactoryBean实现了InitializingBean这个接口,实现了afterPropertiesSet()方法。

在afterPropertiesSet()方法中,最后三行:

if (this.autoStartup) {

              startScheduler(this.scheduler, this.startupDelay);

       }

容器工厂会在SchedulerFactoryBean构造出来后,立即调用SchedulerFactoryBean实现的afterPropertiesSet()方法。如果autoStartup为true,那么开始执行startScheduler()方法。startScheduler方法会启动一个线程,调用scheduler.start(),开始执行任务。

2.    为什么autoStartup要配置为false的?

我对这个问题起先不是很清楚:为什么不让应用启动的时候,就去启动任务,还要通过ttm后台来人工指定机器再来运行。后来想到,我们deptadmin应用线上有两台机器,如果

autoStartup配置的是true,那么代码部署上去以后,两台机器都会自动运行定时程序,这样有可能会有问题,也有可能没必要。

3.ttm平台是如何启动任务的?

      应该是手动调用了SchedulerFactoryBean的startScheduler方法。待研究。

      问了问兆文,admin后台的两台机器是采用随机策略被选中执行的(如果两台机器都是好的话)。开始我认为应用部署成功之后,ttm后台会调用某一台机器的应用,调用startScheduler()方法,启动定时任务。但是我觉得应该不是这样做的,这样做的话,

deptadmin应用中的autoStartup为true,需要在ttm后台,配置好机器绑定后,定时任务才开始执行。应该是在配置机器后,ttm那边调用了startScheduler()方法,定时任务才开始执行,而不是部署代码成功之后(即IoC容器初始化之后)。从这边看来,SchedulerFactoryBean不能配置为lazy-init(不知道ttm那边怎么实现的)

这样看来,SchedulerFactoryBean绝对不能配置为non-singleton的,即scope="prototype"这个配置项目。

      EOF








本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

2012_11月总结分享 的相关文章

  • 走过2011

    走过2011 时间飞逝 2011不寻常的一年还剩下短短5天 三百天的生活与工作是一份平淡一份快乐 工作需要总结 生活也要总结 日子才会越来越好 2011是进入公司的第二年 公司开发人员有来有离 我没有离开 因为我不喜欢跳槽 但我不跳槽的主要
  • OrCAD PSPICE 仿真 问题集

    1 创建SIM 文件时出现 cannot initialize profile A 所有路径也都是英文路径 B 检查下安装目录下的SPB 16 6 tools pspice目录下的orsimsetup dll是不是还在 也可以找个新的文件替
  • Failed to bind properties under ‘spring.datasource.password‘ to java.lang.String

    1 记录一次坑 在配置jasypt时 一些都很顺利 pom引入 项目启动 从网上搜索资料jar包启动手动设置秘钥 java jar Djasypt encryptor password 1234qwer test jar 但是在部署的时候
  • 隐藏dlg窗口方法

    单独找到任务栏设置父窗口 并不能达到隐藏窗口的效果 还是有一个对话框在任务栏中出现 0 窗口属性设置步骤2 调整对话框属性ToolWindow为true步骤3 调整对话框属性Border为None 1 设置任务栏位父窗口 CWnd task
  • echarts 自定义鼠标悬停展示

    tooltip trigger axis formatter function params let htmlStr for let i 0 i lt params length i const param params i const x
  • 知识总结:ajax提交的参数中包含img标签,无法获取到src值

    在调试bug时 ajax提交的参数是一段html标签 var content img src www xxx com image xxxx jpg alt ajax url xxxx xxxx method sendPic data con
  • 话谈实际工作中的数据分析

    篇始 不知不觉 到新的公司任数据分析师一职已有大半年的时光 在段时光中 无可避免的犯了很多错误 亦得到了许多收获 今天 对于在职中的一些过错与收获进行总结 以期在日后的工作与成长过程中 能够更加的顺利 谈谈数据分析工作需具备能力 pytho
  • MyBatis 使用数组作为参数

  • 语雀 个人使用指南

    优点 markdown 此处为语雀内容卡片 点击链接查看 https www yuque com nanfang fw1qz wuc5c4 cts7ny 特色卡片 基础模块 思维导图无缝组成文本 第三方服务 免费即够用 多平台 云端存储 中
  • centos7下源码编译安装python3.8

    0 简介 centos7下源码编译安装python3 8 3 7 版本均可 3 6可通过yum安装 yum install python36 略 Centos安装Python3 8 centos7下源码编译安装python3 8 3 7 版
  • 2019年个人总结

    今天是今年的最后 一天 写个个人总结 对自己一年来的工作进行总结 通过分析和研究进而肯定成绩并找出问题 得出经验和教训 2019年自己的前端方面 移动端 完成了好艺的app项目 协会的微官网 好艺的app转为公众号 学生开学统计项目等 其中
  • IDEA中快速查看maven依赖树关系, 以及快速解决jar包冲突

    安装Maven Helper 插件 打开pom xml 切换到Dependency Analyzer 即可看见jar包的传递依赖关系 比如 spring boot starter websocket 中已经包含了spring boot st
  • 关于Undefined symbols for architecture x86_64这个错的总结

    最近在Mac上做一个程序 需要调用动态链接库 出现两次Undefined symbols for architecture x86 64的错误 所以总结下 第一个是 Undefined symbols for architecture x8
  • JAVA导出Excel文件

    JAVA导出Excel文件 一 集成POI 1 Apache POI 2 easyexcel 二 Excel相关操作 1 基础Excel导出 2 压缩Zip导出 3 错误Excel导出 4 根据Html导出 5 根据模板导出 6 根据模板及
  • @Transactional注解失效场景之——同类中方法调用,事务失效

    文章目录 一 亲身案例 二 改进方式 三 原理分析 该篇博客为总结自己曾写下的Bug 一 亲身案例 当时的场景为 在controller层获取一笔交易单的信息 前台传给controller层为Map类型的键值对 然后controller层直
  • Android高德地图自定义Mark并实现聚合效果

    Android高德地图自定义Mark并实现聚合效果 起因 公司本来项目里面用到了高德地图 然后最近老板看见别人的APP里面有个聚合的这个功能 老板 这个效果能不能实现 我也要 没有办法因为以前没有做过高德地图点聚合这个东西 然后只能勉强的答
  • 程序员MM一年的工作总结

    11月8号就是 工作 一周年纪念日了 是该对这过去的一年做个总结了 当初来这个公司因为它是第一个递橄榄枝给我的地方 为了尽量少的减少毕业和工作之间的空档时间 就接受了 我在这一年中改变很大 这样的改变是综合的 1 技术 这里所说的技术应该算
  • javaの日志级别

    最近几周给项目补日志 头都大了 项目开发接口时一定要同步日志 一定 首先 日志级别从低到高 all
  • 2012_11月总结分享

    11月份下旬 我在技术上主要看了看spring的IoC容器实现相关的内容 但是这次来不及写了 这是一个很长的故事 就分享了一下11月份遇到的值得记录的东西吧 中间也穿插2篇文章分享 无缝对接 总结如下 1 代码规范问题 2 Tair批量读取
  • Linux部署jar包,隐藏命令行参数

    Linux部署jar包 隐藏命令行参数 一 背景需求 二 查阅资料 三 实现隐藏库 3 1 测试test c 3 2 设置隐藏库 3 3 验证 四 应用jar启动命令 五 直接应用结果 最新项目安全检测 发现配置文件中数据库密码 redis

随机推荐

  • ICCV 2023

    点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入 作者介绍 张耕维 悉尼科技大学在读博士生 研究方向为持续学习 报告题目 通过慢学习和分类器对齐在预训练模型上进行持续学习 内容简介 持续学习研究的目标在于提高模型利用顺序到达的数
  • windows下使用django实现定时任务

    简介 在做 弹幕弹幕 小程序后端时 需要定时清除数据库中无用的弹幕 在网上查得可以使用Django中的django apscheduler实现这一功能 我在这里记录一下使用这一Application的过程 django apschedule
  • vue封装年月日时分秒

  • case when then else_CASE 表达式

    一 语法及作用 使用CASE表达式可以帮助我们解决复杂的查询问题 相当于条件判断的函数 判断每一行是不是满足条件 CASE CASE 表达式会从对最初的WHEN子句中的 lt 求值表达式 gt 进行求值开始执行 所谓求值 就是要调查该表达式
  • STM32CubeIDE使用笔记(01):基础说明与开发流程

    文章目录 目的 基础事项 下载安装 界面说明 项目文件夹 常用快捷键 开发流程 总结 目的 STM32cubeIDE是ST官方推出的一款用于开发STM32的工具 其实就是整合了STM32CubeMX和TrueSTUDIO而成 对于STM32
  • C、C++、C#、python、java编程—数据类型的使用(二)

    四 Python 4 1字符串 1 字符串使用 var1 Hello World var2 Python Runoob print var1 0 var1 0 print var2 1 5 var2 1 5 以上实例执行结果 var1 0
  • 文本同文件一并提交的后端接口处理(一个实体类)

    出现的问题 org springframework web HttpMediaTypeNotSupportedException Content type multipart form data boundary WebKitFormBou
  • jupyter基本使用方法

    jupyter基本使用方法 菜单栏 File Edit View Insert Cell Kernel Help 工具条 单元 快捷键 菜单栏 File Edit View Insert Cell Kernel Help 工具条 单元 在M
  • 图书管理系统数据字典_2. 结构化——数据字典

    返回目录 Chilan Yuk 软件工程分析设计图库目录 zhuanlan zhihu com 一 基本知识 用于定义数据流和数据存储的结构 并给出构成所给的数据流和数据存储的各数据项的基本数据类型 数据字典中应该包括关于数据的如下信息 一
  • BUCK电路分析(二)

    BUCK电路分析 二 PSIM仿真同步BUCK电路 在上片文章中 初步的分析了BUCK电路的工作原理 本章使用PSIM软件仿真BUCK电路 观察分析BUCK电路器件关键波形 图1是同步BUCK电路图 开关频率设置为200K 固定占空比 在仿
  • Game101现代计算机图形学作业1

    Game101现代计算机图形学作业1 一 作业描述 二 解决方法 一 模型变换 二 投影变换 绕任意轴旋转 三 总结 四 参考和引用 一 作业描述 给定三维下三个点 v 0 2 0 0
  • esp32固件下载时有关串口通信的问题

    最近我做了个简易的esp32开发板 用arduino写了点程序 却怎么也传不上去 用arduino上传的时候总是显示 A fatal error occurred Failed to connect to ESP32 No serial d
  • 启用Powershell脚本(因为在此系统上禁止运行脚本)

    以管理员身份运行一个Powershell窗口 get executionpolicy Restricted set executionpolicy remotesigned Y get executionpolicy RemoteSigne
  • c++基于gSoap开发编译异常

    在程序中存在多个gSoap客户端代理类的话 比如我项目中用到的两个NMMAILGgzwSerSoapProxy h和ZJFaxMangerHttpBindingProxy h 其中第一个NMMAILGgzwSerSoapProxy h类是后
  • 解决 pip install requirements.txt 失败问题

    将命令改为 pip install r requirements txt
  • vscode中jupyter控制是否完整输出,是否折叠。

    打开一个笔记本 右上角设置 自定义笔记本布局 设置output scrolling 设置后 重启vscode生效
  • jwt的token自动续约_JWT的TOKEN续期功能

    JWT里有一个关键的东东 就是续期TOKEN 即TOKEN快过期时 刷新一个新的TOKEN给客户端 办法如下 1 后端生成TOKEN import com starmark core shiro model SecurityUser imp
  • 抖音视频怎么制作

    1 抖音拍摄制作 抖音短视频作为一款视频拍摄 分享软件 自身也带有一些功能可以实现抖音视频制作 做出的抖音视频也很好玩 步骤 1 首先安装好抖音并打开软件 点击软件正下方的 2 可以点击 视频 自动拍摄一段视频 或者点击 上传 将已经拍摄好
  • 如何在命令行中显示五彩斑斓的“黑”

    1 前言 大部分 coder 已经习惯了命令行枯燥的黑底白字 而且任何编程语言入门的第一行代码都是教我们如何在标准输出 大部分情况就是命令行终端或控制台 打印一行 非黑即白 的 hello world 以至于很多不懂编程的 大佬 都觉得程序
  • 2012_11月总结分享

    11月份下旬 我在技术上主要看了看spring的IoC容器实现相关的内容 但是这次来不及写了 这是一个很长的故事 就分享了一下11月份遇到的值得记录的东西吧 中间也穿插2篇文章分享 无缝对接 总结如下 1 代码规范问题 2 Tair批量读取