代理模式

代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

静态代理

/**
 * 接口
 * @author wj
 *
 */
interface IuserDao{
	void save();
}
/**
 * 目标对象
 * @author wj
 *
 */
class UserDao implements IuserDao{

	@Override
	public void save() {
		// TODO Auto-generated method stub
		System.out.println("已经保存数据");
	}
	
}
/**
 * 代理对象
 * @author wj
 *
 */
class UserDaoProxy implements IuserDao{
	UserDao userdao;
	public UserDaoProxy(UserDao userdao) {
		// TODO Auto-generated constructor stub
		this.userdao = userdao;
	}

	@Override
	public void save() {
		// TODO Auto-generated method stub
		this.userdao.save();
	}
	
}
public class Test2 {
	public static void main(String[] args) {
		/**
		 * 目标对象
		 */
		UserDao userDao = new UserDao();
		/**
		 * 代理 对象
		 */
		UserDaoProxy userDaoProxy = new UserDaoProxy(userDao);
		/**
		 * 执行代理方法
		 */
		userDaoProxy.save();
	}
}

我们可以看到执行后的结果

事实上,调用代理的方法,实际上是调用了委托类的方法。(不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法)
    优点:可以做到在不修改目标对象的功能前提下,对目标功能扩展.
    缺点:   因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护.

动态代理

在动态代理中我们不再需要再手动的创建代理类,我们只需要编写一个动态处理器就可以了。真正的代理对象由JDK运行时为我们动态的来创建。

动态代理有两种

  • JDK本身提供的动态代理机制 Proxy ->只能代理接口
  • 第三方 CGLib动态代理 ->基于拦截器 用来代理类

1,利用Proxy实现动态代理

       实现一个类,从INvocationHandler继承,重写invoke()方法

       调用Proxy的NewInsatnce方法。产生了实现指定接口的代理类对象

class MyProxy implements InvocationHandler{
    private Iuser iuser ;//iuser引用的是委托对象
    public MyProxy(Iuser iuser){
        this.iuser = iuser;
    }

    /**
     * 
     * @param proxy 当前调用对象
     * @param method 所调方法
     * @param args 方法里的参数
     * @return
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("call Myproxy invoke");
        System.out.println("当前调用对象"+proxy.getClass());
        System.out.println("所调方法为:"+method.getName());
        /**
         * 执行此方法
         */
        method.invoke(iuser);
        return null;
    }
}
interface Iuser{
    void talk();
    void eat();
}

class Boss implements Iuser{

    public void talk() {
        System.out.println("boss talk");
    }

    public void eat() {
        System.out.println("boss eat");
    }
}
public class ProxyTest {
    public static void main(String[] args) {

        /**
         * 2,调用Proxy的NewInstance方法,产生实现了指定接口的代理对象
         */
        Iuser user = (Iuser) Proxy.newProxyInstance(ProxyTest.class.getClassLoader(),
                new Class[]{Iuser.class}, new MyProxy(new Boss()));

        user.eat();
        user.talk();
    }
}
public static Object newProxyInstance(ClassLoader loader, 指定当前目标对象使用的类加载器,获取加载器的方法是固定的
                                      Class<?>[] interfaces, 定目标对象实现的接口的类型,使用泛型方式确认类型
                                      InvocationHandler h) 指定的动态处理器,执行目标对象的方法时,会触发时间处理器的方法。以下为动态代理产生的类
