代理模式
AOP面向切面编程的底层思想就是代理模式,理解代理模式对理解AOP模式很有帮助。
代理模式分为:
- 静态代理
- 动态代理
用UML图来简单描述一下
1 静态代理
静态代理角色分析
-
抽象角色 : 一般使用接口或者抽象类来实现
-
真实角色 : 被代理的角色
-
代理角色 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作 .
-
客户 : 使用代理角色来进行一些操作 .
静态代理实例一:
-
抽象角色Rent
public interface Rent { public void rent(); }
-
真实角色Host
public class Host implements Rent { public void rent() { System.out.println("房屋出租"); } }
-
代理角色Proxy
public class Proxy implements Rent { private Host host; public Proxy() { } public Proxy(Host host) { this.host = host; } @Override public void rent() { seeHouse(); host.rent(); fare(); } //看房 public void seeHouse() { System.out.println("带房客看房"); } //收中介费 public void fare() { System.out.println("收中介费"); } }
-
客户client
public class Client { public static void main(String[] args) { //房东要租房 Host host = new Host(); //中介帮助房东 Proxy proxy = new Proxy(host); //你去找中介! proxy.rent(); } }
**理解:**代理模式中,真实角色和代理角色共同实现租房这一抽象接口,真正拥有租房权限的是真实角色,因为代理角色找到了真实角色,真实角色将租房这一权限给代理。
- **优点:**代理角色除了代理了租房这一功能还可以提供其他的一些附加功能,比如签合同,看房等,这是真实角色不想做的事情,但是却不会影响他本身的租房功能。
静态代理实例二:
-
抽象接口UserService
public interface UserService { void add(); void delete(); void update(); void query(); }
-
真实角色UserServiceImpl
public class UserServiceImpl implements UserService { public void add() { System.out.println("增加了一个用户"); } public void delete() { System.out.println("删除了一个用户"); } public void update() { System.out.println("更新了一个用户"); } public void query() { System.out.println("查询了一个用户"); } }
-
代理角色UserServiceImplProxy
public class UserServiceImplProxy implements UserService{ private UserServiceImpl userServiceImpl; public void setUserServiceImpl(UserServiceImpl userServiceImpl) { this.userServiceImpl = userServiceImpl; } @Override public void add() { log("add"); userServiceImpl.add(); } @Override public void delete() { log("delete"); userServiceImpl.delete(); } @Override public void update() { log("update"); userServiceImpl.update(); } @Override public void query() { log("query"); userServiceImpl.query(); } public void log(String message){ System.out.println("执行了"+message); } }
-
客户端
public static void main(String[] args) { //真实业务 UserServiceImpl userService = new UserServiceImpl(); //代理类 UserServiceImplProxy proxy = new UserServiceImplProxy(); //使用代理类实现日志功能! proxy.setUserServiceImpl(userService); proxy.add(); }
**理解:**和之前的静态代理案例一一样,通过代理角色的方式,在实现真实角色功能的基础上,不影响的增加一些代理功能。
- 这也是AOP底层的实现机制
2 动态代理
就和在mybatis时做分页一样,当分页的类型多的时候,我们不希望为每一种类型都增加一个分页类,这个时候我们使用泛型的方式来实现不同类型数据的返回匹配。
-
动态代理的角色和静态代理的一样 .
-
动态代理的代理类是动态生成的 . 静态代理的代理类是我们提前写好的
-
动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理
-
基于接口的动态代理----JDK动态代理
-
基于类的动态代理–cglib
-
现在用的比较多的是 javasist 来生成动态代理 . 百度一下javasist
-
JDK的动态代理需要了解两个类
核心 : InvocationHandler 和 Proxy 。
使用方式:
//代理角色:中介
public class ProxyInvocationHandler implements InvocationHandler {
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成代理类,重点是第二个参数,获取要代理的抽象角色!之前都是一个角色,现在可以代理一 类角色
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
seeHouse();;
Object object = method.invoke(rent,args);
fare();
return object;
}
//看房
public void seeHouse() {
System.out.println("带房客看房");
}
//收中介费
public void fare() {
System.out.println("收中介费");
}
}
//租客
public class Client {
public static void main(String[] args) {
//真实角色
Host host = new Host();
//代理实例的调用处理程序
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setRent(host);
//将真实角色放置进去!
Rent proxy = (Rent)pih.getProxy();
//动态生成对应的代理类!
proxy.rent();
}
}
- 通过这样的方式,我们就可以动态的代理Rent这一类的对象了。
除了代理这一类的方法,有时候我们希望能够实现所有对象的代理,这个时候我们可以把Rent改为Object类型,这样就可以代理所有的对象类型了。
使用方法:
public class ProxyInvocationHandler implements InvocationHandler {
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//生成代理类
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
// proxy : 代理类 method : 代理类的调用处理程序的方法对象.
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
Object result = method.invoke(target, args);
return result;
}
public void log(String methodName) {
System.out.println("执行了" + methodName + "方法");
}
}
public class Test {
public static void main(String[] args) {
//真实对象
UserServiceImpl userService = new UserServiceImpl();
//代理对象的调用处理程序
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setTarget(userService);
//设置要代理的对象
UserService proxy = (UserService)pih.getProxy();
//动态生成代理类!
proxy.delete();
}
}
3 小结
就和工具类一样,动态代理可以很方便的动态完成一些有需求变更和频繁使用的工作。