1、静态代理
由三部分构成:抽象角色(真实角色和代理角色共同父接口,或者说是共有的功能)、真实角色(实现抽象角色)、代理角色(实现抽象角色,获取真实角色的引用,并附加操作)。除了真实对象和代理对象共同实现父接口的方式外,还可以让代理对象直接继承真实角色,但是此方法不够灵活,一般使用实现接口方式。
-
抽象角色,声明真实对象和代理对象的共同接口。即真实对象和代理对象共同要实现的行为动作
-
真实角色,代理角色所代理的对象,亦即我们最终要引用的对象
-
代理角色,代理角色内部含有对真实角色的引用,从而可以去操作真实对象,同时代理对象提供与真实对象的接口,以便在任何时候都能代替真实对象。同时,代理对象在执行真实对象的操作时,也能附加它自己的操作,相当于对真实对象的封装。
缺点:每当有一个真实对象需要被代理,就需要创建一个新的代理类,因为代理类内含有对真实对象的引用,代理类需要与真实对象一一对应。这样,当需要代理的真实对象比较多时,代理类就会急剧增加,增加了代码的复杂性,使代码变得尤其繁重,不易维护。也就是说,一个中介只能代理一个房东,这显然是不行的。
(1) 抽象角色(出租房屋)
public interface Rent {
public void rent();
}
(2) 真实角色(房东)
public class LandLord implements Rent {
@Override
public void rent() {
System.out.println("LandLord");
}
}
(3) 代理角色(房屋中介)(租房前收中介费,租房后收押金)
public class Proxy implements Rent {
private LandLord landLord;
@Override
public void rent() {
agencyFees();
if (null == landLord)
landLord = new LandLord();
landLord.rent();
cashPledge();
}
public void agencyFees() {
System.out.println("Agency Fees");
}
public void cashPledge() {
System.out.println("Cash Pledge");
}
}
2、动态代理(JDK 和 Cglib)
由三部分构成:抽象角色(真实角色父接口)、真实角色(实现抽象角色)、代理角色(获取真实角色的引用,并附加操作)。
(1) 使用JDK实现动态代理
JDK实现动态代理需要使用newProxyInstance方法,而且需要重写invoke方法,该方法需要接收三个参数,完整的写法是:
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) {}
注意该方法是在Proxy类中是静态方法,且接收的三个参数依次为:
-
ClassLoader loader:指定当前目标对象使用类加载器,获取加载器的方法是固定的
-
Class<?>[] interfaces:目标对象实现的接口的类型,使用泛型方式确认类型
-
InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入
从上述传入参数,可以看出,使用JDK实现动态代理时,被代理的对象(即真实角色)必须实现一个或者多个接口,否则Class<?>[] interfaces参数将出现错误,导致无法使用动态代理。
a、抽象角色(出租房屋)
public interface Rent {
public void rent();
}
b、真实角色(房东)
public class LandLord implements Rent {
@Override
public void rent() {
System.out.println("LandLord");
}
}
c、代理角色1(实现InvocationHandler接口,重写invoke方法)
public class DynamicProxy implements InvocationHandler {
private Object real; // 生成真实角色的两种方式
public DynamicProxy(Object real) {
this.real = real;
}
public void setReal(Object real) {
this.real = real;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
agencyFees();
Object object = method.invoke(real, args);
cashPledge();
return object;
}
public void agencyFees() {
System.out.println("Agency Fees");
}
public void cashPledge() {
System.out.println("Cash Pledge");
}
}
客户端调用动态代理:
LandLord landLord = new LandLord();
DynamicProxy handler = new DynamicProxy(landLord);
Rent rent = (Rent) Proxy.newProxyInstance(LandLord.class.getClassLoader(), LandLord.class.getInterfaces(), handler);
rent.rent();
d、代理角色2(将newProxyInstantce进一步封装,使客户端调用更加简单)
public class DynamicProxy { private Object real; // 生成真实角色的两种方式
public DynamicProxy(Object real) {
this.real = real;
}
public void setReal(Object real) {
this.real = real;
}
public Object getProxyInstance() {
return Proxy.newProxyInstance(real.getClass().getClassLoader(),real.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
agencyFees();
Object object = method.invoke(real, args);
cashPledge();
return object;
}
});
}
public void agencyFees() {
System.out.println("Agency Fees");
}
public void cashPledge() {
System.out.println("Cash Pledge");
}
}
客户端调用动态代理:
LandLord landLord = new LandLord();
Rent rent = (Rent) new DynamicProxy(landLord).getProxyInstance();
rent.rent();
(2) 使用Cglib实现动态代理
静态代理和JDK动态代理模式都要求被代理对象(即真实角色)实现一个或者多个接口,但有时候被代理对象只是一个单独的对象,并没有实现任何的接口,此时就可以使用继承的方式来实现动态代理,这种方法就叫做Cglib代理。
Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展。Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截)。Cglib包的底层是通过使用一个小而快的字节码处理框架ASM来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
a、抽象角色(出租房屋)
public interface Rent {
public void rent();
}
b、真实角色(房东)
public class LandLord implements Rent {
@Override
public void rent() {
System.out.println("LandLord");
}
}
c、代理角色(房东)
public class CGLibProxy implements MethodInterceptor {
private Object real;
public CGLibProxy(Object real) {
this.real = real;
}
public Object getProxyInstance() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(real.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
agencyFees();
Object object = proxy.invokeSuper(obj, args);
cashPledge();
return object;
}
public void agencyFees() {
System.out.println("Agency Fees");
}
public void cashPledge() {
System.out.println("Cash Pledge");
}
}
客户端调用动态代理:
LandLord landLord = new LandLord();
Rent rent = (Rent) new CGLibProxy(landLord).getProxyInstance();
rent.rent();