代理模式,也叫做委托模式:为其他对象提供一种代理以控制对这个对象的访问。
作用:提供一个代理类,让程序员调用目标方法时,不再是直接对目标方法进行调用,而是通过代理类间接调用。

生活中的例子:
从客户端角度出发,它调用Subject接口定义的目标方法,并不关心这个方法的实现逻辑。 从代理模式结构出发,Proxy(代理类)没有实现目标方法,但是它可以调用目标方法并且在不修改目标方法的前提下,增加其他逻辑(功能),使得整个代码的可扩展性大大提高。

静态代理:由程序员创建代理类或特定工具自动生成源码在对其编译,在程序运行前代理类的.class文件就已经存在了。也就是在租房之前,中介就已经做好了准备工作,就等客户来“调用”了。
我们通过代码来观察一下:
定义业务接口(定义出租房子):
public interface HouseSubject{
void rentHouse();
}实现接口(房东出租房子):
public class RealHouseSubject implements HouseSubject{
@Override
public void rentHouse(){
System,out.println("我是房东,我要出租房子");
}
}代理类(中介,代理房东出租房子)
public class HouseProxy implements HouseSubject{
private HouseSubject houseSubject;
public HouseProxy(HouseSubject houseSubject){
this.houseSubject = houseSubject;
}
@Override
public void rentHouse(){
System,out.println("我是中介,开始代理");
houseSubject.rentHouse();
System,out.println("我是中介,结束代理");
}
}客户端使用方法:
public class Main{
public static void main(String[] args){
HouseSubject subject=new RealHouseSubject();
//创建代理类
HouseProxy proxy=new HouseProxy(subject);
//通过代理类访问目标方法
proxy.rentHouse();
}
}从运行结果发现,虽然静态代理都实现了目标方法的代理,但是方法的增强都是手动完成,很死板。如果以后需要增加其他接口(功能),还需要对业务实现类新增代理类。
其实这里我有一个疑问,为什么不把所有方法都写在一个类里面,这样就只有一个代理类了。
这样设计会反应出一些原则问题,比如违反一个职责原则:一个类只能表现出它本身职责;代理逻辑难以复用:代理模式的主要职责受到限制,因为不同方法需要不同的增强逻辑,不能都混在一个类里面。(比如要其中一个方法计算耗时,但是另一个方法需要事务管理,最好的方法就是动态代理+职责拆分)
动态代理:在程序运⾏时,运⽤反射机制动态创建⽽成
我们不需要针对每个对象都单独创建一个代理类,⽽是把这个创建代理对象的⼯作推迟到程序运⾏时由JVM来实现.也就是说动态代理在程序运⾏时,根据需要动态创建⽣成。(有点像懒汉模式) Java对动态代理进行了实现,并提供了一些API,常见的实现有:
定义接口及其实现类(HouseSubject和RealHouseSubject)
public interface HouseSubject{
void rentHouse();
}
public class RealHouseSubject implements HouseSubject{
@Override
public void rentHouse(){
System,out.println("我是房东,我要出租房子");
}
}自定义InvocationHandler并重写invoke方法,在invoke方法中调用目标方法(被代理方法)并自定义一些处理逻辑
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class JDKInvocationHandler implements InvocationHandler {
//目标对象就是代理对象
private Object target;
public JDKInvocationHandler(Object target){
this.target=target;
}
/**
* @param proxy 代理对象
* @param method 目标方法
* @param args 方法对应的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//代理增强内容
System.out.println("我是中介,开始代理");
//通过反射调用被代理的方法
Object retVal=method.invoke(target,args);
System.out.println("我是中介,结束代理");
return retVal;
}
}InvocationHandler接⼝是Java动态代理的关键接⼝之⼀,它定义了⼀个单⼀⽅法invoke(),⽤于处理被代理对象的⽅法调⽤。通过InvocationHandler接口,对被代理对象的方法进行功能增强。
客户端创建一个代理对象并使用
public class Main {
public static void main(String[] args) {
HouseSubject target= new RealHouseSubject();
//创建⼀个代理类:通过被代理类、被代理实现的接⼝、⽅法调⽤处理器来创建
HouseSubject proxy = (HouseSubject) Proxy.newProxyInstance(
target.getClass().getClassLoader(),//使用目标类的类加载器
new Class[]{HouseSubject.class},//代理要实现的接口
new JDKInvocationHandler(target)//方法调用代理类
);
proxy.rentHouse();
}
}整个流程是:

总结:JVM为接口中的每个方法生成相同的调用模板,所有的方法调用都通过invoke这一个入口,新增方法时 代理逻辑自动生效(method.invoke(target, args)调用实际方法),无需修改代码。
CGLIB是开源项目,使用需要添加相关依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>接口及其实现类同上:
自定义MethodeInterceptor 并重写intercept方法(与invoke类似)
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CGLIBInterceptor implements MethodInterceptor {
//目标对象(中介)
private Object target;
public CGLIBInterceptor() {
this.target=target;
}
/**
* @param obj 被代理的对象(房东)
* @param method 目标方法(增强方法)
* @param args 方法参数
* @param proxy 代理对象(中介)调用原始方法
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
//代理增强内容
System.out.println("我是中介,开始代理");
//通过反射调用被代理的方法
Object retVal=method.invoke(target,args);
System.out.println("我是中介,结束代理");
return retVal;
}
}客户端创建代理类:
public class DynamicMain {
public static void main(String[] args) {
HouseSubject target= new RealHouseSubject();
//被代理的接口 拦截的目标方法
HouseSubject proxy= (HouseSubject)
Enhancer.create(target.getClass(),new CGLIBInterceptor(target));
proxy.rentHouse();
}
}