一、前言
1、代理模式概念
为一个对象提供一个替身,以控制对这个对象的访问,即通过代理对象访问目标对象(被代理对象),这样做的好处:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。
被代理对象可以是远程对象、创建开销大的对象和需要安全控制的对象。
2、分类
java中的代理模式分为三种:静态代理、动态代理(JDK代理、接口代理)、Cglib代理。
其中Cglib代理有些书上也把它归为了动态代理。
二、示例
1、静态代理
在静态代理当中,不管是被代理对象(也称目标对象),还是代理对象,都需要去实现共同的接口(或者是继承共同的父类)。
优点: 在不修改目标对象功能的前提下,能够通过代理对象对目标功能进行扩展。
缺点: 因为代理对象与目标对象需要实现相同的接口,所以会有很多代理类。
UML类图如下图所示:
(其中TeacherDao是被代理对象,TeacherDaoProxy是代理对象)
代码:
- ITeacherDao.java
public interface ITeacherDao
{
public abstract void teach();
}
- TeacherDao.java
public class TeacherDao implements ITeacherDao
{
@Override
public void teach()
{
System.out.println("老师正在上课。。。。。");
}
}
- TeacherDaoProxy.java
public class TeacherDaoProxy implements ITeacherDao
{
private ITeacherDao dao;
public TeacherDaoProxy(ITeacherDao dao)
{
this.dao=dao;
}
@Override
public void teach()
{
System.out.println("准备上课。。。");
dao.teach();
System.out.println("结束上课。。。");
}
}
- Client.java
public class Client
{
public static void main(String[] args)
{
TeacherDaoProxy teacherDaoroxy=new TeacherDaoProxy(new TeacherDao());
teacherDaoroxy.teach();
}
}
2、动态代理(JDK代理、接口代理)
动态代理与静态代理比较明显的一个区别是,动态代理中的代理对象不需要去实现接口,仅要求目标对象(亦称被代理对象)去实现接口。
代理对象的生成是利用JDK的API,动态地在内存中构建对象。
用到的是java.lang.reflect.Proxy这个类中的一个静态方法newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h),
该方法接收三个参数,分别是:
loader - 定义代理类的类加载器
interfaces - 代理类要实现的接口列表
h - 指派方法调用的调用处理程序
UML类图如下:
代码:
- ITeacherDao.java
public interface ITeacherDao
{
void teach();
}
- TeacherDao.java
public class TeacherDao implements ITeacherDao
{
@Override
public void teach()
{
System.out.println("教师正在上课。。。");
}
}
- ProxyFactory.java
public class ProxyFactory
{
private Object target;
public ProxyFactory(Object target)
{
this.target=target;
}
public Object getProxyInstance()
{
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
System.out.println("开始上课。。。");
Object object=method.invoke(target, args);
System.out.println("结束代理。。。");
return object;
}
}
);
}
}
- Client.java
public class Client
{
public static void main(String[] args)
{
ITeacherDao dao=new TeacherDao();
ProxyFactory factory=new ProxyFactory(dao);
ITeacherDao instance=(ITeacherDao)factory.getProxyInstance();
instance.teach();
}
}
3、Cglib代理
Cglib代理与前面两种代理不同的是,目标对象不需要去实现接口,它使用目标对象的子类来实现代理,Cglib代理也称为子类代理,有些书也将其归为动态代理。
Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口,被许多AOP框架使用,例如Spring AOP,实现方法拦截。
Cglib包的底层使用字节码处理框架ASM来转换字节码并生成新的类。
要想使用Cglib代理,首先得导入jar包(共4个),引入依赖。点我下载jar包 。密码:c6ca
Cglib代理的UML类图如下:
代码:
- TeacherDao.java
public class TeacherDao
{
public String teach()
{
System.out.println("老师正在授课中……Cglib代理,目标对象无需实现接口!");
return "hello";
}
}
- ProxyFactory.java
public class ProxyFactory implements MethodInterceptor
{
private Object target;
public ProxyFactory(Object target)
{
this.target=target;
}
public Object getProxyInstance()
{
Enhancer enhancer=new Enhancer();//创建一个工具类
enhancer.setSuperclass(target.getClass());//设置父类
enhancer.setCallback(this);//设置回调函数
return enhancer.create();//创建子类对象,即代理对象
}
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable
{
System.out.println("代理开始~");
Object object=arg1.invoke(target, arg2);
System.out.println("代理结束~");
return object;
}
}
- Client.java
public class Client
{
public static void main(String[] args)
{
ProxyFactory proxyFactory=new ProxyFactory(new TeacherDao());
TeacherDao teacherDao=(TeacherDao)proxyFactory.getProxyInstance();
String string=teacherDao.teach();
System.out.println("方法的返回值:"+string);
}
}
三、总结
- 静态代理中,目标对象和代理对象都需要实现接口。
- 动态代理中,目标对象需要实现接口。
- Cglib代理中,目标对象不需要实现接口。