代理模式
由于某些原因需要给某对象提供一个代理以控制对该对象的访问,这时,访问对象不适合或直接引用目标对象,代理对象作为访问对象和目标对象的中介
角色
- 抽象主题:通过接口或抽象类声明真实主题和代理对象实现的业务方法
- 真实主题:实现了抽象主题的具体业务,是代理对象所代表的真实对象,是最终要引用的对象
- 代理类:通过了与真实主题相同的接口,其内部还有对真实主题的引用,它可以访问,控制或扩展真实主题的功能
UML类图
静态代理
代理类在编译器就生成
抽象主题
// 售票接口
public interface SellTickets {
void sell();
}
真实主题
// 火车站
public class Station implements SellTickets {
@Override
public void sell() {
System.out.println("火车站售票");
}
}
代理类
// 代理点
public class Agency implements SellTickets {
// 真实主题的引用
private Station station = new Station();
@Override
public void sell() {
System.out.println("代理点收取一定费用");
station.sell();
}
}
测试类:
public class ProxyClient {
public static void main(String[] args) {
// 获取静态代理类
ProxySell proxySell = new ProxySell();
// 执行代理方法
proxySell.sell();
}
}
执行结果
动态代理
代理类在java运行时动态生成(分为JDK代理和Cglib代理两种)
JDK代理
抽象主题和真实主题与静态代理类的相同
// 通过代理对象工场生成代理对象
public class ProxyFactory {
// 声明目标对象
private Station station = new Station();
public SellTickets getProxyObject(){
/**
* ClassLoader loader, 类加载器,用于加载代理类,可以通过目标对象获取类加载器
* Class[] interfaces, 代理类实现接口的字节码对象
* InvocationHandler h 代理对象的调用处理程序
*/
SellTickets proxyObject = (SellTickets) Proxy.newProxyInstance(station.getClass().getClassLoader(),
station.getClass().getInterfaces(), (o, method, objects) -> {
System.out.println("invoke方法执行了");
System.out.println("代售点收取了一些费用(JDK代理)");
Object invoke = method.invoke(station, objects);
return invoke;
});
return proxyObject;
}
}
测试类:
public class ProxyClient {
public static void main(String[] args) {
// 创建代理对象工厂
ProxyFactory proxyFactory = new ProxyFactory();
// 创建代理对象
SellTickets proxyObject = proxyFactory.getProxyObject();
// 调用代理方法
proxyObject.sell();
}
}
执行结果:
Cglib代理
引入依赖
maven:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
gradle:
compile group:'cglib',name:'cglib',version:'2.2.2'
真实主题
public class Shop {
public void sale() {
System.out.println("商店卖东西");
}
}
代理类
public class ShopProxyFactory implements MethodInterceptor {
private Shop shop;
public ShopProxyFactory(Shop shop) {
this.shop = shop;
}
public Shop getShopProxy() {
// 创建enhancer对象,相当于jdk代理中的proxy对象
Enhancer enhancer = new Enhancer();
// 设置父类字节码,因为使用cglib创建的代理对象实际是被代理对象的子类
enhancer.setSuperclass(Shop.class);
// 设置回调函数,传参是Callback 只需要类本身实现MethodInterceptor这个接口,就把这个类进行传参即可
enhancer.setCallback(this);
// 创建代理对象
Shop shop = (Shop) enhancer.create();
return shop;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("代售点中方法执行了");
System.out.println("代售点收取了一些费用(cglib)");
Object invoke = method.invoke(shop, objects);
return invoke;
}
}
测试类:
public class ShopProxyClient {
public static void main(String[] args) {
ShopProxyFactory shopProxyFactory = new ShopProxyFactory(new Shop());
Shop shopProxy = shopProxyFactory.getShopProxy();
shopProxy.sale();
}
}
执行结果:
静态代理和动态代理的区别
静态代理在一开始就将代理类生成好了,动态代理在运行时候才会生成
动态代理不用和被代理对象实现同样的接口
静态代理只能通过手动完成代理操作,如果被代理类添加了方法,那么代理类也要添加代理方法,违背开闭原则
动态代理在运行时动态生成代码的方式,取消了被代理类的扩展限制,符合开闭原则