Spring(六)

Spring面向方面编程(AOP)

2016/6/19 12:51:27 seventeenWen

AOP总结


虽然可以通过PreformanceHandler实现横切逻辑的动态织入,但还是有不足之处:

  1. 目标类的所有方法都添加了横切逻辑,而有时,并不是所有的方法都需要横切逻辑。
  2. 通过硬编码的方式织入了横切逻辑的织入点,在业务方法开始前和结束后织入代码。
  3. 需要手工编写代理对象的创建过程,为不同类创建代理是,需要编写不同的代码。

Spring的AOP便解决了上面的三点,

  • 通过Pointcut(切点)指定了在哪些类的哪些方法上织入横切逻辑。
  • 通过Advice(增强)描述横切逻辑的方法和具体织入的点(方法前,方法后,方法的两端)。
  • 通过Advisor(切面)将Pointcut和Advice两者组装起来。

Spring的Advice(增强)

  1. 前置增强(org.springframework.aop.BeforeAdvice):表示在方法前增强。
    BeeforeAdvice接口只定义了一个方法
    void before(Method method, Object[] args, Object target) throws Throwable;

三个参数:

  1. method:目标类的方法
  2. args:目标类传入的参数
  3. obj:目标类的对象

Spring的ProxyFactory

代理工厂(ProxyFactory)
Spring源码(org.springframework.aop.framework.AopProxy)中定义类这么个接口:

    public interface AopProxy {

    Object getProxy();

    Object getProxy(ClassLoader classLoader);

    }

它有两个实现类JdkDynamicAopProxy和CglibAopProxy,一个是使用JDK动态代理技术,一个是使用Cglib代理技术实现的。如果通过ProxyFactory的setInterfaces指定接口进行代理则使用JDK代理,如果针对类进行代理则使用CGLib技术


Spring中的配置

<bean id="ServeAdvice" class="com.spring.proxy.test.ServeAdviceBefpreAdvice">   
<bean id="target" class="com.spring.proxy.test.target">
<bean id="obj" class="org.springframework.aop.framework.ProxyFactoryBean"
        P:proxyinterfaces="com.spring.proxy.test.interface"//指定需要代理的接口
        P:interceptorNames="adviceMethod"//指定使用的增强方法
        p:target-ref="target"//指定对哪个Bean进行增强

其他属性:

  • target:代理的目标对象
  • proxyInterfaces:代理需要实现的接口
  • interceptorNames:需要植入目标对象的Bean列表,这些Bean必须实现了org.aopalliance.intercept.MethodInterceptor或org.springframework.aop.Advisor,配置中的顺序代表调用的顺序
  • singleton:返回来的对象是否为单例
  • optimeize:设置为true时,强制使用CGLib代理
  • proxyTargetClass:是否对类进行代理,设置为true时,使用CGLib代理

  1. 后置增强(org.springframework.aop.AfterReturningAdvice):表示在方法后增强。
    AfterReturningAdvice接口只定义了一个方法
    void afterReturning(Method method, Object[] args, Object target) throws Throwable;\
  2. 环绕增强(org.springframework.aop.MethodInterceptor):表示方法环绕增强(即在方法前后调用),
    Object invoke(MethidInvocation invocation) throws Throwable
  3. 异常抛出增强(org.springframework.aop.ThrowsAdvice) :表示异常抛出增强,ThrowsAdvice接口没有任何方法,它是一个标识接口,我们必须以

    void afterThrowing(Methid method,Onject[] args,Object target,Throwable);

    这么定义异常的抛出,方法名必须是afterThrowing,前两个参数可选要么都填,要么都不填,最后Throwable参数必须添加,并且是Throwable或它的子类。

  4. 引介增强(org.springframework.aop.support.DelegatingIntriductionInterceptor):它不是在目标方法周围织入增强,而是为目标类创建新的方法和属性,所以引介增强的连接点是类级别的,而非方法级别的,即即使目标类没有实现某个接口,同过引介增强可以为目标类创建实现某接口的代理。通过扩展DelegatingIntroductionInterceptor实现类来定义自己的引介增强类。

Spring的切面

如果我们想要有选择的织入到目标类的某些方法中,就需要使用切点进行连接点的定位。
Spring通过(org.springframework.Pointcut)接口描述切点,接口有两个方法:

ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();

ClassFilter中定义了一个方法:

