7.代理模式
本文转载:https://blog.kuangstudy.com/index.php/archives/526/
一.代理模式
1.什么是代理模式
为什么要学习代理模式,因为AOP的底层机制就是动态代理!
代理模式:
-
静态代理
-
动态代理
学习aop之前 , 我们要先了解一下代理模式!
租房案例:
2.静态代理
静态代理角色分析
-
抽象角色 : 一般使用接口或者抽象类来实现
-
真实角色 : 被代理的角色
-
代理角色 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作 .
-
客户 : 使用代理角色来进行一些操作 .
(1)抽象角色:租房Rent.java
1 //抽象角色:租房 2 public interface Rent { 3 4 void rent(); 5 }
(2)真实角色:房东Host.java
1 //真实角色: 房东,房东要出租房子 2 public class Host implements Rent{ 3 public void rent() { 4 System.out.println("房屋出租"); 5 } 6 }
(3)代理角色:Proxy.java
1 //代理角色:中介 2 public class Proxy implements Rent { 3 4 private Host host; 5 public Proxy() { } 6 public Proxy(Host host) { 7 this.host = host; 8 } 9 10 //租房 11 public void rent(){ 12 seeHouse(); 13 host.rent(); 14 fare(); 15 } 16 //看房 17 public void seeHouse(){ 18 System.out.println("带房客看房"); 19 } 20 //收中介费 21 public void fare(){ 22 System.out.println("收中介费"); 23 } 24 }
(4)租客角色:Client.java
1 //客户类,一般客户都会去找代理! 2 public class Client { 3 public static void main(String[] args) { 4 //房东要租房 5 Host host = new Host(); 6 //中介帮助房东 7 Proxy proxy = new Proxy(host); 8 9 //你去找中介! 10 proxy.rent(); 11 } 12 }
3.静态代理优缺点分析
-
优点:
-
可以使真实角色的操作更加纯粹,不用去关注一些公共的业务
-
公共业务交给代理角色,实现了业务分工
-
公共业务发生扩展的时候,方便集中管理
-
-
缺点:
-
一个真实角色就会产生一个代理角色;代码量就会翻倍,开发效率就会变低
-
4.静态代理深入理解
(1)业务层抽象接口:UserService.java
1 //抽象角色:增删改查业务 2 public interface UserService { 3 void add(); 4 void delete(); 5 void update(); 6 void query(); 7 }
(2)业务层实现类:UserServiceImpl
1 //真实对象,完成增删改查操作的人 2 public class UserServiceImpl implements UserService { 3 4 public void add() { 5 System.out.println("增加了一个用户"); 6 } 7 8 public void delete() { 9 System.out.println("删除了一个用户"); 10 } 11 12 public void update() { 13 System.out.println("更新了一个用户"); 14 } 15 16 public void query() { 17 System.out.println("查询了一个用户"); 18 } 19 }
(3)代理角色:用来添加日志功能UserServiceProxy.java
1 //代理角色,在这里面增加日志的实现 2 public class UserServiceProxy implements UserService { 3 private UserServiceImpl userService; 4 5 public void setUserService(UserServiceImpl userService) { 6 this.userService = userService; 7 } 8 9 public void add() { 10 log("add"); 11 userService.add(); 12 } 13 14 public void delete() { 15 log("delete"); 16 userService.delete(); 17 } 18 19 public void update() { 20 log("update"); 21 userService.update(); 22 } 23 24 public void query() { 25 log("query"); 26 userService.query(); 27 } 28 29 public void log(String msg){ 30 System.out.println("执行了"+msg+"方法"); 31 } 32 33 }
(4)用户类:Client.java
1 public class Client { 2 public static void main(String[] args) { 3 //真实业务 4 UserServiceImpl userService = new UserServiceImpl(); 5 //代理类 6 UserServiceProxy proxy = new UserServiceProxy(); 7 //使用代理类实现日志功能! 8 proxy.setUserService(userService); 9 10 proxy.add(); 11 } 12 }
(5)总结
-
我们在不改变原来的代码的情况下,实现了对原有功能的增强,这是AOP中最核心的思想
5.动态代理
-
动态代理和静态代理角色一样
-
动态代理的代理类是动态生成的,不是我们直接写好的
-
动态代理大致上分为两大类:(基于接口和基于类的)
-
基于接口:经典的是JDK的动态代理
-
基于类:例如:cglib
-
java字节码实现:现在用的比较多的是 javasist 来生成动态代理 . 百度一下javasist
-
我们这里使用JDK的原生代码来实现,其余的道理都是一样的!
-
(1)动态代理实现
JDK的动态代理需要了解两个类
-
核心 : InvocationHandler 和 Proxy
-
InvocationHandler:调用处理程序类
-
Proxy:创建动态代理类
抽象租房角色:Rent.java
1 //抽象角色:租房 2 public interface Rent { 3 4 void rent(); 5 }
真实租房角色:Host.java
1 //真实角色: 房东,房东要出租房子 2 public class Host implements Rent { 3 public void rent() { 4 System.out.println("房屋出租"); 5 } 6 }
代理角色:ProxyInvocationHandler. java
1 import java.lang.reflect.InvocationHandler; 2 import java.lang.reflect.Method; 3 import java.lang.reflect.Proxy; 4 5 public class ProxyInvocationHandler implements InvocationHandler { 6 private Rent rent; 7 8 public void setRent(Rent rent) { 9 this.rent = rent; 10 } 11 12 //生成代理类,重点是第二个参数,获取要代理的抽象角色!之前都是一个角色,现在可以代理一类角色 13 public Object getProxy(){ 14 return Proxy.newProxyInstance(this.getClass().getClassLoader(), 15 rent.getClass().getInterfaces(),this); 16 } 17 18 // proxy : 代理类 method : 代理类的调用处理程序的方法对象. 19 // 处理代理实例上的方法调用并返回结果 20 @Override 21 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 22 seeHouse(); 23 //核心:本质利用反射实现! 24 Object result = method.invoke(rent, args); 25 fare(); 26 return result; 27 } 28 29 //看房 30 public void seeHouse(){ 31 System.out.println("带房客看房"); 32 } 33 //收中介费 34 public void fare(){ 35 System.out.println("收中介费"); 36 } 37 38 }
租客角色:Client . java
1 //客户类 2 public class Client { 3 public static void main(String[] args) { 4 //真实角色 5 Host host = new Host(); 6 //代理实例的调用处理程序 7 ProxyInvocationHandler pih = new ProxyInvocationHandler(); 8 pih.setRent(host); //将真实角色放置进去! 9 Rent proxy = (Rent) pih.getProxy(); //动态生成对应的代理类! 10 proxy.rent(); 11 } 12 }
(2)动态代理深入理解
-
我们来使用动态代理实现代理我们后面写的UserService!
-
我们也可以编写一个通用的动态代理实现的类!所有的代理对象设置为Object即可!
代理角色:ProxyInvocationHandler. java
1 public class ProxyInvocationHandler implements InvocationHandler { 2 private Object target; 3 4 public void setTarget(Object target) { 5 this.target = target; 6 } 7 8 //生成代理类 9 public Object getProxy(){ 10 return Proxy.newProxyInstance(target.getClass().getClassLoader(), 11 target.getClass().getInterfaces(),this); 12 } 13 14 // proxy : 代理类 15 // method : 代理类的调用处理程序的方法对象. 16 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 17 log(method.getName()); 18 Object result = method.invoke(target, args); 19 return result; 20 } 21 22 public void log(String methodName){ 23 System.out.println("执行了"+methodName+"方法"); 24 } 25 26 }
客户角色:Client.java
1 public class Client { 2 public static void main(String[] args) { 3 //真实对象 4 UserServiceImpl userService = new UserServiceImpl(); 5 //代理对象的调用处理程序 6 ProxyInvocationHandler pih = new ProxyInvocationHandler(); 7 pih.setTarget(userService); //设置要代理的对象 8 UserService proxy = (UserService)pih.getProxy(); //动态生成代理类! 9 proxy.delete(); 10 } 11 }
(3)动态代理的好处
静态代理有的它都有,静态代理没有的,它也有!
-
可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .
-
公共的业务由代理来完成 . 实现了业务的分工 ,
-
公共业务发生扩展时变得更加集中和方便 .
-
一个动态代理 , 一般代理某一类业务
-
一个动态代理可以代理多个类,代理的是接口!
6.总结:
(1)静态代理特点:代理类(UserServiceProxy)和被代理类(UserServiceImpl)在编译期间就确定下来了
(2)动态代理特点:
-
代理类是在代码运行时才能确定下来的,通过ProxyInvocationHandler创建出代理类
-
可以灵活的通过不同的被代理类创建不同的代理类