课程链接:

1    简析

1.1  advisor简析

2    代码演练

2.1  类似顾问通知实现:(代码演练中没有用到顾问标签)

 

 

 

 

 

1    简析

顾问:在通知的基础之上,在细化我们的aop切面!


通知和顾问都是切面的实现方式!
通知是顾问的一个属性!

顾问会通过我们的设置,将不同的通知,在不通过的时间点,把切面
织入到不同的切入点!

PointCutAdvisor接口!
比较常用的两个实现类:
NameMatchMethodPointcutAdvisor :根据切入点(主业务方法)名称织入切面!
RegexpMethodPointcutAdvisor :根据自定义的正则表达式织入切面!

正则表达式中常用的三个运算符
.   任意单个字符
+   表示字符出现一次或者多次
*   表示字符出现0次或者多次

1.1  advisor简析(更加灵活的配置切面,详细的可以参见2.1)

Advisor是Pointcut和Advice的配置器,它包括PointcutAdvice,是将Advice注入程序中Pointcut位置的代码

<aop:aspectj-autoproxy/>
   <aop:config proxy-target-class="true">
       <aop:pointcut id="servicePointcut"
                     expression="execution(* com.cpic..*Service.*(..))" />
       <aop:advisor pointcut-ref="servicePointcut" advice-ref="txAdvice"
                    order="3" />
   </aop:config>
   <tx:advice id="txAdvice" transaction-manager="transactionManager">
       <tx:attributes>
           <tx:method name="add*" />
           <tx:method name="insert*" />
           <tx:method name="remove*" />
           <tx:method name="save*" />
           <tx:method name="update*" />
           <tx:method name="delete*" />
           <tx:method name="cancel*" />
           <tx:method name="trans*" />
           <tx:method name="commit*" />
           <tx:method name="submit*" />
           <tx:method name="issue*" />
           <tx:method name="accept*" />
           <tx:method name="underwrite*" />
           <tx:method name="modify*" />
           <tx:method name="calculate*" />
           <tx:method name="copy*" />
           <tx:method name="print*" />
           <tx:method name="create*" />
           <tx:method name="send*" />
           <tx:method name="activate*" />
           <tx:method name="generate*" /> 
           <tx:method name="do*" />
           <tx:method name="find*" read-only="true" />
           <tx:method name="get*" read-only="true" />
           <tx:method name="load*" read-only="true" />
           <tx:method name="list*" read-only="true" />
           <!-- log方法会启动一个新事务 -->
           <tx:method name="log*" propagation="REQUIRES_NEW"
                      isolation="READ_COMMITTED" />
           <!-- 如果通过java代码来进行分库判断,这里exeNewTS方法需要启动一个新事务 ,切换数据源时使用-->
           <tx:method name="exeNewTS*" propagation="REQUIRES_NEW"
                      isolation="READ_COMMITTED" />
          <!--  <tx:method name="exeNewTS*"/> -->
       </tx:attributes>
   </tx:advice>

 

2    代码演练

2.1  类似顾问通知实现:(代码演练中没有用到顾问标签)

测试类:

package com.imooc.test.aop;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.BlockJUnit4ClassRunner;

import com.imooc.aop.schema.advisors.service.InvokeService;
import com.imooc.test.base.UnitTestBase;

@RunWith(BlockJUnit4ClassRunner.class)
public class TestAOPSchemaAdvisors extends UnitTestBase {
    
    public TestAOPSchemaAdvisors() {
        super("classpath:spring-aop-schema-advisors.xml");
    }
    
        

    @Test
    /**
     * 1    这里问题的关键:在 ConcurrentOperationExecutor.java类中的try方法中
     *         把正常的方法service.invoke() 和出现异常的方法service.invokeException() 进行对比
     * 
     * 2    从xml传值    <property name="maxRetries" value="3"/>
     */
    public void testSave(){
        InvokeService service  = super.getbean("invokeService");
        service.invoke();
        
        System.out.println("===================================================================================================================");
        service.invokeException();
    }
}

 

配置类:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop" 
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
 >


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

<!-- 配置aop -->
<aop:config>
    <aop:aspect id="concurrentOperationRetry" ref="concurrentOperationExecutor">
        <!-- 注意:此处有小空格 -->

      <aop:pointcut id="idempotentOperation" 

        expression="execution(* com.imooc.aop.schema.advisors.service.*.*(..)) " />

     <aop:around pointcut-ref="idempotentOperation" method="doConcurrentOperation"/>

    </aop:aspect>
</aop:config>




<!-- 配置bean类 ,当下类作为通知类存在-->
<bean id="concurrentOperationExecutor" class="com.imooc.aop.schema.advisors.ConcurrentOperationExecutor">

    <property name="maxRetries" value="3"/>

    <property name="order" value="100"/>
</bean>

</beans>

 

实体类:

package com.imooc.aop.schema.advisors.service;

import org.springframework.dao.PessimisticLockingFailureException;
import org.springframework.stereotype.Service;

@Service
public class InvokeService {
    
    public void invoke() {
        System.out.println("Invoke Service ....");
    }
    
    public void invokeException(){
        throw new PessimisticLockingFailureException("");
    }

}

 

通知类:

package com.imooc.aop.schema.advisors;

import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.core.Ordered;
import org.springframework.dao.PessimisticLockingFailureException;

public class ConcurrentOperationExecutor implements Ordered{

    private static final int DEFAULT_MAX_RETRIES = 2;
    
    private int maxRetries = DEFAULT_MAX_RETRIES;
    
    private int order = 1;

    public int getMaxRetries() {
        return maxRetries;
    }

    public void setMaxRetries(int maxRetries) {
        this.maxRetries = maxRetries;
    }

    public int getOrder() {
        return order;
    }

    public void setOrder(int order) {
        this.order = order;
    }
    
    /**
     * 通知对应的方法
     * @param pjp
     * @return
     * @throws Throwable 
     */
    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 e) {
                lockFailureException = e;
            }
        } while (numAttempts<=this.maxRetries);//次数递增,当小于常量(xml传入的次数)时
        System.out.println("Try error:"+numAttempts);
        return lockFailureException;
        
    }
    
    
    
}

 

打印日志:

四月 20, 2019 3:01:36 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@45a5049a: startup date [Sat Apr 20 15:01:36 CST 2019]; root of context hierarchy
四月 20, 2019 3:01:36 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [spring-aop-schema-advisors.xml]
四月 20, 2019 3:01:36 下午 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor <init>
信息: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
Try Times : 1
Invoke Service ....
===================================================================================================================
Try Times : 1
Try Times : 2
Try Times : 3
Try Times :4
Try error:4
四月 20, 2019 3:01:37 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose
信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@45a5049a: startup date [Sat Apr 20 15:01:36 CST 2019]; root of context hierarchy

 

posted on 2019-04-20 10:30  菜鸟乙  阅读(347)  评论(0编辑  收藏  举报