什么是代理模式?
代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。
代理模式分类:
静态代理与动态代理,动态代理两者实现方式——JDK动态代理,CGLIB动态代理。
静态代理:在程序运行前,代理类的字节码文件就存在。
动态代理:程序运行时动态创建代理类。
什么是代理类?
为对象提供一种代理以控制对这个对象的访问。
静态代理:
比如我们存取的时候需要验钞机,通过它,合格了,才能将前存进银行。这个验钞机就好比代理类,我们不能直接接触内部,需要经过中间的验钞机,才能把我们的钱存进去。
具体实现:
public interface IBank {
public void save();
}
public class Bank implements IBank{
@Override
public void save() {
System.out.println("Bank.save()");
}
}
public class Proxy implements IBank{
private Bank bank;
public Proxy(Bank bank) {
this.bank = bank;
}
@Override
public void save() {
// 判断是否合法
System.out.println("Proxy.save.before");
bank.save();
System.out.println("Proxy.save.after");
}
}
public class Money {
public static void main(String[] args) {
Bank bank = new Bank();
IBank proxy = new Proxy(bank);
proxy.save();
}
}
为什么要让代理类(验钞机)和目标对象(银行)访问同一个接口(IBank)?
为了让客户端(钱)访问的时候,代理类和目标对象的行为保持一致,这是一种对目标对象的保护。
总结代理类的作用:实现与目标对象相同的接口,可以用来代替目标对象;保存一个目标对象的引用,在需要时调用目标对象对应的方法;控制对目标对象的访问。
总结静态代理优点:可以在不修改目标对象的前提下,对目标对象进行功能扩展。
这一点就像是古代的摄政王,有些时候以皇帝的名义出发,做了很多事,不管好坏,在底层老百姓眼里,只要皇帝没驾崩,这些都是皇帝的旨意。
静态代理缺点:有一个目标对象就要有一个代理对象,会产生很多代理对象;而一旦接口增加了方法,代理类和目标对象都要去维护,繁琐。
动态代理:这里主要说JDK动态代理
JDK动态代理: 使用JDK的反射机制,创建代理类的对象。
注:不需要自己写代理对象,但还是需要实现接口;代理对象,是利用JDKAPI动态地在内存中构建。
具体实现:
public class ProxyFactory {
/**
* 使用动态代理生成代理对象
* @param target 目标对象(还是要实现一个接口)
* @return 代理对象
*/
public static Object getProxyInstance(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(), // 目标对象使用的类加载器
target.getClass().getInterfaces(), // 目标对象实现的接口
new InvocationHandler() { // 事件处理器
// 这个invoke方法就相当于代理类MiShu里面的qianzi()方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Object proxy 代理对象
// Method method 调用的方法
// Object[] args 调用的方法的参数
System.out.println("ProxyFactory.invoke.before");
Object returnValue = method.invoke(target, args);
System.out.println("ProxyFactory.invoke.after");
return returnValue;
}
}
);
}
}
public interface IBank {
public void save();
}
public class Bank implements IBank{
@Override
public void save() {
System.out.println("Bank.save()");
}
}
public class Money {
public static void main(String[] args) {
Bank target = new Bank();
IBank proxy = (IBank)ProxyFactory.getProxyInstance(target);
proxy.save();
}
}
JDK动态代理的优点:不需要自己写代理类
JDK动态代理的缺点:只能实现对接口方法的增强,不能实现对接口类的动态代理。
针对JDK动态代理的缺点,如果想要实现对接口类的动态代理,可以使用CGLIB动态代理。
在Spring的AOP编程中,如果加入容器的目标对象有实现接口,用JDK代理;如果目标对象没有实现接口,用CGLIB代理。