Spring学习笔记(八)-----Spring in Action

Spring学习笔记(八)-----Spring in Action
    Spring的AOP框架允许你将分散在系统中的功能块放到一个地方-切面。重用通用功能的常用面向对象技术是使用继承和委

托模式。但由于基础类在系统中到处使用,使用继承会引起脆弱的继承关系。委托模式比较笨拙,依然需要重复调用委托对象

。使用AOP,你也是在一个地方定义通用功能,只是你可以声明式定义何时何地应用这些功能,而不一年欧冠在需要新功能的地

方修改代码。交叉业务现在可以被模块化到特定对象切面中。这样做有2个好处,第一,现在每个业务逻辑放在一个地方,而不

是分散到代码的各个角落。第二,我们的服务模块现在更加清晰,因为他们只包含他们的核心功能,辅助功能转移到切面中。

    切面(Aspect):切面是你要实现的交叉功能。切面最常用的例子是日志记录。日志记录在系统中到处需要用到。
    连接点(Joinpoint):连接点是应用程序执行过程中插入切面的地点。这个地点可以是方法调用,异常抛出,或者是要修改

字段。切面代码在这些地方插入到你的应用流程中,添加新的行为。
    通知(Advice):通知切面的实际实现。它通知应用系统新的行为。
    切入点(PointCut):切入点定义了通知应该应用在哪些连接点。通知可以应用到AOP框架支持的任何连接点。你并不希望把

所有切面应用到所有可能的连接点上。切入点让你指定通知应用到什么地方。
    引入(Introduction):引入允许你为已存在类添加新方法和属性。
    目标对象(Target):目标对象是被通知对象。它既可以是你编写的类也可以是你要添加定制行为的第三方类。
    代理(Proxy):代理是将通知应用到目标对象后创建的对象。对于客户对象来说,目标对象和代理对象是一样的。
    织入(Weaving):织入是将切面应用到目标对象从而创建一个新的代理对象的过程。
    切入点定义了哪些连接点要被通知。

    Spring的AOP实现:
    在Spring中所有的通知都以Java类的形式编写。代理Bean只有在第一次被应用系统需要的时候才被创建。如果你使用的是ApplicationContext,代理对象在BeanFactory载入所有Bean的时候被创建。因为Spring在运行期创建代理,所以使用Spring AOP不需要特殊编译期。
    Spring有2种代理创建方式。如果目标对象实现了一个接口暴露的方法,Spring将使用JDK的Java.lang.reflect.Proxy类创建代理。这个类让Spring动态产生一个新的类,它实现了所需的接口,织入了通知,并且代理对目标对象的所有请求。
    如果目标对象没有实现任何接口,Spring使用CGLIB库生成目标对象的子类。在创建这个子类的时候,Spring将通知织入,并且对目标对象的调用委托给这个子类。

    通知包含了切面的逻辑。所以当你创建一个通知对象的时候,你是在编写实现交叉功能的代码。而且,记住Spring的连接点模型是建立在方法拦截上。这意味着你编写的Spring通知会在方法调用周围的各个地方织入系统中。通知的类型有:Around,Before,After,Throws

前置通知:需要扩展MethodBeforeAdvice接口
public interface MethodBeforeAdvice{
    void before(Method method,Object[] args,Object target)throws Throwable;
}

<? xml version="1.0" encoding="UTF-8" ?>
<! DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd" >

< beans >
    
<!--  创建代理目标对象  -->
    
< bean  id ="kwikEMartTarget"  class ="com.springinaction.chapter03.store.ApuKwikEMart" ></ bean >
    
<!--  创建通知  -->
    
< bean  id ="welcomeAdvice"  class ="com.springinaction.chapter03.store.WelcomeAdvice" ></ bean >
    
<!--  创建代理对象  -->
    
< bean  id ="kwikEMart"  class ="org.springframework.aop.framework.ProxyFactoryBean" >
        
<!--  代理类实现的接口  -->
        
< property  name ="proxyInterfaces" >
            
< value > com.springinaction.chaper03.store.kwikEMart </ value >
        
</ property >
        
<!--  要织入的通知  -->
        
< property  name ="interceptorNames" >
            
< list >
                
< value > welcomeAdvice </ value >
            
</ list >
        
</ property >
        
<!--  要代理的目标对象  -->
        
< property  name ="target" >
            
< ref  bean ="kwikEMartTarget" />
        
</ property >
    
</ bean >
</ beans >

ProxyFactoryBean类是一个在BeanFactory中显示的创建代理对象的中心类。像我们展示的那样,你可以给它一个要实现的接口,一个要代理的目标对象,一个要织入的通知,并且它将创建一个崭新的代理对象。通常配置ProxyFactoryBean,让它实现和目标对象一样的接口。

后置通知:需要实现AfterReturningAdvice
public interface AfterReturningAdvice{
    void afterReturning(Object returnValue,Method method,Object[] args,Object target)throws Throwable;
}

环绕通知:需要实现MethodInterceptor,同时实现前置和后置通知
public interface MethodInterceptor extends Interceptor{
    Object invoke(MethodInvocation invocation)throws Throwable;
}
MethodInterceptor接口和前面介绍的2种通知不同点:
1、MethodInterceptor能够控制目标方法是否真的被调用。通过调用MethodInvocation.proceed()方法来调用目标方法。这一点不同于前两个,目标方法总是被调用的。
2、MethodInterceptor让你可以控制返回的对象。就是说你可以返回一个与proceed()方法返回对象完全不同的对象。
package  com.wyq.spring.base.aopinstance;

import  java.util.HashSet;
import  java.util.Set;

import  org.aopalliance.intercept.MethodInterceptor;
import  org.aopalliance.intercept.MethodInvocation;
import  org.jboss.remoting.samples.transporter.basic.Customer;


/**  
 * 
@author  作者 
 * 
@version  创建时间:2009-11-5 下午05:19:19 
 * 类说明 
 
*/
public   class  OnePerCustomerInterceptor  implements  MethodInterceptor {
    
// 定义包含用户的集合
     private  Set customers  =   new  HashSet();
    
/*
     * 当你在方法调用的前后都需要交叉切面逻辑时,应该使用MethodInterceptor。由于你必须要记得显示调用
     * invocation.proceed()方法,所以,在满足要求的情况下,最好还是使用MethodBeforeAdvice或
     * AfterReturningAdvice.
     
*/
    
    
public  Object invoke(MethodInvocation invocation)  throws  Throwable {
         Customer customer 
=  (Customer)invocation.getArguments()[ 0 ];
         
if (customers.contains(customer)){
             System.out.println(
" 抛出异常 " );
         }
         
// 调用目标方法
         Object squishee  =  invocation.proceed();
         
// 添加用户
         customers.add(customer);
         
// 返回目标方法结果
         return  squishee;
    }
}



   

你可能感兴趣的:(Spring学习笔记(八)-----Spring in Action)