如鹏网 大学生计算机学习社区

CowNew开源团队

http://www.cownew.com 邮件请联系 about521 at 163.com

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  363 随笔 :: 2 文章 :: 808 评论 :: 0 Trackbacks

#

为了巩固 CGLib 的知识,下面我们实现一个稍微复杂一点的例子。

例、请实现一个拦截器,使其能够检测一个 JavaBean 的哪些字段改变了。

1 )首先定义一个 JavaBean

public class PersonInfo

{

     private String name;

 

     private String email;

 

     private int age;

 

     private String address;

 

     public String getEmail()

     {

         return email;

     }

 

     public void setEmail(String email)

     {

         this.email = email;

     }

 

     public String getName()

     {

         return name;

     }

 

     public void setName(String name)

     {

         this.name = name;

     }

 

     public String getAddress()

     {

         return address;

     }

 

     public void setAddress(String address)

     {

         this.address = address;

     }

 

     public int getAge()

     {

         return age;

     }

 

     public void setAge(int age)

     {

         this.age = age;

     }

}

2 )定义一个 MethodInterceptor ,这一步是最关键的

import java.lang.reflect.Method;

import java.util.Collections;

import java.util.HashSet;

import java.util.Set;

 

import net.sf.cglib.proxy.MethodInterceptor;

import net.sf.cglib.proxy.MethodProxy;

 

public class JavaBeanDataChangeInterceptor implements MethodInterceptor

{

     private static final String SET = "set";

 

     private Set changedPropSet;

 

     public JavaBeanDataChangeInterceptor()

     {

         changedPropSet = new HashSet();

     }

 

     public Object intercept(Object obj, Method method, Object[] args,

              MethodProxy proxy) throws Throwable

     {

         String name = method.getName();

         if (name.startsWith(SET))

         {

              String s = name.substring(SET.length());

              changedPropSet.add(s);

         }

         return proxy.invokeSuper(obj, args);

     }

 

     public Set getChangedPropSet()

     {

         return Collections.unmodifiableSet(changedPropSet);

     }

 

     public void reset()

     {

         changedPropSet.clear();

     }

}

定义一个集合 changedPropSet 用来存放修改了的字段名,增加了一个方法 reset 用来清空此集合,增加了一个 getChangedPropSet 方法用来供外界得到修改了的字段,为了防止调用者对 changedPropSet 做修改,因此我们采用 Collections.unmodifiableSet 对返回的集合进行不可修改的修饰。

intercept 方法中,我们判断如果被调用的方法以 set 开头,则把此字段名放入 changedPropSet 集合中。

3 )定义剖析用工具类。

import net.sf.cglib.proxy.Callback;

import net.sf.cglib.proxy.Factory;

 

public class JavaBeanInterceptorUtils

{

     public static JavaBeanDataChangeInterceptor getInterceptor(

              Object obj)

     {

         if (!(obj instanceof Factory))

         {

              return null;

         }

         Factory f = (Factory) obj;

         Callback[] callBacks = f.getCallbacks();

         for (int i = 0, n = callBacks.length; i < n; i++)

         {

              Callback callBack = callBacks[i];

              if (callBack instanceof JavaBeanDataChangeInterceptor)

              {

                   return (JavaBeanDataChangeInterceptor) callBack;

              }

         }

         return null;

     }

}

这个 JavaBeanInterceptorUtils 只有一个方法 getInterceptor ,这个方法用于从一个被 CGLib 代理的 JavaBean 中取出拦截器 JavaBeanDataChangeInterceptor

前边提到了, CGLib 实现拦截的方式就是生成被拦截类的子类,这个子类实现了 net.sf.cglib.proxy.Factory 接口,这个接口中有一个非常重要的方法 getCallbacks() ,通过这个方法我们可以得到所有的拦截器

4 主程序

public class MainApp

{

     public static void main(String[] args)

     {

         Enhancer enhancer = new Enhancer();

         enhancer.setSuperclass(PersonInfo.class);

         enhancer.setCallback(new JavaBeanDataChangeInterceptor());

 

         PersonInfo info = (PersonInfo) enhancer.create();

         // 对生成的 JavaBean 做一些初始化

         info.setAddress(" 地址 1");

         info.setAge(21);

         info.setName("tom");

 

         // 得到拦截器

         JavaBeanDataChangeInterceptor interceptor = JavaBeanInterceptorUtils

                   .getInterceptor(info);

         // 复位修改字段记录集合

         interceptor.reset();

 

         // JavaBean 做一些修改

         editPersonInf(info);

 

         // 得到修改了的字段

         Iterator it = interceptor.getChangedPropSet().iterator();

         while (it.hasNext())

         {

              System.out.println(it.next());

         }

     }

 

