zoukankan      html  css  js  c++  java
  • Java静态代理和动态代理

      Spring框架用了很久了,对于Spring AOP也只是应用在数据库事务管理上面。对于Spring AOP的原理也只是知道使用动态代理实现,再深入的就知之甚少了,惭愧啊。

    最近有时间深入学习了一下,现在对动态代理的原理和应用进行一下总结。对于Spring AOP的基础概念和实现原理后续会进行总结。

      代理模式又分为静态代理和动态代理

      在现实生活中代理模式比比皆是,就拿租房来说, 房东要出租房子,就通过中介将房源挂出,当有租客想要租房子时,需要先跟中介进行沟通,看房子最后才跟房东签合同交钱等等,

    但是真正的房子出租价格都是房东定的(计算的),所以中介就是房东的代理。

      接下来分别通过静态代理和动态代理来实现房东通过中介出租房租给租客这个业务场景。

      静态代理模拟实现房屋出租业务场景:

      1 /**
      2  * @author Jack2013
      3  * 出租房屋接口
      4  */
      5 public interface Rentable {
      6 
      7     public void rentOutHouse() ;
      8 }
      9 /**
     10  * @author Jack2013
     11  * 房东,被代理的对象
     12  */
     13 public class Landlord implements Rentable {
     14         
     15     public void rentOutHouse() {
     16         System.out.println("我是房东,我与租客签合同并收取租金...");
     17     }
     18     
     19 }
     20 /**
     21  * @author Jack2013
     22  * 房产中介,代理房东出租房子
     23  */
     24 public class HouseAgent implements Rentable {
     25     
     26     private Rentable rentable;
     27 
     28     public void rentOutHouse() {
     29         showHouse() ;
     30         rentable.rentOutHouse();
     31         getFee() ;
     32     }
     33     
     34     public boolean hasRentable() {
     35         return rentable == null ? Boolean.FALSE : Boolean.TRUE ;
     36     }
     37     
     38     private void showHouse() {
     39         System.out.println("我是中介,我带租客看房子...");
     40     }
     41     
     42     private void getFee() {
     43         System.out.println("我是中介,我拿到了报酬...");
     44     }
     45 
     46     public Rentable getRentable() {
     47         return rentable;
     48     }
     49 
     50     public void setRentable(Rentable rentable) {
     51         this.rentable = rentable;
     52     }
     53 }
     54 /**
     55  * @author Jack2013
     56  *    租客,通过中介租房子
     57  */
     58 public class Renter {
     59     
     60     /**
     61      * 找到有房源的中介
     62      */
     63     public HouseAgent findHouseAgent(List<HouseAgent> agents) {
     64         for(HouseAgent agent : agents) {
     65             if(agent.hasRentable()) {
     66                 System.out.println("我找到一个有房源的中介...");
     67                 return agent ;
     68             }
     69         }
     70         return null ;
     71     }
     72     
     73     public void moveIn() {
     74         System.out.println("我是房客,我搬进了新租的房子...");
     75     }
     76     
     77     public Renter() {
     78         System.out.println("我是打工族,我准备租房子...");
     79     }
     80     
     81 }
     82 import java.util.List;
     83 import com.google.common.collect.Lists;
     84 /**
     85  * @author Jack2013
     86  * 测试类
     87  */
     88 public class Test {
     89 
     90     public static void main(String[] args) {
     91         List<HouseAgent> houseAgents = Lists.newArrayList() ;
     92         HouseAgent agent1 = new HouseAgent() ;
     93         HouseAgent agent2 = new HouseAgent() ;
     94         houseAgents.add(agent1) ;
     95         houseAgents.add(agent2) ;
     96         
     97         //房东找中介2出租自己的房子
     98         Landlord landlord = new Landlord() ;
     99         agent2.setRentable(landlord) ; 
    100     
    101         //租客通过中介租房子
    102         Renter renter = new Renter() ;
    103         HouseAgent agent = renter.findHouseAgent(houseAgents) ;
    104         agent.rentOutHouse() ;
    105         renter.moveIn(); 
    106     }
    107 }
    108 运行结果如下: 
    109 
    110     我是打工族,我准备租房子...
    111     我找到一个有房源的中介...
    112     我是中介,我带租客看房子...
    113     我是房东,我与租客签合同并收取租金...
    114     我是中介,我拿到了报酬...
    115        我是房客,我搬进了新租的房子...

       上面模拟场景中的中介目前只提供房屋出租的业务,如果想要提供房屋出售业务,则需要在添加一个Salable接口类,这是必须的,另外还必须添加一个Salable接口实现类的代理类。

         应为静态代理只能代理一个接口,但是动态代理则不需要增加新的代理类。

      动态代理模拟实现房屋出租和出售业务场景:

      1 /**
      2  * @author Jack2013
      3  * 出售房屋接口
      4  */
      5 public interface Salable {
      6 
      7     public void saleOutHouse() ;
      8 }
      9 
     10 /**
     11  * @author Jack2013
     12  * 出租房屋接口
     13  */
     14 public interface Rentable {
     15 
     16     public void rentOutHouse() ;
     17 }
     18 
     19 /**
     20  * @author Jack2013
     21  * 房东,被代理的对象
     22  */
     23 public class Landlord implements Rentable, Salable {
     24         
     25     public void rentOutHouse() {
     26         System.out.println("我是房东,我与租客签合同并收取租金...");
     27     }
     28 
     29     public void saleOutHouse() {
     30         System.out.println("我是房东,我与买家签合同并收取全款...");
     31     }
     32     
     33 }
     34 
     35 import java.lang.reflect.InvocationHandler;
     36 import java.lang.reflect.Method;
     37 import java.lang.reflect.Proxy;
     38 
     39 public class HouseAgentCompany implements InvocationHandler{
     40 
     41     private String companyName ;
     42     
     43     private Object target;
     44     
     45     public HouseAgentCompany(){}
     46     
     47     public HouseAgentCompany(String companyName){
     48         this.companyName = companyName ;
     49         System.out.println("["+this.companyName + "] 成立");
     50     }
     51     
     52     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
     53         showHouse() ;
     54         method.invoke(target, args) ;
     55         getFee() ;
     56         return null;
     57     }
     58     
     59     @SuppressWarnings("unchecked")
     60     public <T> T assign() {
     61         System.out.println("这里是" + this.companyName + ",为您分配一个专职员工服务");
     62         return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
     63     }
     64 
     65     private void showHouse() {
     66         System.out.println("我是中介,我带租客看房子...");
     67     }
     68     
     69     private void getFee() {
     70         System.out.println("我是中介,我拿到了报酬...");
     71     }
     72 
     73     public Object getTarget() {
     74         return target;
     75     }
     76 
     77     public void setTarget(Object target) {
     78         this.target = target;
     79     }
     80 
     81     public String getCompanyName() {
     82         return companyName;
     83     }
     84 
     85     public void setCompanyName(String companyName) {
     86         this.companyName = companyName;
     87     }
     88 }
     89 
     90 public class People {
     91 
     92     private String name ;
     93     
     94     public People(){}
     95     
     96     public People(String name){
     97         this.name = name ;
     98     }
     99 
    100     public String getName() {
    101         return name;
    102     }
    103 
    104     public void setName(String name) {
    105         this.name = name;
    106     }
    107 }
    108 
    109 public class Buyer extends People{
    110 
    111     public Buyer(String name) {
    112         super(name) ;
    113         System.out.println("我是白领: "+name+",我准备租房子...");
    114     }
    115     
    116     public void moveIn() {
    117         System.out.println("我是房客,我搬进了新买的房子...");
    118     }
    119     
    120     public Buyer() {
    121         System.out.println("我是白领,我准备买房子...");
    122     }
    123 }
    124 
    125 /**
    126  * @author Jack2013
    127  *    租客,通过中介租房子
    128  */
    129 public class Renter extends People{
    130     
    131     public Renter(String name) {
    132         super(name) ;
    133         System.out.println("我是打工族:"+name+",我准备租房子...");
    134     }
    135     
    136     /**
    137      * 找到有房源的中介
    138      */
    139     public HouseAgent findHouseAgent(List<HouseAgent> agents) {
    140         for(HouseAgent agent : agents) {
    141             if(agent.hasRentable()) {
    142                 System.out.println("我找到一个有房源的中介...");
    143                 return agent ;
    144             }
    145         }
    146         return null ;
    147     }
    148     
    149     public void moveIn() {
    150         System.out.println("我是房客,我搬进了新租的房子...");
    151     }
    152     
    153     public Renter() {
    154         System.out.println("我是打工族,我准备租房子...");
    155     }
    156     
    157 }
    158 
    159 import com.gxg.demo.jdk.proxy.Buyer;
    160 import com.gxg.demo.jdk.proxy.Landlord;
    161 import com.gxg.demo.jdk.proxy.Rentable;
    162 import com.gxg.demo.jdk.proxy.Renter;
    163 import com.gxg.demo.jdk.proxy.Salable;
    164 
    165 public class DynamicTest {
    166 
    167     public static void main(String[] args) {
    168         //中介公司
    169         HouseAgentCompany agentCompany = new HouseAgentCompany("NB房屋中介公司") ;
    170         System.out.println("-------------------------场景模拟开始-----------------------------");
    171         /**
    172          * 租房场景
    173          * */
    174         //房东找中介公司出租自己的房子
    175         Landlord landlordToRent = new Landlord() ;
    176         agentCompany.setTarget(landlordToRent); 
    177         //租客通过中介公司租房子
    178         Renter renter = new Renter() ;
    179         //中介公司随即分配一个中介服务租客
    180         Rentable randomAgentToRent = agentCompany.assign() ;
    181         randomAgentToRent.rentOutHouse(); 
    182         renter.moveIn(); 
    183         System.out.println("======================场景分界线====================");
    184         
    185         /**
    186          * 买房场景
    187          * */
    188         //房东找中介公司出售自己的房子
    189         Landlord landlordToSale = new Landlord() ;
    190         agentCompany.setTarget(landlordToSale); 
    191         
    192         //买家通过中介公司买房子
    193         Buyer buyer = new Buyer() ;
    194         //中介公司随即分配一个中介服务买家
    195         Salable randomAgentToSale = agentCompany.assign() ;
    196         randomAgentToSale.saleOutHouse(); 
    197         buyer.moveIn(); 
    198     }
    199 }
    200 
    201 运行结果:
    202 
    203 [NB房屋中介公司] 成立
    204 -------------------------场景模拟开始-----------------------------
    205 我是打工族,我准备租房子...
    206 这里是NB房屋中介公司,为您分配一个专职员工服务
    207 我是中介,我带租客看房子...
    208 我是房东,我与租客签合同并收取租金...
    209 我是中介,我拿到了报酬...
    210 我是房客,我搬进了新租的房子...
    211 ======================场景分界线====================
    212 我是白领,我准备买房子...
    213 这里是NB房屋中介公司,为您分配一个专职员工服务
    214 我是中介,我带租客看房子...
    215 我是房东,我与买家签合同并收取全款...
    216 我是中介,我拿到了报酬...
    217 我是房客,我搬进了新买的房子...

        动态代理与静态代理的区别在于事先对需要代理的类,需要代理的方法是未知的。

      需要调用者传入被代理的对象Target,根据通过反射机制获取到的Target实现的接口,动态生成一个代理对象ProxyObject,

      当程序调用ProxyObject代理对象实现的接口种某个方法,此时完成了对Target的某个方法的代理操作。

      由于事先未知所以动态代理可以代理多个接口。

  • 相关阅读:
    Spring Boot 2 快速教程:WebFlux Restful CRUD 实践(三)
    Spring Boot 2 快速教程:WebFlux 快速入门(二)
    ES 集群上,业务单点如何优化升级?
    Spring Boot 2.x 系列教程:WebFlux 系列教程大纲(一)
    泥瓦匠想做一个与众不同的技术"匠"
    java编程行业微信群,无论新手老手欢迎加入,会一直更新
    Spring Boot 2.x 系列教程:WebFlux REST API 全局异常处理 Error Handling
    解决方案:如何防止数据重复插入?
    阿里 Java 手册系列教程:为啥强制子类、父类变量名不同?
    品阿里 Java 开发手册有感
  • 原文地址:https://www.cnblogs.com/jack2013/p/4487687.html
Copyright © 2011-2022 走看看