Spring实战教程 | 第十二篇:用Spring AOP实现异常处理和记录程序执行时间

这个实例用于一个系统的所以方法执行过程中出现异常时,把异常信息都记录下来,还有记录每个方法的执行时间,这两个业务逻辑首先使用SpringAOP的自动代理功能,然后一个用Java的动态代理,一个用CGLIB代理

用Spring AOP的自动代理实现

(1)定义负责异常处理的Advice为ExceptionHandler.java ,负责当程序执行过程中出现异常,把异常信息记录下来

public class ExceptionHandler implements ThrowsAdvice{
    private Logger logger=Logger.getLogger(this.getClass().getName());
    //重写afterThrowing()方法
    public void afterThrowing(Method m,Object[] args,Object target,
            Throwable subclass)
    {
        logger.log(Level.INFO,args[0]+" 执行 "+m.getName()+" 时有异常抛出..."+subclass);
    }
}

(2)定义负责记录执行时间的Advice为TimeHandler.java
使用Spring提供的Around通知实现该功能

/*
 * 负责记录每个方法的执行时间
 * 因为使用的是环绕通知,所以要实现接口MethodInterceptor
 */
public class TimeHandler implements MethodInterceptor {
    private Logger logger = Logger.getLogger(this.getClass().getName());

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        //获取初始时间
        long procTime = System.currentTimeMillis();
        logger.log(Level.INFO, invocation.getArguments()[0] + " 开始执行 "
                + invocation.getMethod() + " 方法");
        try {
            Object result=invocation.proceed();
            return result;
        } finally {
            // 计算执行时间
            procTime=System.currentTimeMillis()-procTime;
            logger.log(Level.INFO, invocation.getArguments()[0] + " 执行 "
                    + invocation.getMethod() + " 方法结束");
            logger.log(Level.INFO, " 执行 "+invocation.getMethod().getName()+
                    " 方法共用了 "+procTime+" 毫秒");
        }
    }
}

(3)定义业务逻辑接口LogicInterface.java

/*
 *    共定义3个方法,新增、修改和删除
 */
public interface LogicInterface {
    public void doInsert(String name);
    public void doUpdate(String name);
    public void doDelete(String name);
}

(4)实现业务逻辑接口的类Logic1.java

public class Logic1 implements LogicInterface {

    @Override
    //负责新增
    public void doInsert(String name) {
        System.out.println("执行具体负责新增的业务逻辑...");
        for(int i=0;i<10000000;i++)
        {
            //模拟执行时间
        }   
    }

    @Override
    //负责修改
    public void doUpdate(String name) {
        System.out.println("执行具体负责修改的业务逻辑...");
        for(int i=0;i<20000000;i++)
        {
            //模拟执行时间
        }   
    }
    @Override
    //负责删除
    public void doDelete(String name) {
        System.out.println("执行具体负责删除的业务逻辑...");
        for(int i=0;i<20000000;i++)
        {
              //模拟异常发生
            i=i/0;
        }   
    }
}

不实现业务逻辑接口的类Logic2.java

public class Logic2 {
    //负责新增
    public void doInsert(String name) {
        System.out.println("执行具体负责新增的业务逻辑...");
        for(int i=0;i<10000000;i++)
        {
            //模拟执行时间
        }

    }
    //负责修改
    public void doUpdate(String name) {
        System.out.println("执行具体负责修改的业务逻辑...");
        for(int i=0;i<20000000;i++)
        {
            //模拟执行时间
        }
    }

    //负责删除
    public void doDelete(String name) {
        System.out.println("执行具体负责删除的业务逻辑...");
        for(int i=0;i<20000000;i++)
        {
            i=i/0;
        }
    }
}

(5)自动代理配置文档

    <bean id="logic1" class="aop.action.Logic1"></bean>
    <bean id="logic2" class="aop.action.Logic2"></bean>

    <!-- 设定为自动代理 -->
    <bean id="autoProxyCreator"
        class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>

    <!-- 负责记录有异常发生时的信息 -->
    <bean id="exceptionHandler" class="aop.action.ExceptionHandler"></bean>

    <bean id="exceptionHandlerAdvisor"
        class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="advice">
            <ref bean="exceptionHandler" />
        </property>
        <!-- 对指定类的任何方法有效 -->
        <property name="patterns">
            <value>.*.*</value>
        </property>
    </bean>

    <!-- 负责记录方法的记录时间 -->
    <bean id="timeHandler" class="aop.action.TimeHandler"></bean>

    <bean id="timeHandlerAdvisor"
        class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="advice">
            <ref bean="timeHandler" />
        </property>
        <!-- 对指定类的任何方法有效 -->
        <property name="patterns">
            <value>.*.*</value>
        </property>
    </bean>

