Spring AOP中的代理模式

代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。 

Spring 为解耦而诞生,其中AOP(面向切面编程)是很浓重的一笔。

这里简单记录一下AOP 给我带来的好处:

1.

用了一段时间,想通过简单的代码,更好的阐述以及理解它。

 

以前:假设我们有个简单的业务,还是经典的Hello World,那么我们定义一个Service 接口,一个ServiceImpl 实现类,一个sayHello 方法,这里使用网上很经典的日志记录的例子。

 

1.Service接口:定义一个sayHello  的业务方法

Java代码   收藏代码
  1. public interface Service {  
  2.     public void sayHello();  
  3. }  

 

2.ServiceImpl实现类:主要是打印HelloWord,但是日常项目中,在主要业务前后可能会添加日志记录,或者开启事务等其他必要操作。

Java代码   收藏代码
  1. public class ServiceImpl implements Service{  
  2.   
  3.     @Override  
  4.     public void sayHello() {  
  5.         System.out.println("前置日记:打印、启动事务等..");  
  6.         System.out.println("Hello world!");  
  7.         System.out.println("后置日记:打印、关闭事务等..");  
  8.     }  
  9. }  

 

例子很简单,那么假设,我们不光拥有sayHello ,还有sayBye 等多个方法,并且都需要其他操作呢?那么你是不是会写很多个这样的,重复的代码?

当然,你可以减少一部分工作量,你可以这样:

Java代码   收藏代码
  1. public class ServiceImpl implements Service{  
  2.   
  3.     @Override  
  4.     public void sayHello() {  
  5.         before();  
  6.         System.out.println("Hello world!");  
  7.         after();  
  8.     }  
  9.   
  10.     @Override  
  11.     public void sayBye() {  
  12.         before();  
  13.         System.out.println("Bye bye!");  
  14.         after();  
  15.     }  
  16.       
  17.     public static void before(){  
  18.         System.out.println("前置日记:打印、启动事务等..");  
  19.     }  
  20.       
  21.     public static void after(){  
  22.         System.out.println("后置日记:打印、关闭事务等..");  
  23.     }  
  24. }  

 

我们再次假设,如果我们拥有更多的业务方法:sayHi(),sayOther()....,需要更多的其他操作:打印信息,传输记录....。并且其他ServiceImpl 里面的方法也需要这些方法呢?那么我们是不是每个类又要继续添加呢?

当然,你可以这样做:建立一个对Service 添加额外功能的类,统一提供。

Java代码   收藏代码
  1. public class ServiceFactory {  
  2.     public static void before(){  
  3.         System.out.println("前置日记:打印、启动事务等..");  
  4.     }  
  5.       
  6.     public static void after(){  
  7.         System.out.println("后置日记:打印、关闭事务等..");  
  8.     }  
  9.       
  10.     public static void other(){  
  11.         System.out.println("做其他的事..");  
  12.     }  
  13. }  

 

ServiceImpl 就成这样:

Java代码   收藏代码
  1. public class ServiceImpl implements Service{  
  2.   
  3.     @Override  
  4.     public void sayHello() {  
  5.         ServiceFactory.before();  
  6.         System.out.println("Hello world!");  
  7.         ServiceFactory.after();  
  8.     }  
  9.   
  10.     @Override  
  11.     public void sayBye() {  
  12.         ServiceFactory.before();  
  13.         System.out.println("Bye bye!");  
  14.         ServiceFactory.after();  
  15.     }  
  16.   
  17.     @Override  
  18.     public void sayHi() {  
  19.         ServiceFactory.before();  
  20.         System.out.println("Hi");  
  21.         ServiceFactory.after();  
  22.           
  23.         ServiceFactory.other();  
  24.     }  
  25. }  

 

 这样代码,感觉是少了一些,但是我们的原则是尽量 别重复同样的代码,提高代码的复用性,改动最小为基准。也许业务很复杂,比较多,那么你要重复多少代码,整个类要写得多麻烦所啊!如果到时候有些假设before 和after 需要变化位置,你又要改动多少呢?

 

当然,目前的的JDK (大于1.3)为了解决这些问题,为我们提供的反射机制,动态代理机制。看看如何更好的解决这个问题。这里先copy 下,什么是代理:

 

Java的动态代理机制
代理模式是常用的Java设计模式。代理类主要负责为委托类预处理消息、过滤信息、把消息转发给委托类,以及事后处理信息等。
    理论 - -总是那么抽象(~。~),简单点说,就是:1.我的目的是去学校,那么校服 早餐 校车,这些我都需要,但是不由我做,全部代理给我父母搞定了(当然我是自己搞定的。)2.再简单的说就是:我只关注我主要的事情,其他附加的事情,全部交给别人搞定。看代码..

MyPorxy 我的代理类:

