代理模式顾名思义,有一个代理类,一个被代理的目标对象,代理类可以在目标类的方法前后做一些事情。
实际上,一旦配置完毕,目标类的所有方法前后都会做那些事情。
我用自己的话总结一下,别喷。
有两种方法 一种是java反射机制,另一种效率比较好,采用cglib,后者也是spring AOP采用的技术。
直接上例子
一个接口,不一定是dao举例子而已
public interface StudentDao {
public void saveStudent();
public void queryStudent();
}
一个实现以上接口的类。
public class StudentDaoImpl implements StudentDao {
@Override
public void saveStudent() {
System.out.println("保存学生资料。。。。");
}
@Override
public void queryStudent() {
System.out.println("查询学生资料。。。。");
}
}
代理 类
public class DAOProxy implements InvocationHandler {
private Object originalObject;
public Object bind(Object obj) {
this.originalObject = obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
.getClass().getInterfaces(), this);
}
void preMethod() {
System.out.println("----执行方法之前----");
}
void afterMethod() {
System.out.println("----执行方法之后----");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
preMethod();
result = method.invoke(this.originalObject, args);
afterMethod();
return result;
}
}
##
代理类继承了java.lang.reflect.InvocationHandler;
bind这个方法绑定代理对象和目标对象,其中:Proxy.newProxyInstance接收三个参数,①类加载器②目标对象实现的所有接口③代理对象本身
bind方法把目标对象拿到,绑定好,又作为返回值传递回来,所以绑定之后的目标对象是增加了代理功能后的了
第二个参数是接口,所以,用java反射机制实现动态代理,那目标对象一定要实现接口
invoke方法也接收三个参数:①代理对象②要用代理的方法③这个方法的参数
我之前只学过基础java反射,知道这是反射的方法,只是多了一个代理对象
测试类如下
public class TestDaoProxy extends TestCase {
public void testDaoProxy(){
StudentDao studentDao = new StudentDaoImpl();
DAOProxy daoProxy=new DAOProxy();
studentDao = (StudentDao)daoProxy.bind(studentDao);
studentDao.queryStudent();
}
}
换成目标类中的另一个方法也是通用的。
下面是第二中方法,第二中方法使用cglib技术,需要jar包,jar包在spring的依赖包中有,3.0已经继承进主jar包,2.5有单独的jar包
cglib和前一个方法的不同是没有接口也可以
目标类如下
public class StudentDao {
public void saveStudent() {
System.out.println("保存学生资料。。。。");
}
public void queryStudent() {
System.out.println("查询学生资料。。。。");
}
}
代理类如下
public class DAOCglibProxy implements MethodInterceptor {
private Object originalObject;
public Object bind(Object obj) {
this.originalObject = obj;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(obj.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
void preMethod() {
System.out.println("----执行方法之前----");
}
void afterMethod() {
System.out.println("----执行方法之后----");
}
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
preMethod();
Object result = proxy.invokeSuper(obj, args);
afterMethod();
return result;
}
}
测试方法如下
public void testDAOCglibProxy() {
StudentDao studentsDao = new StudentDao();
DAOCglibProxy proxy = new DAOCglibProxy();
studentsDao = (StudentDao) proxy.bind(studentsDao);
studentsDao.queryStudent();
}
cglib实际上是通过继承出一个子类实现的代理。可以把Enhancer看做那个子类的生成器 ,所以在bind方法中,指定父类,然后绑定好代理对象就可以了
指定父类:enhancer.setSuperclass(obj.getClass());
绑定代理方法:enhancer.setCallback(this);
然后返回创建好的已经加了代理的目标对象:return enhancer.create();
在测试类中使用的时候很简单,只要绑定好,然后执行就行。
可见还是cglib这个方法更方便,而且据说效率最高。所以spring采用之。