天天看點

代理模式

概念:委托一個代理類對另一個類進行控制(代理類中有被代理類的對象,同時可以在代理類中增強)

使用場景:aop(可以控制被代理類是否被調用,是否被代理)。

優點:1.確定被代理類的隐秘性

           2.降低耦合性(不用挨個加需要增強的方法)

缺點:類數量的增多,結構更複雜。

類圖:

代理模式
代碼:

靜态代理

1 靜态代理:靜态代理就是把增強的方法寫在代理的類中,在編譯時就确定了,這樣耦合性比較高,除了方法量級較小或者增強的方法固定,其他情況不推薦。

subject接口

1. public interface PlayLol{
2. public void plya();
3. }      

realSubject

1. public class IsPlay implements PlayLol{
2. public void play() {
3.         System.out.println("開始玩");
4.     }
5. }      

proxy

1. public class ProxySubject implements PlayLol{
2. 
3. private PlayLol playLol;
4.  //關鍵,将被代理對象傳進來
5. public ProxySubject(final PlayLol playLol) {
6. this.playLol = playLol;
7.     }
8. 
9. public void play() {
10.         System.out.println("打開電腦");
11. //可以增加控制 ,可以不讓他玩。。。
12.         subject.play();
13.         System.out.println("15投");
14.     }
15. }      

調用

1. public class MainClass {
2. public static void main(String[] args) {
3. PlayLol playLol = new IsPlay();
4.         playLol.paly();
5. 
6. System.out.println("============");
7. 
8. ProxySubject proxySubject = new ProxySubject(playLol);
9.         proxySubject.paly();
10.     }
11. }      

2.動态代理:

JDK代理

代理類

1. public class ProxyHandler implements InvocationHandler {
2. 
3. private Object object;
4. 
5. public DynamicProxyHandler(final Object object) {
6. this.object = object;
7.     }
8. 
9. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
10. System.out.println("先開電腦");
11. Object result = method.invoke(object, args);
12. System.out.println("關電腦");
13. return result;
14.     }
15. }      

調用:

1. public class MainClass {
2. public static void main(String[] args) {
3.         PlayLol subject = new IsPlay();
4. /**
5.          * ClassLoader loader:指定目前目标對象使用的類加載器,擷取加載器的方法是固定的
6.          * Class<?>[] interfaces:指定目标對象實作的接口的類型,使用泛型方式确認類型
7.          * InvocationHandler:指定動态處理器,執行目标對象的方法時,會觸發事件處理器的方法
8.          * 都是固定寫法
9.          */
10.         PlayLol proxySubject = (PlayLol) Proxy.newProxyInstance(PlayLol.class.getClassLoader(),
11. new Class[]{PlayLol.class},
12. new ProxyHandler(subject));
13.         proxySubject.play();
14.     }      

CGLib動态代理

如果被代理類沒有接口不可以使用jdk動态代理

被代理類

1. public class IsPlay{
2. public void play() {
3.         System.out.println("開始玩");
4.     }
5. }      
1. public class CglibProxy implements MethodInterceptor {
2. private Object target;//業務類對象,供代理方法中進行真正的業務方法調用
3. 
4. //相當于JDK動态代理中的綁定
5. public Object getInstance(Object target) {
6. this.target = target;  //給業務對象指派
7. Enhancer enhancer = new Enhancer(); //建立加強器,用來建立動态代理類
8.         enhancer.setSuperclass(this.target.getClass());  //為加強器指定要代理的業務類(即:為下面生成的代理類指定父類)
9. //設定回調:對于代理類上所有方法的調用,都會調用CallBack,而Callback則需要實作intercept()方法進行攔
10.         enhancer.setCallback(this);
11. // 建立動态代理類對象并傳回
12. return enhancer.create();
13. // 以上都是固定寫反
14.     }
15. // 實作回調方法
16. public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
17. System.out.println("開電腦");
18.         proxy.invokeSuper(obj, args); //調用業務類(父類中)的方法
19. System.out.println("關電腦");
20. return null;
21.     }
22. }      
1. public class MainClass {
2. public static void main(String[] args) {
3. IsPlay play= new IsPlay();
4. CglibProxy cglibProxy = new CglibProxy();
5. IsPlay realSubjectProxy =
6.                 (IsPlay) cglibProxy.getInstance(play);
7.         realSubjectProxy.play();
8.     }
9. }      

引用:CGLIB建立的動态代理對象比JDK建立的動态代理對象的性能更高,但是CGLIB建立代理對象時所花費的時間卻比JDK多得多。是以對于單例的對象,因為無需頻繁建立對象,用CGLIB合适,反之使用JDK方式要更為合适一些。同時由于CGLib由于是采用動态建立子類的方法,對于final修飾的方法無法進行代理。