Java代码   收藏代码
  1. import java.lang.reflect.InvocationHandler;  
  2. import java.lang.reflect.Method;  
  3. import java.lang.reflect.Proxy;  
  4.   
  5.   
  6. public class MyProxy implements InvocationHandler{  
  7.       
  8.     // 目标对象,也就是我们主要的业务,主要目的要做什么事  
  9.     private Object delegate;  
  10.       
  11.     /** 
  12.      * 和你额外需要做得事情,进行绑定,返回一个全新的对象(写法,基本上固定的) 
  13.      * @param delegate 
  14.      * @return 
  15.      */  
  16.     public Object bind(Object delegate){  
  17.         this.delegate = delegate;  
  18.         return Proxy.newProxyInstance(this.delegate.getClass().getClassLoader(),   
  19.                 this.delegate.getClass().getInterfaces(), this);  
  20.     }  
  21.       
  22.     /** 
  23.      * 你刚才需要执行的方法,都需要通过该方法进行动态调用 
  24.      */  
  25.     @Override  
  26.     public Object invoke(Object proxy, Method method, Object[] args)  
  27.             throws Throwable {  
  28.         Object obj = null;  
  29.         // 执行前置的方法  
  30.         ServiceFactory.before();  
  31.         // 通过反射,执行目标方法,也就是你的主要目的  
  32.         obj = method.invoke(this.delegate, args);  
  33.         // 执行后置的方法  
  34.         ServiceFactory.after();  
  35.         // 返回值给调用者  
  36.         return obj;  
  37.     }  
  38.   
  39. }  

 

这里运用的反射知识,还需要去看看,这里就不解释了。

 

ServiceImpl 变化:

Java代码   收藏代码
  1. public class ServiceImpl implements Service{  
  2.   
  3.     @Override  
  4.     public void sayHello() {  
  5.         System.out.println("Hello world!");  
  6.     }  
  7.   
  8.     @Override  
  9.     public void sayBye() {  
  10.         System.out.println("Bye bye!");  
  11.     }  
  12.   
  13.     @Override  
  14.     public void sayHi() {  
  15.         System.out.println("Hi");  
  16.     }  
  17. }  

 

   测试类:

 

Java代码   收藏代码
  1. public class Test {  
  2.   
  3.     /** 
  4.      * 测试类 
  5.      * @param args 
  6.      */  
  7.     public static void main(String[] args) {  
  8.         // 不启用代理  
  9.         //Service service = new ServiceImpl();  
  10.         // 使用代理  
  11.         Service service = (Service)new MyProxy().bind(new ServiceImpl());  
  12.           
  13.         service.sayHello();  
  14.         service.sayBye();  
  15.         service.sayHi();  
  16.     }  
  17. }  

 

 

OK,那么你现在看看,我们的业务实现类ServiceImpl 是不是干净多了,代码是不是在某些地方见过呢?即时你再进行添加更多的方法,也可以同样实现了对吗?当然,在Test里面,假设我们有的方法想用,有的方法不想用,那么又该怎么实现呢?


详细介绍:

代理(Proxy)有两种:
静态代理-Static proxy
动态代理-Dynamic proxy

1. 静态代理
为实现静态代理需要为HelloSpeaker写一个HelloProxy类,同样实现IHello接口,并在hello方法执行log,并执行HelloSpeaker的hello()方法。

Java code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/**
  * 此处可以为接口也可以为抽象类
  * @author ljn
  *
  */
public  interface  IHelloSpeaker {
     public  abstract  void  hello();
}
 
/**
  * 接口实现类日志功能  简单的打印一句话
  * @author ljn
  *
  */
public  class  HelloSpeaker  implements  IHelloSpeaker {
     public  void  hello(){
         System.out.println( "............this is Log" );
     }
}
 
/**
  * 代理类实现IHelloSpeaker接口,同时拥有实际对象的引用(private HelloSpeaker helloObj;//代理类内部引用真实类)
  * 代理必须完成委托对象的动作,也可以添加自己的动作(doBefore,doAfter)。
 
  * @author ljn
 
  */
public  class  HelloProxy  implements  IHelloSpeaker {
 
     private  HelloSpeaker helloObj; // 代理类内部引用委托类
 
     public  HelloProxy(HelloSpeaker helloSpeaker) {
         this .helloObj = helloSpeaker;
     }
 
     private  void  doBefore() {
         System.out.println( "method doBefore invoke!" );
     }
 
     private  void  doAfter() {
         System.out.println( "method doAfter invoke!" );
 
     }
 
     @Override
     public  void  hello() {
         // TODO Auto-generated method stub
         doBefore(); // 其他业务逻辑
         helloObj =  new  HelloSpeaker();
         helloObj.hello(); // 委托类具体的业务逻辑。
         doAfter(); // 其他业务逻辑
     }
}
/**
*测试类
*/
public  class  Test {
     public  static  void  main(String[] args) {
//其中HelloProxy中helloObject为需要代理的对象,在其它地方如下来使用代理机制
         IHelloSpeaker proxy =  new  HelloProxy( new  HelloSpeaker());
         proxy.hello();
     }
}


2:动态代理
Java code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import  java.lang.reflect.InvocationHandler;
import  java.lang.reflect.Method;
import  java.lang.reflect.Proxy;
 
public  class  LogHandler  implements  InvocationHandler { 
     
     private  Object delegate;
 
     public  Object bind(Object delegate) { 
         this .delegate = delegate; 
         return  Proxy.newProxyInstance( 
                            delegate.getClass().getClassLoader(), 
                            delegate.getClass().getInterfaces(), 
                            this ); 
     }
 
     @Override
     public  Object invoke(Object proxy, Method method, Object[] args)
             throws  Throwable {
         Object result =  null ;         
         try 
             System.out.println( "method starts..." +method);
             result = method.invoke(delegate, args);
             System.out.println( "method starts..." +method);
         catch  (Exception e){ 
             e.printStackTrace();
         }        
         return  result; 
     }
}
//测试程序
public  static  void  main(String[] args) {
         LogHandler logHandler  =  new  LogHandler(); 
         
         IHelloSpeaker helloProxy = 
                 (IHelloSpeaker) logHandler.bind( new  HelloSpeaker()); 
         helloProxy.hello();
     }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值