     private static void editPersonInf(PersonInfo info)

     {

         info.setName("Jim");

         info.setAddress("N.Y Street");

     }

}   

运行结果:

Address

Name

 

这个“变化字段拦截器”是有一定实际意义的,比如可以用来实现“只保存修改了的字段以提高效率”等功能

 

很多资料中都说如果要使用 JDK Proxy ,被代理的对象的类必须要实现接口,这种说法是不严谨的。从上边的例子我们可以看出,正确的说法应该是:如果要使用 JDK Proxy ,那么我们要通过代理调用的方法必须定义在一个接口中。“面向接口编程而不是面向实现编程”是 OOP 开发中的一条基本原则,因此这种限制并不会对我们的开发造成障碍。

posted @ 2007-02-20 00:50 CowNew开源团队 阅读(345) | 评论 (0)编辑 收藏

     摘要: 服务器通过配置文件将符合特定格式的 URL 同 Servlet 建立对应关系,当一个客户端请求到达服务器的时候,服务器就会分析其 URL 格式并派发给合适的 Servlet 处理,然后将 Servlet 处理完成的结果返回给客户。 与 ASP 、 ...  阅读全文
posted @ 2007-02-19 21:45 CowNew开源团队 阅读(784) | 评论 (0)编辑 收藏

公司安排偶做终端字符界面库,这是我半个月做出来的东西,呵呵,挺有意思,与大家分享。
p3.JPG

这是用这些控件搭建出来的程序界面,供大家把玩
p1.JPGp2.JPG
posted @ 2007-02-13 17:37 CowNew开源团队 阅读(536) | 评论 (2)编辑 收藏

对象图
XStream支持对象图,也就是“反序列化”一个对象的时候将会保持原来的对象引用关系,这其中包括循环引用关系。 我们可以指定XStream是使用XPath还是IDs来实现对象引用的这种处理方式,指定的方式就是调用XStream的setMode方法,此方法有XStream.XPATH_REFERENCES、XStream.ID_REFERENCES、XStream.NO_REFERENCES三个选项。其意义分别如下:
XStream.XPATH_REFERENCES:这是默认值。这个选项指定XStream使用XPath引用方式处理重复引用。
XStream.ID_REFERENCES:这个选项指定XStream使用ID引用方式处理重复引用。当使用手写XML的时候,这种方式可能更好用一些。 
XStream.NO_REFERENCES:这个选项指定XStream不支持图引用,将对象结构当做树状处理。重复的引用将会被认为是两个独立的对象,而循环引用将会导致一个异常。这种方式速度会更快一些,并且相对于前两者来说占用更少的内存。
自定义转换器
XStream对String, Date, int, boolean等基本类型以及Map, List, Set, Properties等集合类型提供了转换器,因此这些类型可以轻松的实现序列化和反序列化。如果您使用的数据类型不被XStream支持,那么就需要自定义数据转换器。自定义转换器要实现com.thoughtworks.xstream.converters.Converter接口,这个接口定义了如下三个方法:
boolean canConvert(Class type);
void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context);
Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context);
这三个方法分别表示:type这个类型的数据此转换器是否有能力转换;将对象进行编组(marshal)为XML格式;将XML格式反编组(unmarshal)为对象。
我们通常无需直接实现该接口,而是继承com.thoughtworks.xstream.converters.MarshallingContext.AbstractBasicConverter抽象类,然后覆盖:
protected String toString(Object obj)
protected Object fromString(String str);
两个方法即可。可以参考com.thoughtworks.xstream.converters.extended.SqlTimestampConverter的实现代码。
转换器开发完毕以后调用XStream类的public void registerConverter(Converter converter)方法注册转换器。
posted @ 2007-02-13 09:38 CowNew开源团队 阅读(814) | 评论 (0)编辑 收藏

