zoukankan      html  css  js  c++  java
  • Java反射机制在代理模式中的使用

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

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

     静态代理模式:

    //接口类
    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();
    	}
    }
    

     输出结果:

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

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

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

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

    动态代理模式:

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

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

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

           proxy:需要代理的对象

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

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

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

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

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

    newProxyInstance需要的参数如下:

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

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

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

    代码如下:

    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");
    	}
    }
    
    进行日志记录,方法为:doSave
    执行保存方法【doSave】
    事物提交
    --------------分割线-----------------
    进行日志记录,方法为:getById
    执行根据ID查找对象方法【getById】
    

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

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

    https://blog.csdn.net/mlc1218559742/article/details/52767156

  • 相关阅读:
    Java多线程之 对同一个值操作
    Java 之 应用多线程计算1+2+...+100之多种方法比较(二)
    Java 之 应用多线程计算1+2+...+100之多种方法比较(一)
    SQL语句优化
    第六章:shiro Realm相关对象
    第五章:shiro密码加密
    第四章:shiro的INI配置
    第三章:shiro授权认证
    第二章:shiro身份验证
    第一章:Shiro简介
  • 原文地址:https://www.cnblogs.com/leijiangtao/p/4463061.html
Copyright © 2011-2022 走看看