代理模式的三种角色:
- 抽象角色:声明真实对象和代理对象的共同接口。
- 代理角色:代理对象角色内部含有对真实对象的引用,从而可以操纵真实的对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象,同时代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
- 真实角色:代理所代理的真实角色,是我们要引用的对象。
静态代理:
模拟场景:租房
- 抽象接口:HireHouse
- 真实角色:HireHouseImpl
- 代理角色:HireHouseProxy
抽象接口:
public interface HireHouse {
public void hire();
}
真实角色:
public class HireHouseImpl implements HireHouse{
@Override
public void hire() {
System.out.println("租房");
}
}
代理角色:
public class HireHouseProxy implements HireHouse {
//真实角色
private HireHouse hh;
public HireHouseProxy(HireHouse hh) {
super();
this.hh = hh;
}
@Override
public void hire() {
System.out.println("收中介费");
hh.hire();
System.out.println("扣押金");
}
}
调用代码:
public static void main(String[] args) {
HireHouse hh=new HireHouseProxy(new HireHouseImpl());
hh.hire();
}
使用说明:
- 真实角色(HireHouseImpl)和代理角色(HireHouseProxy)都实现了抽象接口(HireHouse)
- 代理角色(HireHouseProxy)内部含有对真实角色(HireHouseImpl)的引用,从而可以操纵真实的对象
静态代理的局限:
- 代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。
- 如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
JDK动态代理:
JDK动态代理的目标是接口的实现类,因此如果要使用JDK动态代理,必须要有接口以及实现类
模拟场景:保存用户信息
- 抽象接口:UserService
- 真实角色:UserServiceImpl
- 代理角色:JDKProxy
抽象接口:
public interface UserService {
public void save();
public void update();
}
真实角色:
public class UserServiceImpl implements UserService {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public void save() {
System.out.println("保存用户");
}
@Override
public void update() {
System.out.println("修改用户");
}
}
代理角色:
public class JDKProxy implements InvocationHandler {
private Object targetObj;
public Object createProxyInstance(Object targetObj) {
this.targetObj=targetObj;
return Proxy.newProxyInstance(this.targetObj.getClass().getClassLoader(), this.targetObj.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Method getMeth=this.targetObj.getClass().getMethod("getUser",null);
Object user=getMeth.invoke(targetObj, null);
Object obj=null;
if(user!=null) {
obj = method.invoke(this.targetObj, args);
}else {
System.out.println("您还没有登录");
}
return obj;
}
}
使用说明:
- 代理角色必须实现InvocationHandler接口
CGLIB动态代理:
CGLIB动态代理可以对普通类(不要求实现接口)做动态代理,目标类不能是final,目标类里面的方法也不能使final,这是因为CGLIB底层是利用了继承的原理