为什么使用数据源
在帐套配置项中,我们使用数据源来表示对应的数据库连接。使用数据源有两个好处:对开发人员屏蔽数据库细节,只要通过JNDI取得数据源就可以了,无需关心数据库连接是如何建立的;数据源通常都提供了数据库连接池的功能。
数据库连接是一种关键的有限的昂贵的资源,而且数据库连接的建立和关闭也是很耗费系统资源的。在传统的两层C/S架构中,一个客户端对应一个数据库连接,在用户活动期间就独占此连接;而在分布式系统中,数据库连接的建立与关闭是异常频繁的,因此数据库连接的对系统的性能影响更是明显。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标。数据库连接池正是针对这个问题提出来的。
数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数来设定的。数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而再不是重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。
JDBC3.0规范中规定了如下的接口和类来实现数据库连接池:
javax.sql.ConnectionEvent:连接事件
javax.sql.ConnectionPoolDataSource:连接池数据源
javax.sql.PooledConnection:被池化的连接
javax.sql.ConnectionEventListener:连接事件监听接口
上边这些接口和类是对数据库连接池内部实现的规定,对于使用者来说是透明的。数据库连接池的使用者一般只和DataSource接口直接打交道,通过这个接口获得数据库连接,其主要方法为:
Connection getConnection():得到一个数据库连接
Connection getConnection(String userName,String password):得到一个数据库连接
java.io.PrintWriter getLogWriter():获得Log Writer的对象
void setLogWriter(java.io.PrintWriter out):设置Log Writer
void setLoginTimeout(int seconds):设置数据源尝试连接数据库的最大时间
int getLoginTimeout():获得数据源尝试连接数据库的最大时间
开源社区中有很多数据库连接池的实现,比如PoolMan等,使用这些数据库连接池包可以保证跨应用服务器的移植。不过在本案例系统中,我们使用应用服务器的数据源功能提供的数据库连接池。数据源在不同的服务器中有不同的配置方式,下面介绍Tomcat中数据源的配置。
打开%TOMCAT_HOME%\conf\server.xml,在</Context>和</host>前添加如下配置文件项:
<Context docBase="CowNewPIS" path="/CowNewPIS"      reloadable="true">
<Resource type="javax.sql.DataSource"
      auth="Container" name="jdbc/PISMSSQL_Dev" />
<ResourceParams name="jdbc/PISMSSQL_Dev">
<parameter>
<name>maxWait</name>
<value>5000</value>
</parameter>
<parameter>
<name>maxActive</name>
<value>4</value>
</parameter>
<parameter>
<name>password</name>
<value></value>
</parameter>
<parameter>
<name>url</name>
<value>
jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=PISDev1106
</value>
</parameter>
<parameter>
<name>driverClassName</name>
<value>
com.microsoft.jdbc.sqlserver.SQLServerDriver
    </value>
</parameter>
<parameter>
<name>maxIdle</name>
<value>2</value>
</parameter>
<parameter>
<name>username</name>
<value>sa</value>
</parameter>
</ResourceParams>
</Context>
 
在配置的时候,要指定数据库的JDBC驱动、数据库连接URL等。数据源配置完毕,重启服务器。编写一个测试客户端:
Context ctx=null;
Connection conn=null;
try
{
ctx=new InitialContext();
DataSource ds=(DataSource)ctx.lookup("java:comp/env/jdbc/PISMSSQL_Dev");
conn=ds.getConnection();
}
finally
{
if(conn!=null)
conn.close();
if(ctx!=null)
ctx.close();
}

Tomcat启动的时候会将Server.xml中的数据源配置绑定到JNDI中,我们可以在应用服务器启动的时候用代码来代替Tomcat完成绑定:
BasicDataSource bdds = new BasicDataSource();
//设置数据库驱动
bdds.setDriverClassName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
//设置JDBC的URL
bdds.setUrl("jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=PISDev1106");
bdds.setUsername("sa");
//设置连接池初始大小
bdds.setInitialSize(2);     
//JNDI配置
Map env = new Hashtable();
env.put("java.naming.factory.initial",
"org.apache.naming.java.javaURLContextFactory");
InitialContext ctx=new InitialContext(env);     
//数据源绑定到JNDI
ctx.bind("jdbc/PISMSSQL_Dev",bdds);

这样我们可以把数据源的配置文件移到ServerConfig.xml中,增加类似如下的配置:
<DataSources>
<DataSource
name=”jdbc/PISMSSQL_Dev” driverClassName=”com.microsoft.jdbc.sqlserver.SQLServerDriver”
url=”jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=PISDev1106”
userName=”sa”
>
</DataSource>
</DataSources>
在应用服务器启动的时候,到ServerConfig.xml中读取数据源配置完成绑定。这种方式一是减少了实施人员配置文件的工作量,服务端的任何配置都可以在这个配置文件中完成;二是使得系统在不同服务器之间移植变得更加容易。

