代理模式有静态代理和动态代理:
动态代理的实现有多种:
- 基于接口—JDK动态代理
- 基于类–Cglib动态代理
- java字节码实现:javasist(有待学习)
静态代理:
静态代理首先需要的也是接口,需要代理类去实现被代理类所实现的接口,如图:
//出租接口
public interface Rent {
public void rentHouse();
}
//房东类
public class Landlord implements Rent{
@Override
public void rentHouse() {
System.out.println("出租房子+房子信息");
}
}
//代理类(先理解为中介)
public class StaticProxy implements Rent{
private Landlord landlord;
public void setLandlord(Landlord landlord) {
this.landlord = landlord;
}
@Override
public void rentHouse() {
//代理可以做其他事
System.out.println("陪你看房");
//代理执行方法
landlord.rentHouse();
System.out.println("售后服务");
}
}
public class Test {
public static void main(String[] args) {
//租房子得有一个房东
Landlord landlord = new Landlord();
//再来个中介
StaticProxy agent = new StaticProxy();
//理解为将房东信息给中介
agent.setLandlord(landlord);
//找不到房东,通过中介租房子
agent.rentHouse();
}
}
理解完静态代理,再看看代码,发现如果每次需要代理一个类,就需要重新写一个代理类,这样的话会大大增加代码量,于是基于静态代理,动态代理又来了。
动态代理:
分析静态代理上面的代码,可以看出,只要我们在代理类中的’房东’(Landlord)不写死,再稍作修改,我们就可以用一个类去代理多个。而JDK给我们提供了InvocationHandler接口和Proxy类,我们就可以实现动态代理。
//还是一个必要的接口
public interface UserDao {
public void add();
public void delete();
}
//我们的被代理类
public class UserDaoImpl implements UserDao{
@Override
public void add() {
System.out.println("执行add");
}
@Override
public void delete() {
System.out.println("执行delete");
}
}
//我们的代理类,首先必须实现InvocationHandler接口//核心
public class UserDaoProxy implements InvocationHandler {
private Object o;
//通过set方式动态设置这个被代理对象
public void setO(Object o) {
this.o = o;
}
//通过proxy的newProxyInstance获取被代理之后的对象(实际还是反射实现)//核心
public Object getObject(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),o.getClass().getInterfaces(),this);
}
//必须重写invoke//核心
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log();
//通过反射去调用想要调用的方法
return method.invoke(o, args);
}
//增加的业务
public void log(){
System.out.println("[Debug] 增加了日志方法");
}
}
//测试方法
public static void main(String[] args) {
//不论怎么我们还是要一个被代理类
UserDaoImpl userDaoImpl = new UserDaoImpl();
UserDaoProxy userDaoProxy = new UserDaoProxy();
//把被代理类给到代理类
userDaoProxy.setO(userDaoImpl);
//这个userDao是已经被代理的对象
UserDao userDao = (UserDao)userDaoProxy.getObject();
userDao.add();
}
这样测试下来,发现我们可以在不改变原来代码的基础上,加入新的业务。这就是JDK原生的动态代理。