代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
静态代理
/**
* 接口
* @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修饰的方法无法进行代理。