那些年我们一起着迷的Spring:Introduction和advisor(十一)

转载:Spring入门(Schema-based AOP其四)

Introduction

简介允许切面声明一个实现指定接口的通知对象,并且提供了一个接口实现类来表达这些对象
<aop:aspect>中的<aop:declare-parents>元素声明。该元素用于声明所匹配的类型拥有一个新的parent(因此得名)

<aop:aspect id="usageTrackerAspect" ref="usageTracking">

    <aop:declare-parents
    	<!--匹配什么样的类型-->
        type-matching="com.xyz.myapp.service.*+" 
        <!--具体使用哪一个接口-->
        implement-interface="com.xyz.myapp.service.tracking.UsageTracked" 
		 <!--指定接口实现类 -->
        default-impl="com.xyz.myapp.service.tracking.DefaultUsageTracked"/>

    <aop:before 
        pointcut="com.xyz.myapp.SystemArchitecture.businessService() and this(usageTracked)"
        method="recordUsage"/>

</aop:aspect>
public void recordUsage(UsageTracked usageTracked){
    
    
    usageTracked.incrementUseCount();
}

这是一个方法,方法里边输入是一个接口,然后调用这个接口的incrementUseCount方法,增加被调用的次数。

  UsageTracked usageTracked=(UsageTracked)context.getBean("myService");

matching匹配到的是myService这个类,也就是bean的id是myService,但是我们getBean之后会把它强制转为这个接口,为什么能够这么转?因为刚才有说到,<aop:declare-parents>会用于声明所有匹配的类型拥有一个新的parent,也就是说,当前这个declare-parents匹配到了myService这个类,所以它会给myService这个bean对应的类指定一个新的parent,也就是implement-interface里边指定的UsageTracked,所以这里可以做这种强制类型转化。

示例

//com.imooc.aop.schema.advice包下
public interface Fit {
    
    
    void filter();
}

public class FitImpl implements Fit {
    
    
    @Override
    public void filter() {
    
    
        System.out.println("FitImpl filter.");
    }
}

<aop:config>
    <aop:aspect id="moocAspectAOP" ref="moocAspect">
    <!--types-matching匹配的是com.imooc.aop.schema.advice.biz这个包下的所有方法。-->
            <aop:declare-parents 
            		types-matching="com.imooc.aop.schema.advice.biz.*(+)" 
                    implement-interface="com.imooc.aop.schema.advice.Fit"
                    default-impl="com.imooc.aop.schema.advice.FitImpl"/>
    </aop:aspect>
</aop:config>
@Test
public void testFit() {
    
    
    Fit fit = (Fit)super.getBean("aspectBiz");
    fit.filter();
}
//输出FitImpl filter.

也就是说Fit接口的实现类FitImpl已经被调用,types-matching匹配到AspectBiz这个类,为它指定了一个新的父类Fit,它的实现FitImpl。

advisor

advisor就像一个小的自包含的方面,只有一个advice
切面自身通过一个bean表示,并且必须实现某个advice接口,同时,advisor也可以很好的利用AspectJ的切入点表达式 。
Spring通过配置文件中<aop:advisor>元素支持advisor。
实际使用中,大多数情况下它会和transactional advice配合使用(也就是使用时,会和与事务相关的advice使用) 为了定义一个advisor的优先级以便让advice可以有序,可以使用order属性来定义advisor的顺序

<aop:config>
    <aop:pointcut id="businessService" 
        expression="execution(*com.xyz.myapp.service..(..))"/>

    <aop:advisor 
        pointcut-ref="businessService"
        advice-ref="tx-advice"/>
</aop:config>

<tx:advice id="tx-advice">
    <tx:attributes>
        <tx:method name="*" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>

tx:advice是一个关于事务的相关的声明。

<context:component-scan base-package="com.imooc.aop.schema"></context:component-scan>

    <aop:config>
        <aop:aspect id="concurrentOperationRetry" ref="concurrentOperationExecutor">
            <aop:pointcut id="idempotentOperation"
                expression="execution(* com.imooc.aop.schema.advisors.service.*.*(..)) " />
<!--                expression="execution(* com.imooc.aop.schema.service.*.*(..)) and -->
<!--                                @annotation(com.imooc.aop.schema.Idempotent)" /> -->
            <aop:around pointcut-ref="idempotentOperation" method="doConcurrentOperation" />
        </aop:aspect>
    </aop:config>

    <bean id="concurrentOperationExecutor" class="com.imooc.aop.schema.advisors.ConcurrentOperationExecutor">
        <property name="maxRetries" value="3" />
        <property name="order" value="100" />
    </bean>

context:component-scan是一个自动的扫描,扫描包下面的配置
然后看一下bean对应的类ConcurrentOperationExecutor,这个类作为一个切面来使用

public class ConcurrentOperationExecutor implements Ordered {
    
    

    private static final int DEFAULT_MAX_RETRIES = 2;
    private int maxRetries = DEFAULT_MAX_RETRIES;   
    private int order = 1;
    public void setMaxRetries(int maxRetries) {
    
    
        this.maxRetries = maxRetries;
    }

    public int getOrder() {
    
    
        return this.order;
    }

    public void setOrder(int order) {
    
    
        this.order = order;
    }
	//对应切面中的环绕通知方法
    public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
    
    
        int numAttempts = 0;
        PessimisticLockingFailureException lockFailureException;
        do {
    
    
            numAttempts++;
            System.out.println("Try times : " + numAttempts);
            try {
    
    
                return pjp.proceed();
            } catch (PessimisticLockingFailureException ex) {
    
    
                lockFailureException = ex;
            }
        } while (numAttempts <= this.maxRetries);
        System.out.println("Try error : " + numAttempts);
        throw lockFailureException;
    }
}

匹配到的类是InvokeService

@Service
public class InvokeService {
    
    

    public void invoke() {
    
    
        System.out.println("InvokeService ......");
    }

    public void invokeException() {
    
    
        throw new PessimisticLockingFailureException("");
    }
}

这个类里边有两个方法,invoke是可以正常调用。invokeException每一次调用都会抛出异常,所以每次执行都会失败,超过最大执行次数会抛出lockFailureException并打印。

单元测试方法

    @Test
    public void testSave() {
    
    
        InvokeService service = super.getBean("invokeService");
        service.invoke();

        System.out.println();
        service.invokeException();
    }

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/eluanshi12/article/details/97003179
今日推荐