代理模式
代理,就是帮别人做事情
你只需要去做你的事情就可以了,其他的事情交给代理来做
为什么要学习代理模式? 因为这就是SpringAOP的底层! 【面试高频 :SpringAOP,SpringMVC】
代理模式的分类:
- 静态代理
- 动态代理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6ZQNCl5L-1611832820467)(Spring.assets/image-20201230141341876.png)]
真实对象 跟 代理对象 要去实现 租房接口
静态代理
角色分析:
-
抽象角色:一般会用接口或者抽象类来解决
//租房 public interface Rent { public void rent(); }
-
真实角色:被代理的角色
//房东 public class Host implements Rent{ public void rent() { System.out.println("房东要出租房子"); } }
-
代理角色:代理真实角色,代理后一般会做一些附属操作
//代理角色 public class Proxy implements Rent{ // 首先要代理房东出租房子 private Host host; public Proxy(){ } public Proxy(Host host) { this.host = host; } public void rent() { seeHouse(); host.rent(); fare(); } //代理有很多自己的方法 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(); //代理房东出租房子,但是代理角色一般会有一些附属操作 Proxy proxy = new Proxy(host); //通过代理租房子,不需要面对房东 proxy.rent(); } } /* 一开始是直接去找房东租房子 现在很懒,想在网上找房子,就很难去找房东租房子了 然后就去找到 中介 租房子。 中介帮房东出租房子 */
静态代理模式的好处:
- 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
- 公共业务也就交给代理角色!实现了业务的分工
- 公共业务发生扩展的时候,方便集中管理!
缺点:
- 一个真实角色就会产生对应的代理角色,如果有多个真实角色 代码量会翻倍~开发效率会变低
静态代理加深理解
代理模式:就是不改变原有的业务情况下,给他增加一些功能、扩展一些功能
- 抽象角色
//抽象角色
public interface UserService {
public void add();
public void update();
public void delete();
public void select();
}
-
真实业务
//真实业务 public class UserServiceImpl implements UserService{ public void add() { System.out.println("新增一个方法"); } public void update() { System.out.println("修改一个方法"); } public void delete() { System.out.println("删除一个方法"); } public void select() { System.out.println("查询一个方法"); } }
-
代理类
public class UserServiceProxy implements UserService{ //要代理的对象 private UserServiceImpl userService; public void setUserService(UserServiceImpl userService){ this.userService = userService; } public void add() { log("add"); userService.add(); } public void update() { log("update"); userService.update(); } public void delete() { log("delete"); userService.delete(); } public void select() { log("select"); userService.select(); } public void log(String aa){ System.out.println("输出了"+aa+"日志"); } }
-
测试
public class Client { public static void main(String[] args) { UserServiceImpl userService = new UserServiceImpl(); UserServiceProxy userServiceProxy = new UserServiceProxy(); userServiceProxy.setUserService(userService); userServiceProxy.add(); } }
AOP的底层就是代理模式,再不改变源码的情况写增加一些功能
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ppIWt3lX-1611832820471)(Spring.assets/image-20201231125930414.png)]
动态代理
- 动态代理和静态代理角色一样
- 动态代理的代理类是动态生成的,不是我们直接写好的
- 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
- 基于接口: JDK动态代理 【下面使用这个】
- 基于类: cglib
- java字节码实现: javasist
需要了解两个类:Proxy 代理,InvocationHandler:调用处理程序
-
Proxy :提供了创建动态代理类和实例的静态方法
-
InvocationHandler: 调用处理程序实现的接口
动态代理的好处:
- 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
- 公共业务也就交给代理角色!实现了业务的分工
- 公共业务发生扩展的时候,方便集中管理!
- 一个动态代理类代理的是一个接口,一般就是对应的一类业务
- 一个代理类可以代理多个类,只要实现了同一个接口即可
//用这个类自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Object target; //代理谁
public void setTarget(Object target) {
this.target = target;
}
//生成代理类
public Object getProxy(){
/* Proxy.newProxyInstance:生成一个代理对象
this.getClass().getClassLoader():加载得到 类在哪个位置
target.getClass().getInterfaces():表示要代理的接口是哪一个接口
this:代表它自己的 InvocationHandler
*/
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
//调用代理程序的执行方法。 处理代理实例,并返回结果,就是你要代理的人,并返回结果
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 msg){
System.out.println("增加了"+msg+"日志");
}
}
测试:
public class Client {
public static void main(String[] args) {
//真实角色
UserServiceImpl userService = new UserServiceImpl();
//代理角色,不存在,需要通过 ProxyInvocationHandler去生成一个代理类。 因为它实现了InvocationHandler
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setTarget(userService); //设置要代理的对象
//设置动态生成代理类
UserService proxy = (UserService) pih.getProxy();
proxy.delete();
}
}