我和春天有个约会(四)

来源:互联网 发布:pro recorder替代软件 编辑:程序博客网 时间:2024/04/25 18:08
 
Spring AOP头绪众多,先从基本观念入手。
 
Spring AOP基本要务
悄悄地我走了,正如我悄悄地来……
AOP是OOP之后编程思想的又一次变革。在AOP的编程模型中对象A正交地“横切”到对象B的生命周期当中,而B对此却浑然不知,这样以“Aspect”的方式提高了类的重用性、灵活性以及可维护性,毕竟不用对B再动手脚,只要让它做好自己的本职工作,额外的事情交给A来完成。动态代理初步实现了这一点,而Spring AOP提供的方式却更为丰富而灵活。
Spring AOP的几个基本点就是AdviceTargetProxy。Spring AOP的实现基于动态代理,因此理解后者有助于理解前者。
坐而论道不如躬身实践,如下HelloSpeaker就是那个对Aspect浑然不知的傻小子,我们称为Target。为了验证后面的ThrowsAdvice,我故意在参数为空时抛出异常。
 
public class HelloSpeaker implements IHello {
    
public String say_hello(String msg) {
        
if (msg == null || msg.equals("")) {
            
throw new NullPointerException("The arg is null...");
        }
 else {
            System.out.println(
"hello," + msg + "!");
        }

        
return "succeed";
    }

}

 
IHello是从HelloSpeaker引出的接口,这也是HelloSpeaker和Aspect唯一相接的地方,正是凭借这个接口,Target被Aspect玩弄于股掌。
public interface IHello {
    
public String say_hello(String msg);
}

 
下面几个类就是所谓的Advice,Advice就是“横切”的具体行为,如提供日志服务、权限管理等,它们在各种AOP实现中被织入(Weave)主体业务中。
AfterReturningAdvice接口的afterReturning方法在Target方法之后运行;MethodBeforeAdvice接口的before方法在Target方法之前运行;MethodInterceptor的invoke方法更为霸道,除了可在前后修饰之外还决定Target方法的运行,这个做法就类似于动态代理了。
ThrowsAdvice接口有些特殊,并无接口方法,只要实现接口者提供afterThrowing方法,并在方法中提供Throwable参数,并且可选method、target、args等参数。另外该接口并不改变原有的异常处理流程。
public class LogAfterAdvice implements AfterReturningAdvice {

    
public void afterReturning(Object obj_res, Method method, Object[] args,    Object target) throws Throwable {
        String res 
= (String) obj_res;
        System.out.println(
"method " + method.getName() + " ends,res..." + res);
    }

}


public class LogAroundAdvice implements MethodInterceptor {

    
public Object invoke(MethodInvocation method_invocation) throws Throwable {
        System.out.println(
"In method-intercept, before method");
        Object res 
= null;
        
try {
            res 
= method_invocation.proceed();
        }
 finally {
            System.out.println(
"In method-intercept, Method "
                    
+ method_invocation.getMethod().getName() + " end.");
        }

        
return res;
    }

}



public class LogBeforeAdvice implements MethodBeforeAdvice {

    
public void before(Method method, Object[] args, Object target)
            
throws Throwable {
        System.out.println(
"Before " + method.getName() + " starts");
    }


}



public class LogExceptionAdvice implements ThrowsAdvice {
    
public void afterThrowing(Method method, Object[] args, Object target,            Throwable e) {
        System.out.println(
"Exception " + e + ":"
                
+ " occurs at method " + method.getName());
    }

}

 
维系各个Advice和Target的纽带就是Proxy,在这里就是ProxyFactoryBean,定义在配置文件当中。在这个代理当中指定Target及其interface,指定了各类advice。
 <bean id="logBeforeAdvice" class="onlyfun.caterpillar.aop.LogBeforeAdvice"/>
  
  
<bean id="logAfterAdvice" class="onlyfun.caterpillar.aop.LogAfterAdvice"/>
  
  
<bean id="logInterceptor" class="onlyfun.caterpillar.aop.LogAroundAdvice"/>
  
  
<bean id="logException" class="onlyfun.caterpillar.aop.LogExceptionAdvice"/>
  
  
<bean id="helloSpeaker" class="onlyfun.caterpillar.aop.HelloSpeaker"/>
  
  
<bean id="helloProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
      
<property name="proxyInterfaces" value="onlyfun.caterpillar.aop.IHello"/>
      
<property name="target" ref="helloSpeaker"/>
      
<property name="interceptorNames">
          
<list>
              
<value>logBeforeAdvice</value>
              
<value>logAfterAdvice</value>
              
<value>logInterceptor</value>
              
<value>logException</value>
          
</list>
      
</property>
  
</bean>
 
</beans>
 
测试一下,用ApplicationContext提取配置文件,获得代理对象并转化为IHello接口,从接口调用方法,第一次传递非空串,第二次传递空串引发异常:
public class MainTest {
    
public static void main(String[] args) {
        ApplicationContext context 
= new ClassPathXmlApplicationContext(
                
"beanaop-config.xml");
        IHello helloProxy 
= (IHello) context.getBean("helloProxy");
        
try {
            helloProxy.say_hello(
"Tommy");
            helloProxy.say_hello(
null);
        }
 catch (Throwable t) {
            System.out.println(t);
        }

    }

}

 
结果如下:
Before say_hello starts
In method-intercept, before method
hello,Tommy!
In method-intercept, Method say_hello end.
method say_hello ends,res...succeed
====================
Before say_hello starts
In method-intercept, before method
In ThrowsAdvice:Exceptionjava.lang.NullPointerException: The arg is null...: occurs at method say_hello
In method-intercept, Method say_hello end.
in main test:java.lang.NullPointerException: The arg is null...
一切如常。搞清了基本概念,后面或有变化不外如是。
原创粉丝点击