/** * 代理模式: * 爲另外一個對象提供一個佔位符或者替身,以控制對這個對象的訪問 * * 按照控制方式的不一樣: * 遠程代理-->控制訪問遠程對象(不在同一個JVM的對象) * 虛擬代理-->控制訪問大開銷資源的對象(網絡或者IO對象) * 保護代理-->基於權限控制對資源的訪問(不一樣的權限,對資源的訪問層次不一樣) * 緩存代理-->爲開銷大的運算結果提供暫時的存儲 * 智能引用代理-->當主題被引用時,進行額外的操做 * 防火牆代理-->控制網絡資源的訪問 * 同步代理-->在多線程的狀況下爲主題提供安全的訪問 * 複雜隱藏代理-->用來隱藏一個類的複雜度並進行訪問控制 * 寫入時複製代理-->用來控制對象的複製 * * 模式對比: * 裝飾者模式-->包裝一個對象,對其提供額外的功能 * 適配器模式-->包裝一個對象,並提供不一樣的接口 * 外觀模式-->包裝許多對象以提供訪問的簡單接口 * 代理模式 -->包裝一個對象,以控制對它的訪問 * * * 示例: * 遠程代理使用RMI做爲示例 ,遠程訪問的還有EJB和WEBSERVICES * 虛擬代理使用網絡資源的加載做爲示例,利用JFRAME做爲示例 * 保護代理使用資源的訪問做爲示例,像SPRING的AOP就用了保護代理 * * * * @author Administrator * */
一、先看RMI示例的遠程代理java
RMI參考以前的文章 http://blog.csdn.net/undergrowth/article/details/24913031緩存
遠程服務接口安全
package com.undergrowth.proxy; import java.rmi.Remote; import java.rmi.RemoteException; /** * 代理模式: * 爲另外一個對象提供一個佔位符或者替身,以控制對這個對象的訪問 * * 按照控制方式的不一樣: * 遠程代理-->控制訪問遠程對象(不在同一個JVM的對象) * 虛擬代理-->控制訪問大開銷資源的對象(網絡或者IO對象) * 保護代理-->基於權限控制對資源的訪問(不一樣的權限,對資源的訪問層次不一樣) * 緩存代理-->爲開銷大的運算結果提供暫時的存儲 * 智能引用代理-->當主題被引用時,進行額外的操做 * 防火牆代理-->控制網絡資源的訪問 * 同步代理-->在多線程的狀況下爲主題提供安全的訪問 * 複雜隱藏代理-->用來隱藏一個類的複雜度並進行訪問控制 * 寫入時複製代理-->用來控制對象的複製 * * 模式對比: * 裝飾者模式-->包裝一個對象,對其提供額外的功能 * 適配器模式-->包裝一個對象,並提供不一樣的接口 * 外觀模式-->包裝許多對象以提供訪問的簡單接口 * 代理模式 -->包裝一個對象,以控制對它的訪問 * * * 示例: * 遠程代理使用RMI做爲示例 ,遠程訪問的還有EJB和WEBSERVICES * 虛擬代理使用網絡資源的加載做爲示例,利用JFRAME做爲示例 * 保護代理使用資源的訪問做爲示例,像SPRING的AOP就用了保護代理 * * * * @author Administrator * */ public interface GumballMachineRemote extends Remote{ /** * 每一個方法都必須拋出throws RemoteException異常 * @return * @throws RemoteException */ public String getLocation() throws RemoteException; public int getCount() throws RemoteException; public String getDescription() throws RemoteException; public State getCurrState() throws RemoteException; }
package com.undergrowth.proxy; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; /** * 遠程服務對象 * @author Administrator * */ public class GumballMachine extends UnicastRemoteObject implements GumballMachineRemote { String location; String description; int count; State currentState; /** * */ private static final long serialVersionUID = 1L; /** * 由於UnicastRemoteObject構造器須要處理異常 由於RMI在網絡上傳輸 會發生未知的異常 * * @throws RemoteException */ protected GumballMachine() throws RemoteException { super(); // TODO Auto-generated constructor stub } public GumballMachine(String location, String description, int count) throws RemoteException { super(); this.location = location; this.description = description; this.count = count; if(count>0){ this.currentState = new NoMoneyState(); } } @Override public String getLocation() { // TODO Auto-generated method stub return location; } @Override public int getCount() { // TODO Auto-generated method stub return count; } @Override public String getDescription() { // TODO Auto-generated method stub return description; } @Override public State getCurrState() { // TODO Auto-generated method stub return currentState; } }
package com.undergrowth.proxy; import java.io.Serializable; /** * 使用RMI傳輸State * @author Administrator * */ public interface State extends Serializable{ public void insertMoney(); }
package com.undergrowth.proxy; /** * 模擬初始狀態 * @author Administrator * */ public class NoMoneyState implements State { @Override public void insertMoney() { // TODO Auto-generated method stub System.out.println("投幣"); } }
package com.undergrowth.proxy; import java.net.MalformedURLException; import java.rmi.Naming; import java.rmi.NotBoundException; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; /** * RMI註冊服務和查找 * @author Administrator * */ public class RegisterRmiServer { public static void registerRmi(int port,String name,GumballMachineRemote remoteServer){ try { //建立register端口監聽 LocateRegistry.createRegistry(port); //綁定服務 Naming.rebind(name, remoteServer); //註冊遠程服務成功 System.out.println("註冊遠程服務成功"); } catch (RemoteException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static GumballMachineRemote getRmiServer(String name){ try { return (GumballMachineRemote) Naming.lookup(name); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (RemoteException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NotBoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } }
package com.undergrowth.proxy.test; import static org.junit.Assert.*; import java.rmi.RemoteException; import javax.imageio.spi.RegisterableService; import org.junit.Test; import com.undergrowth.proxy.GumballMachine; import com.undergrowth.proxy.GumballMachineRemote; import com.undergrowth.proxy.RegisterRmiServer; public class GumballMachineRemoteTest { @Test public void test() { try { //建立遠程服務 GumballMachineRemote remoteServer=new GumballMachine("廣州蘿崗", "科學大道高德匯", 100); //綁定 int port=4567; RegisterRmiServer.registerRmi(port,"rmi://192.168.1.101:"+port+"/remoteServer", remoteServer); //等待客戶端的查找RMI服務 while(true){ } } catch (RemoteException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Test public void testClient(){ int port=4567; GumballMachineRemote remoteServer=RegisterRmiServer.getRmiServer("rmi://192.168.1.101:"+port+"/remoteServer"); try { System.out.println(remoteServer.getCount()); System.out.println(remoteServer.getLocation()); System.out.println(remoteServer.getDescription()); System.out.println(remoteServer.getCurrState()); } catch (RemoteException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
查看服務端口網絡
控制檯多線程
100 廣州蘿崗 科學大道高德匯 com.undergrowth.proxy.NoMoneyState@193a6a5
二、虛擬代理,使用JFRAME加載圖片組件,加載網絡資源,使用狀態模式管理圖片的狀態eclipse
面板ide
package com.undergrowth.proxy; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import javax.swing.Icon; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; /** * 虛擬代理-->用於代理大開銷的資源 * 使用代理 在未加載資源時,顯示提示信息 * @author Administrator * */ public class LoadImageUrlFrame extends JFrame { /** * */ private static final long serialVersionUID = 1L; JMenu menu; JMenuBar menuBar; Map<String, String> imageResources = new HashMap<String, String>(); ImageComponent imageComponent; public LoadImageUrlFrame() { initResources(); menu = new JMenu("加載圖片"); //添加菜單項 addMenuItem(menu); menuBar = new JMenuBar(); menuBar.add(menu); setJMenuBar(menuBar); //初始化圖片 Icon icon=null; try { icon = new ImageProxy(new URL(imageResources.get("熊黛林"))); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } //添加圖片組件 imageComponent=new ImageComponent(icon); getContentPane().add(imageComponent); // 初始化操做 setSize(800, 500); setLocation((getToolkit().getScreenSize().width-getWidth())/2, (getToolkit().getScreenSize().height-getHeight())/2); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); } /** * 添加菜單項 * @param menu2 */ private void addMenuItem(JMenu menu2) { // TODO Auto-generated method stub for (Iterator iterator = imageResources.keySet().iterator(); iterator.hasNext();) { String name = (String) iterator.next(); //添加菜單項 JMenuItem menuItem=new JMenuItem(name); menuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub //當點擊菜單項的時候 //替換圖片組件中的圖片 並將frame重繪 try { //替換圖像組件中的圖片 imageComponent.setIcon(new ImageProxy(new URL(imageResources.get(e.getActionCommand())))); //重繪面板 repaint(); } catch (MalformedURLException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } }); menu2.add(menuItem); } } /** * 初始化圖片資源 */ private void initResources() { // TODO Auto-generated method stub imageResources .put("古力娜扎", "http://cdn.duitang.com/uploads/item/201207/27/20120727130449_hSxQk.jpeg"); imageResources.put("熊黛林", "http://ent.shangdu.com/stardata/P_5962597_1__1869907784.jpg"); } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub LoadImageUrlFrame frame = new LoadImageUrlFrame(); } }
package com.undergrowth.proxy; import java.awt.Graphics; import javax.swing.Icon; import javax.swing.JComponent; public class ImageComponent extends JComponent { /** * */ private static final long serialVersionUID = 1L; Icon icon; public ImageComponent(Icon icon){ this.icon=icon; } /** * 繪製圖片組件 */ @Override protected void paintComponent(Graphics g) { // TODO Auto-generated method stub super.paintComponent(g); int x=icon.getIconWidth(); int y=icon.getIconHeight(); x=(800-x)/2; y=(500-y)/2; icon.paintIcon(this, g, x, y); } public void setIcon(Icon icon) { this.icon = icon; } }
package com.undergrowth.proxy; import java.awt.Component; import java.awt.Graphics; import java.net.URL; import javax.swing.Icon; import javax.swing.ImageIcon; public class ImageProxy implements Icon { ImageIcon icon; //圖像的狀態 使用狀態模式 在加載與未加載之間切換 ImageState imageLoadState; ImageState imageNonLoadState; ImageState imageCurr; //代理圖片的位置 URL imageUrl; public ImageProxy(URL imageUrl){ this.imageUrl=imageUrl; imageNonLoadState=new ImageNonLoadState(this); imageLoadState=new ImageLoadState(this); imageCurr=imageNonLoadState; } /** * 委託給當前狀態進行處理 */ @Override public void paintIcon(Component c, Graphics g, int x, int y) { // TODO Auto-generated method stub imageCurr.paintIcon(c, g, x, y); } @Override public int getIconWidth() { // TODO Auto-generated method stub return imageCurr.getIconWidth(); } @Override public int getIconHeight() { // TODO Auto-generated method stub return imageCurr.getIconHeight(); } public ImageState getImageCurr() { return imageCurr; } public void setImageCurr(ImageState imageCurr) { this.imageCurr = imageCurr; } public ImageState getImageLoadState() { return imageLoadState; } public ImageState getImageNonLoadState() { return imageNonLoadState; } public ImageIcon getIcon() { return icon; } public void setIcon(ImageIcon icon) { this.icon = icon; } public URL getImageUrl() { return imageUrl; } }
package com.undergrowth.proxy; import javax.swing.Icon; /** * 圖像狀態接口 * @author Administrator * */ public interface ImageState extends Icon{ }
package com.undergrowth.proxy; import java.awt.Component; import java.awt.Graphics; public class ImageLoadState implements ImageState { ImageProxy imageProxy; public ImageLoadState(ImageProxy imageProxy) { super(); this.imageProxy = imageProxy; } @Override public void paintIcon(Component c, Graphics g, int x, int y) { // TODO Auto-generated method stub imageProxy.getIcon().paintIcon(c, g, x, y); } @Override public int getIconWidth() { // TODO Auto-generated method stub return imageProxy.getIcon().getIconWidth(); } @Override public int getIconHeight() { // TODO Auto-generated method stub return imageProxy.getIcon().getIconHeight(); } }
圖片未加載狀態學習
package com.undergrowth.proxy; import java.awt.Component; import java.awt.Graphics; import javax.swing.ImageIcon; public class ImageNonLoadState implements ImageState { ImageProxy imageProxy; public ImageNonLoadState(ImageProxy imageProxy){ this.imageProxy=imageProxy; } @Override public void paintIcon(final Component c, Graphics g, int x, int y) { // TODO Auto-generated method stub g.drawString("正在加載圖片中。。。", x, y); //使用線程 加載網絡資源 加載完成後 重繪面板 new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub //修改圖片狀態 imageProxy.setIcon(new ImageIcon(imageProxy.getImageUrl())); imageProxy.setImageCurr(imageProxy.getImageLoadState()); //重繪 c.repaint(); } }).start(); } @Override public int getIconWidth() { // TODO Auto-generated method stub return 400; } @Override public int getIconHeight() { // TODO Auto-generated method stub return 400; } }
三、保護代理,用於控制權限訪問測試
代理者與被代理者的共同接口ui
package com.undergrowth.proxy; /** * Person接口 用於代理和被代理的共同接口 * 用於實例保護代理 * @author Administrator * */ public interface Person { public String getName() ; public void setName(String name) ; public String getHobby(); public void setHobby(String hobby) ; public String getDescription() ; public void setDescription(String description); public float getScore() ; public void setScore(float score) ; }被代理者
package com.undergrowth.proxy; /** * 每一個人均可以維護本身的信息 可是評分不能本身維護 須要別人維護 * @author Administrator * */ public class PersonBeanImpl implements Person{ String name; String hobby; String description; float score; public PersonBeanImpl(String name, String hobby, String description) { super(); this.name = name; this.hobby = hobby; this.description = description; this.score = 0; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getHobby() { return hobby; } public void setHobby(String hobby) { this.hobby = hobby; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public float getScore() { return score; } public void setScore(float score) { this.score = score; } @Override public String toString() { return "PersonBean [name=" + name + ", hobby=" + hobby + ", description=" + description + ", score=" + score + "]"; } }
package com.undergrowth.proxy; import java.lang.reflect.Proxy; /** * 簡單工廠 * 利用JDK內置的代理 建立代理對象 * @author Administrator * */ public class ProxyFactory { public static Person getOwnerPersonBean(Person personBean){ return (Person) Proxy.newProxyInstance(personBean.getClass().getClassLoader(), personBean.getClass().getInterfaces(), new PersonBeanOwnerHandler(personBean)); } public static Person getNonOwnerPersonBean(Person personBean){ return (Person) Proxy.newProxyInstance(personBean.getClass().getClassLoader(), personBean.getClass().getInterfaces(), new PersonBeanNonOwnerHandler(personBean)); } }
package com.undergrowth.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * 本身處理器(擁有者) 本身能夠維護本身的信息 除了評分之外 * @author Administrator * */ public class PersonBeanOwnerHandler implements InvocationHandler { Person personBean; public PersonBeanOwnerHandler(Person personBean) { super(); this.personBean = personBean; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub if(method.getName().startsWith("get")){//獲取本身的其餘信息 return method.invoke(personBean, args); }else if(method.getName().equals("setScore")){ throw new IllegalAccessException("你不能本身給本身評分"); }else if(method.getName().startsWith("set")){ //設置本身的其餘信息 return method.invoke(personBean, args); } return null; } }
package com.undergrowth.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * 不是本身處理器(非擁有者) 能夠獲取信息 能夠設置其餘人的評分 可是不能設置其餘人的其餘信息 * @author Administrator * */ public class PersonBeanNonOwnerHandler implements InvocationHandler { Person personBean; public PersonBeanNonOwnerHandler(Person personBean) { super(); this.personBean = personBean; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub if(method.getName().startsWith("get")){ return method.invoke(personBean, args); }else if (method.getName().equals("setScore")) { return method.invoke(personBean, args); }else if (method.getName().startsWith("set")) { throw new IllegalAccessException("你不能設置其餘人的其餘信息"); } return null; } }
package com.undergrowth.proxy.test; import static org.junit.Assert.*; import java.lang.reflect.InvocationHandler; import org.junit.Test; import com.undergrowth.proxy.Person; import com.undergrowth.proxy.PersonBeanImpl; import com.undergrowth.proxy.PersonBeanOwnerHandler; import com.undergrowth.proxy.ProxyFactory; public class PersonBeanTest { @Test public void test() { PersonBeanImpl personBean = new PersonBeanImpl("科比", "籃球", "職業素養最好的運動員"); System.out.println(personBean); //建立擁有者 Person personBeanOwner = ProxyFactory.getOwnerPersonBean(personBean); System.out.println(personBeanOwner.getName()); personBeanOwner.setDescription(personBeanOwner.getDescription() + ",老將中的戰鬥機"); System.out.println(personBeanOwner.getDescription()); System.out.println(personBean); try { // 本身給本身評分 會發生異常 personBeanOwner.setScore(100); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); System.out.println(personBean); } //建立非擁有者 Person personNonOwner=ProxyFactory.getNonOwnerPersonBean(personBean); System.out.println(personNonOwner.getDescription()); personNonOwner.setScore(100); System.out.println(personBean); try { //設置別人的信息 會發生異常 personNonOwner.setDescription("足球踢得很是好"); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); System.out.println(personBean); } } }
PersonBean [name=科比, hobby=籃球, description=職業素養最好的運動員, score=0.0] java.lang.reflect.UndeclaredThrowableException at $Proxy4.setScore(Unknown Source) at com.undergrowth.proxy.test.PersonBeanTest.test(PersonBeanTest.java:29) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:601) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) 科比 職業素養最好的運動員,老將中的戰鬥機 PersonBean [name=科比, hobby=籃球, description=職業素養最好的運動員,老將中的戰鬥機, score=0.0] at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) Caused by: java.lang.IllegalAccessException: 你不能本身給本身評分 at com.undergrowth.proxy.PersonBeanOwnerHandler.invoke(PersonBeanOwnerHandler.java:29) ... 25 more PersonBean [name=科比, hobby=籃球, description=職業素養最好的運動員,老將中的戰鬥機, score=0.0] 職業素養最好的運動員,老將中的戰鬥機 PersonBean [name=科比, hobby=籃球, description=職業素養最好的運動員,老將中的戰鬥機, score=100.0] java.lang.reflect.UndeclaredThrowableException at $Proxy4.setDescription(Unknown Source) at com.undergrowth.proxy.test.PersonBeanTest.test(PersonBeanTest.java:42) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:601) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) Caused by: java.lang.IllegalAccessException: 你不能設置其餘人的其餘信息 at com.undergrowth.proxy.PersonBeanNonOwnerHandler.invoke(PersonBeanNonOwnerHandler.java:31) ... 25 more PersonBean [name=科比, hobby=籃球, description=職業素養最好的運動員,老將中的戰鬥機, score=100.0]
以上便是遠程代理、虛擬代理、保護代理的示例代碼,代理模式的應用點太多了,後續遇到或者學習到,持續更新中,記錄學習的腳步