【java设计模式】两种步骤java实现动态代理

【java设计模式】两种方法java实现动态代理

来自视频教程的笔记http://wenku.baidu.com/course/view/192a0066f5335a8102d22000?cid=5

 

代理模式顾名思义,有一个代理类,一个被代理的目标对象,代理类可以在目标类的方法前后做一些事情。

实际上,一旦配置完毕,目标类的所有方法前后都会做那些事情。

 

我用自己的话总结一下,别喷。

 

有两种方法 一种是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采用之。