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的某个方法的代理操作。

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

原文地址:https://www.cnblogs.com/jack2013/p/4487687.html