boolean matches(Class<?> clazz);

clazz代表一个被检测类,这个方法判断是否匹配过滤条件。Spring支持两种匹配器,一种静态方法匹配器,运行期间只会匹配一次,根据方法的名称和入参的顺序匹配,一种动态方法匹配器。会在运行期间检查方法的值。每次调用方法都会匹配一次。

MethodMatcher isRuntime();

方法返回true,代表动态方法,返回false,代表静态方法。


切点类型

  1. 静态方法切点(org.springframework.aop.support.StaticMethodMatcherPointcut):默认匹配所有的类,有两个子类NameMethodPointcut:(简单的根据字符串进行匹配)和AbstractRegexpMethodPointcut(正则表达式进行匹配)
  2. 动态方法切点(org.springframework.aop.support.DynamicMethodMatcherPointcut):默认匹配所有类,
  3. 流程切点(org.springframework.aop.support.ControlFlowPointcut):它的实现类表示控制流程切点,
  4. 复合切点(org.springframework.aop.support.ComposablePointcut):它的实现类是为了创建多个切点的方便提供类

切面类型

Spring中,切面有三种:
1. Advisor:只代表一个切面,是个抽象的接口,代表切面的概念。
2. PointcutAdvisor:代表具有切点的切面,它包含两个类Advice和Pointcut
3. IntroductionAdvisor:代表引介切面,它是应用在类的层面上


静态方法切点Demo

public class WaiterImp implements Waiter{
public void greetTo(String name){
    System.out.println("Waiter greet to "+name+"....");
}
public void serveTo(String name){
    System.out.println("waiter serving to "+name+"....");
}
}


public class SellerImp implements Seller{
public void greetTo(String name){
    System.out.println("seller greet to "+name+"...");
}
}

//定义切面
public class GreetingAdvisor extends StaticMethodMatcherPointcutAdvisor{

private static final long serialVersionUID = 1L;
/* (non-Javadoc)
 * 
 * 匹配方法名称为serveTo的方法
 * @see org.springframework.aop.MethodMatcher#matches(java.lang.reflect.Method, java.lang.Class)
 */
public boolean matches(Method method, Class<?> targetClass) {
    return "serveTo".equals(method.getName());
}
public ClassFilter getClassFilter(){
    return new ClassFilter(){

        /* (non-Javadoc)
         * 
         * 类是Waiter的子类或实现类的匹配
         * 
         * @see org.springframework.aop.ClassFilter#matches(java.lang.Class)
         */
        public boolean matches(Class<?> clazz) {
            return Waiter.class.isAssignableFrom(clazz);
        }

    };


}

}


//定义增强
public class GreetBeforeAdvice implements MethodBeforeAdvice{

public void before(Method method, Object[] args, Object target) throws Throwable {
    System.out.println(target.getClass().getName()+"."+method.getName());
    String clientName=(String)args[0];
    System.out.println("How are you"+clientName+".");
}

}

beans.xml配置

<bean id="waiterTarget" class="com.spring.advisor.WaiterImp"/>
<bean id="sellerTarget" class="com.spring.advisor.SellerImp"/>
<bean id="greetingAdvice    class="com.spring.advisor.GreetBeforeAdvice" />
<bean id="greetingAdvisor"  class="com.spring.advisor.GreetingAdvisor" 
    p:advice-ref="greetingAdvice"/>
<bean id="parent" abstract="true" 
        class="org.springframework.aop.framework.ProxyFactoryBean"
        p:interceptorNames="greetingAdvisor"
        p:proxyTargetClass="true"/>
<bean id="waiter" parent="parent" p:target-ref="waiterTarget"/>
<bean id="seller" parent="parent" p:target-ref="sellerTarget"/>  

测试类Demo

public class Run {
    @Test
    public void RunTest(){
    ApplicationContext ctx =new ClassPathXmlApplicationContext("beans.xml");
    WaiterImp waiter =(WaiterImp) ctx.getBean("waiter");
    SellerImp seller =(SellerImp) ctx.getBean("seller");
    waiter.greetTo("seventeenWen");
    waiter.serveTo("seventeenWen");
    seller.greetTo("seventeenWen");
    }
}

结果:

Waiter greet to seventeenWen....
com.spring.advisor.WaiterImp.serveTo
How are youseventeenWen.
waiter serving to seventeenWen....
seller greet to seventeenWen...
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值