普通代理
就是要求外部场景只能使用代理类,不允许使用原来的类。
直接上代码。
代码语言:javascript复制public interface ICustomer {
public void buy();
}
public class Customer implements ICustomer {
private Strin name;
// 不允许直接用 Customer 对象,所以在构造里判断是否有传一个代理过来
// 如果没有代理就报错
public Customer(ICustomer proxy, String name) throws Exception {
if (proxy == null) {
throw new Exception("必须用代理");
} else {
this.name = name;
}
}
public void buy() {
print("太难买了,排队12个小时终于买到了");
}
}
public class Scalper implements ICustomer {
private Customer customer = null;
public Scalper(String name) {
// 要有同样的参数,去构建被代理者
this.customer = new Customer(this, name);
}
public void buy() {
before();
// 代理在调用被代理对象的同名方法时,可以前后有些处理
customer.buy();
after();
}
private void befor() {
print("先谈价格,是原价的两倍");
}
private void after() {
print("排12个小时,无所谓,因为赚钱了");
}
}
// 场景类
public class Client {
private void test() {
// 外面直接创建代理对象
ICustomer customer = new Scalper("zs");
// 然后调用代理对象的方法,不知道 Customer 的存在
customer.buy();
}
}
强制代理
普通代理是高层创建代理对象,代理对象内部创建被代理对象。
强制代理是高层创建被代理对象,它的内部创建被代理对象,这样高层找到这个被代理对象后再做其它事情。
两者都是静态代理。
代码语言:javascript复制public interface ICustomer {
public void buy();
}
public class Customer implements ICustomer {
private String name;
private ICustome proxy; // 内部维护一个代理对象
public Customer(String name) {
this.name = name;
}
// 对外暴露,让高层调用者找到它的代理类,
// 只能使用这个代理类,外面创建的不行
public ICustomer getProxy() {
proxy = new Scalper(this);
return proxy;
}
public void buy() { // 保证只有外部获取过代理对象才可以调用
if (proxy == null) {
print("无法直接调用")
} else {
print("太难买了,排队12个小时终于买到了");
}
}
}
public class Scalper implements ICustomer {
private ICustomer customer;
// 高层调用者直接创建对象,所以这里不是代理内部根据参数创建
// 而是直接用高层创建的那个
public Scalper(ICustomer customer) {
this.customer = custom;
}
public void buy() {
before();
// 代理在调用被代理对象的同名方法时,可以前后有些处理
customer.buy();
after();
}
private void befor() {
print("先谈价格,是原价的两倍");
}
private void after() {
print("排12个小时,无所谓,因为赚钱了");
}
}
// 场景类
public class Client {
public void test() {
// 外面直接创建代理对象
ICustomer customer = new Customer("zs");
customer.getProxy().buy();
}
}
动态代理
JDK 原生功能,使用 InvocationHandler 接口。不需要自己手动写代理类,写个 Handler 把要代理的对象传进来就行。
代码语言:javascript复制public class CustomerIH implements InvocationHandler {
Class clazz; // 被代理类
Object obj; // 被代理类的实例
public CustomIH(Object obj) { // 要代理谁
this.obj = obj;
}
// 实现接口必须要写的方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在执行被代理对象的方法前后可以做拦截,做判断
Object result = method.invoke(this.obj, args);
return result;
}
}
public class Client {
public void test() {
ICustomer customer = new Customer("zs"); // 被代理类实例
InvocationHandler handler = new CustomerIH(customer);
ICustomer proxy = (ICustomer) Proxy.newProxyInstance(
custom.getClass().getClassLoader(),
custom.getClass().getInterfaces(),
handler); // 创建代理类
proxy.buy();
}
}
Proxy.newProxyInstance 参数既有 ClassLoader,又有 Class,它会在内部创建一个类实现接口,方法通过 handler 的 invoke 去具体的实现。
动态代理不像静态代理需要修改 Custome 本身的代码,而可以扩展功能,适合 AOP 编程,但真要实现 AOP,直接用 AspectJ 了。