Play1.2.x源代码阅读之 enhancers

原文:http://ju.outofmemory.cn/entry/17848

Play中的代码增强是play的魔力之源。Play自己控制java源代码的编译与载入,所以有机会在载入到jvm之前,调用各种enhancer对字节码进行增强,从而获得超强的功能。

Play的代码增强都是基于javassist这个超级强大又易用的字节码工具库。

play.classloading.enhancers.Enhancer

Enhancer是一个abstract的基类,为其它enhancer做了一些准备工作,提供了一些工具方法。它创建了一个javassist.ClassPool实例,并把自定义的ApplicationClassLoader所使用的classpath、以及当前项目中的java源代码路径都传了进去,以保证javassist可以找到所有需要的源代码。

Play中通常使用Annotation作为增强的标记,所以它提供了很多与之相关的工具方法,供子类使用,如hasAnnotation/createAnnotation等。

最关键的方法是一个虚方法:enhanceThisClass(ApplicationClass applicationClass),子类需要实现该方法。传入的ApplicationClass实例相当于一个java源文件,它保存了源文件,原始字节码等信息,在子类中可使用javassist相关方法对原始子节码进行操作,并把增强后的字节码赋给applicationClass.enhancedByteCode

play.classloading.enhancers.PropertiesEnhancer

Play已经内置了一些enhancer。首先是这个PropertiesEnhancer,它可以让我们用字段来实现Property。

在play中,我们可以这样定义类:

public class User {
    public String name;
    public String email;
}

同时在其它类中,也可以直接访问这些字段:

User user = new User();
System.out.println(user.name);

这种方式,让我们的代码看起来简单很多,因为我们不需要再定义一大堆的getter和setter,也不需要在赋值时使用user.setName(”)这种复杂的方式。

这样会让我们有些疑问,因为很多库如hibernate,会对getter/setter进行增强,插入它们自己的代码。而我们这样写,会不会跟他们产生矛盾?

Play通过javassist的强大功能,解决了这个问题。首先是为User类添加getter/setter:如果某个字段是public的,并且没有找到对应的getter/setter,则创建。然后,把项目中包括其它java类对这些字段的所有访问,全部替换为相应的getter/setter。

这样我们看到且操作的是字段,由实际上都被转换为getter/setter,所以不会与其它的库产生冲突。

play.classloading.enhancers.LVEnhancer

LV是指LocalVariable,这个类在Play1.2.5及之前的版本中不叫这个名字,我fork的是play1.3.x。

它的作用是为类中为每一个方法添加一个字段,记录其参数名称。因为play自己调用了eclipse的jdt进行编译,并且在编译时保留了参数名称,所以它可以得到正确的参数名称。这样做比较有用,你还记得我们在定义action时,可以直接定义一些参数,就能拿到同名的request param吗?

public static void login(String username, String password) {
    // 直接使用username和password,它们对应reuqest.params.get("username")和get("password")
}

要是在别的框架中,最起码也要这么写:

public static void login(@Param("username") String username, 
                         @Param("password") String password) {
}

这就是因为play已经事先把login方法对应的参数名记录下来了。

另外,play还会将局部变量的名字也保存起来,比如我可以在action中这么写:

public static void hello() {
    String name = "world";
    render(name);
}

Play将会把name这个名字与它的值保存在一个栈中,之后可以通过值找到相应的名字。

如果在其它的框架中,就得写成这样:

public static void hello() {
    String name = "world";
    Map data = new HashMap();
    data.put("name", name);
    render(data);
}

Play让我们的代码尽可能的简洁。

具体实现细节以后补充。

play.classloading.enhancers.SigEnhancer

该类会计算某一个类的特征,比如类名,各字段、方法相关的类型和名称,static初始化代码等,把它们保存applicationClass的sigChecksum字段中。

当Play执行detectChanges时,会在每次enhance一个类前后对比该值,如果发现变化了,则抛出异常。但我还不太明白为什么要这么做,留待以后。

play.classloading.enhancers.ControllersEnhancer

该类对controller进行增强。

我们在action中,可以直接调用一些static字段,如request.getXxx(), params.get(“xxx”)。在调用时,我们知道它们是“线程安全”的,但是,为什么?要知道它们是static的,是可以被多线程同时访问的。

原来ControllersEnhancer对它们进行的替换。当我们调用"params"’、 "request"、 "response"、 "session"、 "params"、 "renderArgs"、 "routeArgs"、 "validation"、 "inbound"、 "outbound"、 "flash" 这些参数时,它们都会被替换为:

Xxx.current()

这样的形式,从而从ThreadLocal中获取当前线程绑定的值。

该类还进行了其它增强,比如当一个action被调用时要进行判断,是当作一个普通的方法调用,还是返回一个redirect的response给客户端。

另外,play中render()等方法,会以抛出异常的方式判断模板层,为了保证该异常不会被其它类捕获,在这里也进行了检查和屏蔽。

play.classloading.enhancers.MailerEnhancer

该类向Mailer相关的controller中插入了一些保护性代码,具体作用不明。

play.classloading.enhancers.ContinuationEnhancer

该类可让我们的controller支持如continuation,以支持像ajax聊天室那样的功能。即当我们的代码需要等待一些数据(如IO操作,新的聊天信息的到来)时,在保持http连接不断开的同时,腾出当前线程做别的事情。当需要的数据到达时,再恢复线程继续刚才的事情。这样就不会有线程处于无谓的等待状态,可处理更多的请求。

Play使用了commons-javaflow这个库来实现该功能。当我们的代码调用了controller中的await方法时,则会使用org.apache.commons.javaflow.bytecode.transformation.asm.AsmClassTransformer这个类,来增强当前类。

细节之处待以后研究。



购物商城项目采用PHP+mysql有以及html+css jq以及layer.js datatables bootstorap等插件等开发,采用了MVC模式,建立一个完善的电商系统,通过不同用户的不同需求,进行相应的调配和处理,提高对购买用户进行配置….zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值