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的某个方法的代理操作。
由于事先未知所以动态代理可以代理多个接口。