JDK代理机制 学习总结

来源:互联网 发布:java生成随机数 编辑:程序博客网 时间:2024/06/04 01:17

二、JDK代理机制

1、特点:

1)只能代理接口类。如果实现类中的方法需要增强,可以实现接口,重写接口里的方法即可。

2.)不需要引外界包,jdk  api自带API里有Proxy这个工具类。


2、使用

jdk代理类以一个demo的形式展示用法。

业务需要:通过代理类记录被代理对象中add方法的日志信息。

1)接口类  ProductDao

/** *类说明:商品Dao接口<br/> *创建日期:2016年6月18日<br/>  * */public interface ProductDao {public void addProduct();public void updateProduct();}

2)实现类  ProductDaoImpl

/** *类说明:商品实现类<br/> *创建日期:2016年6月18日<br/>  * */public class ProductDaoImpl implements ProductDao{@Overridepublic void addProduct() {System.out.println("添加商品.....");}@Overridepublic void updateProduct() {System.out.println("更新商品....");}}


3)代理类 ProductProxy

说明:上面的两个类里,ProductDao接口类是被代理对象,接下来这个类 ProductProxy是代理对象,代理  被代理对象 里的addProduct方法(这句话有点饶)。

import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class ProductProxy implements InvocationHandler{/** * 第1步:引入被代理对象 ProductDao */private ProductDao productDao; public ProductProxy(ProductDao productDao){this.productDao = productDao;}/** * 第2步:通过Proxy类的实例化方法产生一个代理对象,并返回 * Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) * 参数解释 */public ProductDao createProductDao(){return (ProductDao) Proxy.newProxyInstance(productDao.getClass().getClassLoader(), productDao.getClass().getInterfaces(), this);}/** * 第1.5步:代理对象拦截 被代理对象 中需要处理的方法,然后进行处理,这里是为add方法添加日志信息  */@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if(method.getName().equals("addProduct")){//拦截到指定的方法  addProduct()System.out.println("这里是需要打印的日志信息......");return method.invoke(productDao, args); //执行方法}else{ //其他方法return method.invoke(productDao, args); //执行方法}}}
步骤:

第1步:引入被代理对象,这里是ProductDao;

第2步:产生一个代理对象并返回。

这里需要说明的是,我第一次学习这的时候就很烦恼,代理对象究竟是如何产生的呢?

  可以简单的理解为java自带一个工具类 Proxy ,这个类有个静态方法 newProxyInstance(xx,xx,xx),,我们只要知道调用这个方法,并且转换下类型就可以得到代理即可。

还有一点需要了解的就是这个方法里的三个参数:

Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
* ClassLoader   loader : 类加载器,不理解的话直接记忆      productDao.getClass().getClassLoadeer()   ,这里的productDAO是被代理对象。

* Class<?>[]   interfaces : 类接口,前面说了jdk代理只能代理接口,这里代理的接口是ProductDao ,这里应写为: productDao.getClass().getInterfaces()。

* InvocationHandler   h : 这个类的作用体现在第1.5步里,首先我这里实现了这个接口,所以参数位置可以直接写this,代表invacationHandler的实现类。

其次为什么要写第1.5步呢,第2步的作用是产生一个代理对象并返回,但是如果什么操作都不做就返回就没有意思,第1.5不的作用就是截取需要处理的方法去处理。

第1.5步:在返回代理对象前执行的一个步骤,用来处理需要处理的方法。这个方法是实现InvovationHandler接口后重写的方法。

invoke()方法的三个参数简单介绍一个:proxy 代理对象,method 方法对象,args 参数

需要记忆的:

method.getName 是获得被代理对象的方法名,这里隐式的 遍历 了被代理对象里的所有方法。

method.invoke(productDao,args)  是执行被代理对象的原方法。究其本质,虽然会被add方法进行处理,但没有对原方法进行任何的改变。


4)测试结果

比较了使用代理和没有使用代理执行方法的结果,一目了然看出代理的作用:

public class TestJDKProxy {public static void main(String[] args) {//未使用代理对象执行方法System.out.println("===========================未使用代理对象执行方法===============================");ProductDao productDao = new ProductDaoImpl();productDao.addProduct();productDao.updateProduct();//使用代理对象执行方法System.out.println("==========================使用代理对象执行方法================================");ProductDao productDao2 = new ProductDaoImpl();ProductProxy productProxy = new ProductProxy(productDao2);productDao2 = productProxy.createProductDao();productDao2.addProduct();productDao2.updateProduct();}}

控制台打印语句:

===========================未使用代理对象执行方法===============================
添加商品.....
更新商品....
==========================使用代理对象执行方法================================
这里是需要打印的日志信息......
添加商品.....
更新商品....






0 0