(6)测试Logic1

public class TestAop {
    public static void main(String[] args) {
        ApplicationContext context = new FileSystemXmlApplicationContext(
                "classpath:exception-config.xml");
        LogicInterface logic = (LogicInterface) context.getBean("logic1");
        // 模拟执行新增、修改、删除方法
        try {
            logic.doInsert("张三");
            logic.doUpdate("李四");
            logic.doDelete("王五");

        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

运行结果
这里写图片描述
测试Logic2

Logic2 logic = (Logic2) context.getBean("logic2");

运行结果同上


用Spring AOP的动态代理和CGLIB代理实现

主要修改配置文件,去掉前面的自动代理,使用ProxyFactoryBean代理定义,Logic1只记录程序执行时间,
Logic2只负责捕获异常

    <bean id="logic1" class="aop.action.Logic1"></bean>
    <bean id="logic2" class="aop.action.Logic2"></bean>

    <!-- 设定为自动代理 -->
    <!-- <bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean> -->

    <!-- 负责记录有异常发生时的信息 -->
    <bean id="exceptionHandler" class="aop.action.ExceptionHandler"></bean>

    <bean id="exceptionHandlerAdvisor"
        class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="advice">
            <ref bean="exceptionHandler" />
        </property>
        <!-- 对指定类的任何方法有效 -->
        <property name="patterns">
            <value>.*.*</value>
        </property>
    </bean>

    <!-- 负责记录方法的记录时间 -->
    <bean id="timeHandler" class="aop.action.TimeHandler"></bean>

    <bean id="timeHandlerAdvisor"
        class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="advice">
            <ref bean="timeHandler" />
        </property>
        <!-- 对指定类的任何方法有效 -->
        <property name="patterns">
            <value>.*.*</value>
        </property>
    </bean>

    <!-- 配置Logic1只负责记录执行时间 -->
    <bean id="logic1Proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!-- 动态代理,实现接口 -->
      <property name="proxyInterfaces">
        <value>aop.action.LogicInterface</value>
      </property>
      <property name="target">
         <ref bean="logic1"/>
      </property>
      <!-- 指定代理类 -->
      <property name="interceptorNames">
        <list>
          <value>timeHandlerAdvisor</value>
        </list>
      </property>
    </bean>

    <!-- 配置Logic只负责获取异常信息 -->
    <bean id="logic2Proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
      <!-- CGLIB代理,不用实现接口 -->
      <property name="proxyTargetClass">
        <value>true</value>
      </property>
      <property name="target">
         <ref bean="logic2"/>
      </property>
      <!-- 指定代理类 -->
      <property name="interceptorNames">
        <list>
          <value>exceptionHandlerAdvisor</value>
        </list>
      </property>
    </bean>

Logic1的测试类,使用的是Java的动态代理

public class TestAop {
    public static void main(String[] args) {
        ApplicationContext context = new FileSystemXmlApplicationContext(
                "classpath:exception-config.xml");
        LogicInterface logic = (LogicInterface) context.getBean("logic1Proxy");
        // 模拟执行新增、修改、删除方法
        try {
            logic.doInsert("张三");
            logic.doUpdate("李四");
            logic.doDelete("王五");

        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

这里写图片描述
运行结果只记录程序执行时间
Logic2的测试类,使用的是CGLIB的动态代理

public class TestAop {
    public static void main(String[] args) {
        ApplicationContext context = new FileSystemXmlApplicationContext(
                "classpath:exception-config.xml");
        Logic2 logic = (Logic2) context.getBean("logic2Proxy");
        // 模拟执行新增、修改、删除方法
        try {
            logic.doInsert("张三");
            logic.doUpdate("李四");
            logic.doDelete("王五");

        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

这里写图片描述
运行结果只记录异常信息


小结

AOP编程的实质就是,业务逻辑不再实现横切关注点,而是由单独的类来封装,当业务逻辑需要用到封装的横切关注点,AOP会自动把封装的横切关注点插入到具体的业务逻辑中

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值