简述动态代理与hibernate之二

正文


上篇博文讲到了JDK内置的动态代理模式的使用,但是它有一个限制,就是使用动态代理的的对象必须实现一个或者多个接口。如果想代理没有实现接口的类便可以用CGLIB

cglib


cglib在百度百科上的解释是:
cglib是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。Hibernate支持它来实现PO(Persistent Object 持久化对象)字节码的动态生成
正如上面所述,hibernate中便使用cglib来实现PO(上篇博文中所说的mStudent)的动态生成
为了探索真相,也为了跟随老师的脚步,便尝试着手写实现hibernate中PO的生成过程。
源代码如下:
首先定义一个很简单的vo(bean)

student.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.example.vo;
public class Student {
private String sName;
private int sId;
private String sSex;
private String sWeight;
public String getsName() {
return sName;
}
public void setsName(String sName) {
this.sName = sName;
}
public int getsId() {
return sId;
}
public void setsId(int sId) {
this.sId = sId;
}
public String getsSex() {
return sSex;
}
public void setsSex(String sSex) {
this.sSex = sSex;
}
public String getsWeight() {
return sWeight;
}
public void setsWeight(String sWeight) {
this.sWeight = sWeight;
}
}

重写session相关类Session.java


1
2
3
4
5
6
7
package com.example.hibernate;
import java.io.Serializable;
public interface Session {
public Object load(Class clazz,Serializable id);
}

SessionFactory.java


1
2
3
4
5
6
7
package com.example.hibernate;
public class SessionFactory {
public Session openSession(){
return new SessionImpl();
}
}

实现Session接口的类SessionImpl.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.example.hibernate;
import java.io.Serializable;
import com.example.proxy.HibernateMethodIntercepter;
public class SessionImpl implements Session{
@Override
public Object load(Class clazz, Serializable id) {
// TODO Auto-generated method stub
Object obj = new HibernateMethodIntercepter().createProxy(clazz);
return obj;
}
}

代理类HibernateMethodIntercepter.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.example.proxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class HibernateMethodIntercepter implements MethodInterceptor{
public Object createProxy(Class clazz){
Enhancer enhance = new Enhancer();
enhance.setSuperclass(clazz);
enhance.setCallback(this);
return enhance.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
// TODO Auto-generated method stub
if(method.getName().startsWith("get")){
String sql = "select * from student";
System.out.println(sql);
}
System.out.println("method " + method.getName() + " is intercepted");
Object object = methodProxy.invokeSuper(obj, args);
return object;
}
}

在代理类我实现了判断如果执行了查询操作(get()),那么则输出sql语句的功能,因为这里没有实现配置文件的解析,所以只是很简单的实现了输出功能

测试类testProxyHibernate.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import com.example.hibernate.Session;
import com.example.hibernate.SessionFactory;
import com.example.vo.Student;
public class testProxyHibernate {
public static void main(String[] args) {
// TODO Auto-generated method stub
Session session = new SessionFactory().openSession();
Student mStudent = (Student)session.load(Student.class, new Integer(0));
mStudent.setsName("tom");
System.out.println(mStudent.getsName());
mStudent.setsId(19);
}
}

测试结果:

在测试结果中可以看到只要执行了mStudent中的方法,都会被代理类截获,但是只有在执行get方法(查询操作)之前才会输出sql语句

文末


hibernate中是应用cglib动态创建对象,同时cglib也广泛的被许多AOP的框架使用,例如spring,所以掌握动态代理,反射等知识对我们理解框架的原理,框架的思想是很有帮助的。

博文内容纯原创,如有交流请求,请联系我。

分享一个昨天突然冒出来的新梗

你知道么,北京2008年申奥成功了