/**
 * 动态代理产生的类
 * package com.tl.dynamicproxy;
 *
 * import java.lang.reflect.InvocationHandler;
 * import java.lang.reflect.Method;
 * import java.lang.reflect.Proxy;
 * import java.lang.reflect.UndeclaredThrowableException;
 *
 * final class $Proxy0 extends Proxy
 *   implements IUser
 * {
 *   private static Method m1;
 *   private static Method m4;
 *   private static Method m2;
 *   private static Method m3;
 *   private static Method m0;
 *
 *   public $Proxy0(InvocationHandler paramInvocationHandler)
 *     throws
 *   {
 *     super(paramInvocationHandler);
 *   }
 *
 *   public final boolean equals(Object paramObject)
 *     throws
 *   {
 *     try
 *     {
 *       return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
 *     }
 *     catch (RuntimeException localRuntimeException)
 *     {
 *       throw localRuntimeException;
 *     }
 *     catch (Throwable localThrowable)
 *     {
 *     }
 *     throw new UndeclaredThrowableException(localThrowable);
 *   }
 *
 *   public final void eat()
 *     throws
 *   {
 *     try
 *     {
 *       this.h.invoke(this, m4, null);
 *       return;
 *     }
 *     catch (RuntimeException localRuntimeException)
 *     {
 *       throw localRuntimeException;
 *     }
 *     catch (Throwable localThrowable)
 *     {
 *     }
 *     throw new UndeclaredThrowableException(localThrowable);
 *   }
 *
 *   public final String toString()
 *     throws
 *   {
 *     try
 *     {
 *       return (String)this.h.invoke(this, m2, null);
 *     }
 *     catch (RuntimeException localRuntimeException)
 *     {
 *       throw localRuntimeException;
 *     }
 *     catch (Throwable localThrowable)
 *     {
 *     }
 *     throw new UndeclaredThrowableException(localThrowable);
 *   }
 *
 *   public final void talk()
 *     throws
 *   {
 *     try
 *     {
 *       this.h.invoke(this, m3, null);
 *       return;
 *     }
 *     catch (RuntimeException localRuntimeException)
 *     {
 *       throw localRuntimeException;
 *     }
 *     catch (Throwable localThrowable)
 *     {
 *     }
 *     throw new UndeclaredThrowableException(localThrowable);
 *   }
 *
 *   public final int hashCode()
 *     throws
 *   {
 *     try
 *     {
 *       return ((Integer)this.h.invoke(this, m0, null)).intValue();
 *     }
 *     catch (RuntimeException localRuntimeException)
 *     {
 *       throw localRuntimeException;
 *     }
 *     catch (Throwable localThrowable)
 *     {
 *     }
 *     throw new UndeclaredThrowableException(localThrowable);
 *   }
 *
 *   static
 *   {
 *     try
 *     {
 *       m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
 *       m4 = Class.forName("com.tl.dynamicproxy.IUser").getMethod("eat", new Class[0]);
 *       m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
 *       m3 = Class.forName("com.tl.dynamicproxy.IUser").getMethod("talk", new Class[0]);
 *       m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
 *       return;
 *     }
 *     catch (NoSuchMethodException localNoSuchMethodException)
 *     {
 *       throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
 *     }
 *     catch (ClassNotFoundException localClassNotFoundException)
 *     {
 *     }
 *     throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
 *   }
 * }
 */

看一下运行结果

可以看出来调用目标对象的方法时,会调用MyProXy的invoke()方法。

总结

调用Proxy的NewINstance方法,就会动态产生一个代理对象$Proxy0,实现了指定接口。

class $Proxy0 extends Proxy implement Iuser
public $Proxy0(InvocationHandler handler)

调用目标对象方法时就会调用Handler的invoke()方法。

2,CGLib动态代理

JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就可以使用Cglib实现.

首先导入jar包:

用Maven的话

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.2.4</version>
        </dependency>
/**
 * 未实现接口的类
 */
class Boss {

    public void talk() {
        System.out.println("boss talk");
    }

    public void eat() {
        System.out.println("boss eat");
    }
}

class CglibProxy implements MethodInterceptor{
    private Object target;
    public CglibProxy(Object target){
        this.target = target;
    }

    public Object getInstance(){
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(this.target.getClass());
        //设置回调函数
        enhancer.setCallback(this);
        //创建子类(代理对象)
        return enhancer.create();
    }

    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object result = method.invoke(target,args);
        return result;
    }
}
public class ProxyTest {
    public static void main(String[] args) {
        Boss boss = new Boss();
        CglibProxy cglibProxy = new CglibProxy(boss);
        Boss instance = (Boss)cglibProxy.getInstance();
        instance.eat();
    }
}

我们看一下运行结果


可以 发现。代理类代理Boss,调用对象的方法时,实际上调用了CglibProxy类的intercept()方法。

由于CGLib由于是采用动态创建子类的方法,对于final修饰的方法无法进行代理。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值