java反射机制在代理模式中的使用

代理模式的核心思路就是一个接口有两个子类,一个子类完成核心的业务操作,另一个子类完成与核心业务有关的辅助性操作。

代理模式分为静态代理模式和动态代理模式。

 静态代理模式:

  1. //接口类  
  2. interface Food{  
  3.     public void eat();  
  4. }  
  5. //核心业务操作类  
  6. class RealFood implements Food{  
  7.     @Override  
  8.     public void eat() {  
  9.         System.out.println(”马小超在吃饭!”);  
  10.     }  
  11. }  
  12. //与核心业务有关的辅助性操作  
  13. class ProxyFood implements Food{  
  14.     private Food food;  
  15.       
  16.     public Food bind(Food food){  
  17.         this.food = food;  
  18.         return this;  
  19.     }  
  20.     @Override  
  21.     public void eat() {  
  22.         this.prepare();  
  23.         this.food.eat();  
  24.         this.after();  
  25.     }  
  26.     private void prepare(){  
  27.         System.out.println(”吃饭钱准备:洗手”);  
  28.     }  
  29.     private void after(){  
  30.         System.out.println(”吃饭后收拾:洗碗”);  
  31.     }  
  32. }  
  33. //测试类  
  34. public class StaticProxy {  
  35.     public static void main(String[] args){  
  36.         Food food = new ProxyFood().bind(new RealFood());  
  37.         food.eat();  
  38.     }  
  39. }  
//接口类
interface Food{
    public void eat();
}
//核心业务操作类
class RealFood implements Food{
    @Override
    public void eat() {
        System.out.println("马小超在吃饭!");
    }
}
//与核心业务有关的辅助性操作
class ProxyFood implements Food{
    private Food food;

    public Food bind(Food food){
        this.food = food;
        return this;
    }
    @Override
    public void eat() {
        this.prepare();
        this.food.eat();
        this.after();
    }
    private void prepare(){
        System.out.println("吃饭钱准备:洗手");
    }
    private void after(){
        System.out.println("吃饭后收拾:洗碗");
    }
}
//测试类
public class StaticProxy {
    public static void main(String[] args){
        Food food = new ProxyFood().bind(new RealFood());
        food.eat();
    }
}
输出结果:

  1. 吃饭钱准备:洗手  
  2. 马小超在吃饭!  
  3. 吃饭后收拾:洗碗  
吃饭钱准备:洗手
马小超在吃饭!
吃饭后收拾:洗碗

如上代码所示,定义一个接口类Food,定义一个实现类RealFood来完成核心业务操作,同时再定义一个代理类ProxyFood来完成与核心业务相关的辅助操作。

在代理类ProxyFood中引入代理对象food,定义辅助操作的方法,在重写的eat()方法中引用辅助操作方法。代码如上面所示。

静态的代理模式都是一个接口两个子类,这样一来就会导致一个类只能为一个接口服务。如果有几十个接口,那项目就别做了,这样的设计有很明显的缺陷。那么怎么样才能解决这个问题了?利用反射就可以解决啦。


动态代理模式:

要实现动态代理,则必须实现反射包中的InvocationHandler接口,该接口中只定义了一个invoke()方法,在代理实例上处理方法调用并返回结果。

  1. Object invoke(Object proxy,Method method,Object[] args)throws Throwable  
Object invoke(Object proxy,Method method,Object[] args)throws Throwable

invoke()方法接受的参数如下:

       proxy:需要代理的对象

       method:表示真实主体要调用的执行方法

       args:调用方法时(上面的method代表的方法)传递的参数

在调用invoke()方法时,所有的真实主体类都需要返回一个代理对象,而这个代理对象由Porxy类中的newProxyInstance方法来完成。

  1. public static Object newProxyInstance(ClassLoader loader,  
  2.                                       Class<?>[] interfaces,  
  3.                                       InvocationHandler h)  
  4.                                throws IllegalArgumentException  
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
                               throws IllegalArgumentException

该方法返回一个指定接口的代理实例,这个指定接口可以将方法调用指派到指定的调用处理程序。

newProxyInstance需要的参数如下:

       loader:定义被代理类的类加载器。

       interfaces:被代理类要实现接口列表

       h:指派方法调用的调用处理程序,用被代理类的实例创建动态代理类的实例,用于真正调用处理程序

