代理模式为另一个对象提供一个替身或占位符来控制这个对象的访问。
使用代理模式创建代表对象。代表对象控制对另一个对象的访问,被代表的对象可以是远程的对象、创建开销大的对象或需要安全控制的对象。
同样代理模式又可以分为静态代理模式、动态代理模式与Cglib代理模式。
静态代理模式示例先上这个例子的类图,如我们要访问TeacherDao,但是呢我们现在不要直接去访问它,而是通过一个代理类去帮我们访问它,我们在Client中调用代理类的teach方法,在代理类的teach方法中可以添加一些操作,再去调用TeacherDao的teach方法(有点外观模式的感觉,哈哈哈)。
那么我们多次一举,要这个代理的作用是什么呢?
比如我们在调用teach之前,我们要准备一些上课用的课件呀,之类的(形象化比喻),这样完成一些操作,或者做一些安全性检查呀(和这个例子关系不大)。
那么为什么我们这个是静态代理呢,因为我们在编码的时候,去生成代理类对象,而不是在运行时动态获取,那就是静态的了呀。
好了,那么下面看看代码:
public interface ITeacherDao {
void teach();
}
public class TeacherDao implements ITeacherDao{
@Override
public void teach() {
System.out.println("老师开始教书");
}
}
public class TeacherDaoProxy implements ITeacherDao{
private ITeacherDao dao;
public TeacherDaoProxy(ITeacherDao dao) {
this.dao = dao;
}
@Override
public void teach() {
System.out.println("准备上课课件");
dao.teach();
}
}
public class Client {
public static void main(String[] args) {
ITeacherDao teacherDao = new TeacherDao();
ITeacherDao teacherDaoProxy = new TeacherDaoProxy(teacherDao);
teacherDaoProxy.teach();
}
}
不管是根据代码还是根据类图,我们都发现了代理类与被代理类实现了同一接口,这样做的目的是为了统一它们之间的方法,只是代理去做更多的事情。而在动态代理中,我们则不再去实现同样的事情。
动态代理模式示例同样地,先上类图,从类图中我们发现代理已经不实现ITeacherDao了,这是因为我们可以通过动态代理在运行的时候,去调用TeacherDao,没必要去实现。
好了,我们现在有一个代理工厂,由它去生成TeacherDao的代理,而现在的ITeacherDao的作用就是为了规范TeacherDao的方法。
而动态生成它的代理,我们则需要借助java的Proxy类,本质上是借助反射来实现。
好了,那么我们下面看看代码:
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("准备PPT");
Object invoke = method.invoke(target, args);
return invoke;
}
});
}
}
public class Client {
public static void main(String[] args) {
ITeacherDao teacherDao = new TeacherDao();
ProxyFactory proxyFactory = new ProxyFactory(teacherDao);
ITeacherDao teacherDaoProxy = (ITeacherDao)proxyFactory.getProxyInstance();
teacherDaoProxy.teach();
}
}
主要的修改在于代理类,其实就是用反射动态的创建了代理对象,然后由方法的反射,去调用这个对象的teach方法。
Cglib代理模式示例如果对于上面的被代理类没有实现接口,只是一个单独的类,那么将无法用上面的方式进行动态代理,如果我们进行以下修改:
public class TeacherDao {
public void teach() {
System.out.println("老师开始教书");
}
}
public class Client {
public static void main(String[] args) {
TeacherDao teacherDao = new TeacherDao();
ProxyFactory proxyFactory = new ProxyFactory(teacherDao);
TeacherDao teacherDaoProxy = (TeacherDao)proxyFactory.getProxyInstance();
teacherDaoProxy.teach();
}
}
将会报以下错误:
Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to HeadFirst.Strategy.Proxy.TeacherDao
at HeadFirst.Strategy.Proxy.Client.main(Client.java:8)
而Cglib可以支持动态代理一个单独的类。
那么还是以上面教师的例子,来给出类图:
那么我们就来动手实现以下:
这里面需要导入Cglib的包,我会再稍后上传:
public class TeacherDao {
public void teach() {
System.out.println("老师开始教书");
}
}
//相当于认为设置父类
public class ProxyFactory implements MethodInterceptor {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
public Object getProxyInstance(){
//1.创建一个父类
Enhancer enhancer = new Enhancer();
//2.设置父类
enhancer.setSuperclass(target.getClass());
//3.设置回调函数
enhancer.setCallback(this);
//4.创建子类对象,即代理对象
return enhancer.create();
}
//再调用这个,相当于之前的获取代理对象调用中的方法
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("开始备课");
Object returnVal = method.invoke(target,args);
return returnVal;
}
}
public class Client {
public static void main(String[] args) {
TeacherDao teacherDao = new TeacherDao();
ProxyFactory proxyFactory = new ProxyFactory(teacherDao);
TeacherDao teacherDaoProxy = (TeacherDao)proxyFactory.getProxyInstance();
teacherDaoProxy.teach();
}
}