posted @ 2007-02-13 09:37 CowNew开源团队 阅读(338) | 评论 (0)编辑 收藏

BeanUtils
BeanUtils是Apache-Commons项目提供的另一个非常方便的类库,通过这个类库能够更方便的使用反射。最常用的类是BeanUtils(org.apache.commons.beanutils包中),使用这个类能通过名字访问一个Bean中的某个属性。
通过BeanUtils.getProperty(person,”age”)能得到person的age属性。此方法还支持内嵌对象,比如BeanUtils.getProperty(person,”manager.name”)就能得到person的manager属性的name属性。还支持List和Map类型的属性,如下面的语法即可取得Order的顾客列表中第一个顾客的名字BeanUtils.getProperty(orderBean, "customers[1].name")。 使用BeanUtils.setProperty方法则可以设置javaBean的属性值。
ConstructorUtils提供了调用构造函数的方法,使用public static Object invokeConstructor(Class klass, Object arg)可以直接调用某个类的构造函数。
MethodUtils提供了调用bean方法的方法,使用MethodUtils.invokeMethod(bean, methodName, parameter);可以直接调用某个类的某个方法。
PropertyUtils提供了更详细的属性访问方法,使用public static Class getPropertyType(Object bean, String name)获取属性的Class类型。
UserInfo userInfo = (UserInfo) ConstructorUtils.invokeConstructor(
    UserInfo.class, new Object[] {});
PersonInfo personInfo = (PersonInfo) ConstructorUtils
    .invokeConstructor(PersonInfo.class, new Object[] {});
BeanUtils.setProperty(personInfo, "age", new Integer(20));
BeanUtils.setProperty(personInfo, "name", "Tom");
BeanUtils.setProperty(userInfo, "number", "admin");
  BeanUtils.setProperty(userInfo, "person", personInfo);