代码如下:

  1. import java.lang.reflect.InvocationHandler;  
  2. import java.lang.reflect.Method;  
  3. import java.lang.reflect.Proxy;  
  4. //接口类  
  5. interface DaoI{  
  6.     public void doSave();  
  7.     public Object getById(String id);  
  8. }  
  9. //DaoI实现类,真实主体类,即被代理类  
  10. class DaoImpl implements DaoI{  
  11.     @Override  
  12.     public void doSave() {  
  13.         System.out.println(”执行保存方法【doSave】”);  
  14.     }  
  15.     @Override  
  16.     public Object getById(String id) {  
  17.         System.out.println(”执行根据ID查找对象方法【getById】”);  
  18.         return null;  
  19.     }  
  20. }  
  21. //InvocationHandler实现类  
  22. class DaoProxy implements InvocationHandler{  
  23.     //被代理类的对象  
  24.     private Object target;  
  25.       
  26.     //绑定被代理对象  
  27.     public Object bind(Object target){  
  28.         this.target = target;  
  29.         //返回实现了被代理类所实现的所有接口的Object对象,即动态代理,需要强制转型  
  30.         return Proxy.newProxyInstance(target.getClass().getClassLoader(),   
  31.                 target.getClass().getInterfaces(), this);  
  32.     }  
  33.     //日志记录方法  
  34.     private void log(String method){  
  35.         System.out.println(”进行日志记录,方法为:” + method);  
  36.     }  
  37.     //事物提交方法  
  38.     private void commit(){  
  39.         System.out.println(”事物提交”);  
  40.     }  
  41.       
  42.     /** 
  43.      * <p>Discription:覆盖InvocationHandler接口中的invoke()方法</p> 
  44.      * @param proxy 需要代理的对象 
  45.      * @param method 真实主体要调用的执行方法 
  46.      * @param args 调用方法时传递的参数 
  47.      * @return 
  48.      * @throws Throwable 
  49.      * @author       : lcma 
  50.      * @update       : 2016年10月9日下午2:46:29 
  51.      */  
  52.     @Override  
  53.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  54.         //日志记录操作  
  55.         this.log(method.getName());  
  56.         //使用反射中的invoke()对方法进行动态调用  
  57.         Object obj = method.invoke(this.target, args);  
  58.         //过滤出以do开头的方法,该方法对数据库进行修改,进行事物提交操作  
  59.         if(method.getName().matches(“do[a-zA-Z0-9]+”)){  
  60.             this.commit();  
  61.         }  
  62.         return obj;  
  63.     }  
  64. }  
  65. //测试类  
  66. public class AutoProxy {  
  67.     public static void main(String[] args){  
  68.         //获得代理的实例  
  69.         DaoI dao = (DaoI)new DaoProxy().bind(new DaoImpl());  
  70.         //调用被代理类中的保存方法  
  71.         dao.doSave();  
  72.         System.out.println(”————–分割线—————–”);  
  73.         //获取被代理类中的获取方法  
  74.         dao.getById(”123”);  
  75.     }  
  76. }  
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//接口类
interface DaoI{
    public void doSave();
    public Object getById(String id);
}
//DaoI实现类,真实主体类,即被代理类
class DaoImpl implements DaoI{
    @Override
    public void doSave() {
        System.out.println("执行保存方法【doSave】");
    }
    @Override
    public Object getById(String id) {
        System.out.println("执行根据ID查找对象方法【getById】");
        return null;
    }
}
//InvocationHandler实现类
class DaoProxy implements InvocationHandler{
    //被代理类的对象
    private Object target;

    //绑定被代理对象
    public Object bind(Object target){
        this.target = target;
        //返回实现了被代理类所实现的所有接口的Object对象,即动态代理,需要强制转型
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), 
                target.getClass().getInterfaces(), this);
    }
    //日志记录方法
    private void log(String method){
        System.out.println("进行日志记录,方法为:" + method);
    }
    //事物提交方法
    private void commit(){
        System.out.println("事物提交");
    }

    /**
     * <p>Discription:覆盖InvocationHandler接口中的invoke()方法</p>
     * @param proxy 需要代理的对象
     * @param method 真实主体要调用的执行方法
     * @param args 调用方法时传递的参数
     * @return
     * @throws Throwable
     * @author       : lcma
     * @update       : 2016年10月9日下午2:46:29
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //日志记录操作
        this.log(method.getName());
        //使用反射中的invoke()对方法进行动态调用
        Object obj = method.invoke(this.target, args);
        //过滤出以do开头的方法,该方法对数据库进行修改,进行事物提交操作
        if(method.getName().matches("do[a-zA-Z0-9]+")){
            this.commit();
        }
        return obj;
    }
}
//测试类
public class AutoProxy {
    public static void main(String[] args){
        //获得代理的实例
        DaoI dao = (DaoI)new DaoProxy().bind(new DaoImpl());
        //调用被代理类中的保存方法
        dao.doSave();
        System.out.println("--------------分割线-----------------");
        //获取被代理类中的获取方法
        dao.getById("123");
    }
}
输出结果:

  1. 进行日志记录,方法为:doSave  
  2. 执行保存方法【doSave】  
  3. 事物提交  
  4. ————–分割线—————–  
  5. 进行日志记录,方法为:getById  
  6. 执行根据ID查找对象方法【getById】  
进行日志记录,方法为:doSave
执行保存方法【doSave】
事物提交
--------------分割线-----------------
进行日志记录,方法为:getById
执行根据ID查找对象方法【getById】

动态代理模式可以让我们在不改变原来代码结构的情况下,对原来的“真实方法”进行扩展、增强其功能,并且可以达到控制被代理对象的行为。

动态代理模式运用的知识点就是Java的反射机制,对于上面的代码有些地方我也不是很理解,要想彻底搞懂还有很长的路要走。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值