System.out.println(BeanUtils.getProperty(userInfo, "person.name"));
BeanUtils.setProperty(userInfo, "person.name","xdx");
System.out.println(BeanUtils.getProperty(userInfo, "person.name"));
System.out.println(PropertyUtils.getPropertyType(userInfo,"person"));
运行结果:
Tom
xdx
class com.cownew.PIS.basedata.common.PersonInfo
posted @ 2007-02-05 12:49 CowNew开源团队 阅读(761) | 评论 (1)编辑 收藏

     摘要: LDBC 支持的语法 ( 1 ) Insert 语句 插入单行数据: INSERT INTO tableName [ (columnName [,...] ) ...  阅读全文
posted @ 2007-02-05 12:44 CowNew开源团队 阅读(570) | 评论 (0)编辑 收藏

虽然使用正则表达式能很好的进行字符串的解析、提取、替换,但是对于一些简单的应用,使用 String 类提供的一些方法就可以很好的完成,最突出的就是 split 方法。

split 方法能够很方便的将字符串按照一定的规则拆分开。

比如对于下面的字符串:

Tom,Jane,Tony,Elva,Gigi

只要调用如下的代码就可以将各个名字提取出来:

String value = "Tom,Jane,Tony,Elva,Gigi";

String[] names = value.split(",");

for(int i=0,n=names.length;i<n;i++)

{

     System.out.println(names[i]);

}

运行结果:

Tom

Jane

Tony

Elva

Gigi

 

看到这个运行结果,很多人都认为 split 方法就是按照给定的字符串对字符串进行拆分,知道碰到了下面的问题。

有一个字符串:中国 . 北京 . 海淀 . 学院路。请解析此字符串,并打印输出“中国 北京 海淀 学院路 ”。

于是写代码如下:

String value = " 中国 . 北京 . 海淀 . 学院路 ";

String[] names = value.split(".");

for(int i=0,n=names.length;i<n;i++)

{

     System.out.print(names[i]+" ");

}

运行结果:

 

对,没看错!没有任何输出!

让我们来看看 split 方法的方法签名吧:

public String[] split(String regex)

这里的参数的名称是 regex ,也就是 Regular Expression (正则表达式)。这个参数并不是一个简单的分割用的字符,而是一个正则表达式,看了 split 方法的实现代码就更坚定了我们的信心:

public String[] split(String regex, int limit) {

     return Pattern.compile(regex).split(this, limit);

}

split 的实现直接调用的 Matcher 类的 split 的方法。读者已经知道,“ . ”在正则表达式中有特殊的含义,因此我们使用的时候必须进行转义。

修改代码如下:

private static void split2()

{

     String value = " 中国 . 北京 . 海淀 . 学院路 ";

     String[] names = value.split("\\.");

     for(int i=0,n=names.length;i<n;i++)

     {

         System.out.print(names[i]+" ");

     }

}

运行结果

中国 北京 海淀 学院路

posted @ 2007-01-20 23:38 CowNew开源团队 阅读(2825) | 评论 (9)编辑 收藏

CowNewSQL的扩展:
要编写对新的数据库的支持必须首先开发翻译器,翻译器必须实现IMethodTranslator接口,不过一般只要从BaseMethodTranslator派生即可,BaseMethodTranslator类已经提供了标准的SQL的翻译。因为方法的翻译在BaseMethodTranslator中实现时是独立到一个方法翻译器中的,所以派生类要通过getMethodTranslator方法提供方法翻译器,方法翻译器要实现IMethodTranslator接口,一般从BaseMethodTranslator派生即可。翻译器开发完毕,调用DialectManager类的registerTranslator方法将翻译器注册到系统中。
CowNewSQL的编译
CowNewSQL使用JDK1.5语法编写的,因此如果要在JDK1.4的平台上运行必须使用RetroTranslator将二进制代码编织成在JDK1.4下能运行的二进制代码。RetroTranslator的使用非常简单,在命令行敲入如下指令即可完成代码编织:
java -jar retrotranslator-transformer-1.0.7.jar -srcjar F:\资料\写书\ZDisk\lib\common\cownewSQLjdk5.jar -destjar F:\资料\写书\ZDisk\lib\common\cownewSQLjdk4.jar
RetroTranslator对JDK1.5中枚举等类型的支持是通过RetroTranslator的运行时包来实现的,因此运行时还需要将RetroTranslator的运行时包retrotranslator-runtime-***.jar加入到类路径中。
posted @ 2007-01-20 23:36 CowNew开源团队 阅读(2101) | 评论 (0)编辑 收藏

原文:
http://community.csdn.net/Expert/topic/5294/5294255.xml?temp=.9256861

汇总我的观点:
1、大家应该理性的看待这个问题,尽管从短期来看,这种行为会使大家在短期内受害,但是我想为这家公司喝彩,中国的知识产权保护观念太淡薄了,也间接导致了国内IT环境的乌烟瘴气,利润越来越低。随着中国入世的脚步,国人的版权观念会逐渐加强的。到那个时候国内才会有一个良性循环的环境。
2、大家还记得当年的打假英雄王海吗?尽管他是在借着打假赚钱,也被很多人骂,很多人对他的做法也是嗤之以鼻,可是理性的思考一下,他的行为是不是有积极的意义呢?假如北京美好景象这样的公司再多一点,或者我们每个公司都像北京美好景象这样,那么还有人敢盗用别人的东西吗,还敢随便用网上下载的图片吗,还敢随便用网上下载来的软件包吗,还敢随便用盗版软件搞低价竞争吗?这样我们产品的成本提高了,软件开发的门槛提高了,市场规范了,那么IT业规范化、良性化、规模化发展的格局也就离我们不远了。
如果我见了北京美好景象的老总,我会对他说:你真他妈的无耻,不过我支持你!
3、“我们是要强调版权,但问题是有的图片你从baidu获取的,你知不知道这个图片是不是有版权?”,你连一点的知识产权的观念都没有,悲哀!做商业开发所用的任何东西,除非是明确表示能被免费用于商业用途,否则你都不能未经授权使用。如果你还不理解的话,希望你想想你去黑市买偷来的车是合法的吗?
4、“不过他是应该在图片上写明什么东西的,你这样不写,如果你在用别人的东西的时候,不是也会 被陷害 吗”。严格来说,你用别人的东西的时候必须要他证明这个东西是他合法占有的,并要他书面授权你使用。这听起来有点变态,不过这正是一个高度发达的法制社会的最终目标。如果你听过罗永浩的“小心地滑”、“毒药请勿吞服”那几段语录的话,就明白米国的法治社会是什么样的了,我不是崇洋媚外,但是不得不承认的是在很多事情上我们和很多国家还有很大差距。

总之,支持无耻的“北京美好景象图片有限公司”。
posted @ 2007-01-16 01:06 CowNew开源团队 阅读(1185) | 评论 (7)编辑 收藏

仅列出标题
共30页: First 上一页 15 16 17 18 19 20 21 22 23 下一页 Last