• 21_AOP_Advice增强2(异常、引介)


    【异常抛出增强】

    异常抛出异常最适合的应用场景:事务管理。

    当参与事务的某个Dao发生异常时,事务管理器就必须回滚事务。

    【异常抛出增强 例子】

    【操作数据库的Dao类:PersonDao.java】

    package com.Higgin.part2;
    
    import java.sql.SQLException;
    /**
     * 模拟操作数据库并发生异常
     */
    public class PersonDao {
        //查询所有Person
        public void getAllPerson(){
            throw new RuntimeException("运行时异常...");
        }
        
        //删除所有Person
        public void deleteAllPerson() throws Exception{
            throw new SQLException("删除数据异常...");
        }
    }

    【抛出异常增强(事务管理器):TransactionManager.java】

    package com.Higgin.part2;
    
    import java.lang.reflect.Method;
    
    import org.springframework.aop.ThrowsAdvice;
    
    /**
     * 抛出异常增强:事务管理器
     * 实现的接口:ThrowsAdvice   
     * ThrowsAdvice异常抛出接口没有定义任何方法,是一个标识接口,在运行期间Spring使用反射机制自行判断
     */
    public class TransactionManager implements ThrowsAdvice{
    
        /**
         * 我们必须使用 void afterThrowing(...)方法
         * 方法名:必须为afterThrowing
         * 方法入参:前三个入参Method method,Object[] args,Object target可选(要么三个都提供,要么都不提供),
         *               最后一个入参是Throwable或其子类(这里用了子类Exception)
         *  合法的例子:afterThrowing(SQLException ex)
         *            afterThrowing(RuntimeException ex)
         *            afterThrowing(Method method,Object[] args,Object target,RuntimeException ex)
         */
        public void afterThrowing(Method method,Object[] args,Object target,Exception ex){
            System.out.println("------抛出异常增强------");
            System.out.println("method Name=="+method.getName());
            System.out.println("获取抛出异常的信息:"+ex.getMessage());
            System.out.println("成功滚回事务");
        }
    }

    【Spring配置的文件:part2.xml】

    <?xml version="1.0" encoding="UTF-8"?>  
    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"  
        xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xmlns:jdbc="http://www.springframework.org/schema/jdbc"  
        xmlns:cache="http://www.springframework.org/schema/cache"  
        xsi:schemaLocation="  
        http://www.springframework.org/schema/context  
        http://www.springframework.org/schema/context/spring-context.xsd  
        http://www.springframework.org/schema/beans  
        http://www.springframework.org/schema/beans/spring-beans.xsd  
        http://www.springframework.org/schema/tx  
        http://www.springframework.org/schema/tx/spring-tx.xsd  
        http://www.springframework.org/schema/jdbc  
        http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd  
        http://www.springframework.org/schema/cache  
        http://www.springframework.org/schema/cache/spring-cache-3.1.xsd  
        http://www.springframework.org/schema/aop  
        http://www.springframework.org/schema/aop/spring-aop.xsd  
        http://www.springframework.org/schema/util  
        http://www.springframework.org/schema/util/spring-util.xsd">
        
        <!-- 要增强的目标对象 -->
        <bean id="target" class="com.Higgin.part2.PersonDao"/>
    
        <!-- 抛出异常的增强  -->
        <bean id="transactionManager" class="com.Higgin.part2.TransactionManager"/>
        
        <!-- Spring代理工厂的成员变量配置(注意这里没有p:proxyInterfaces接口属性配置)-->
        <bean id="personDao" class="org.springframework.aop.framework.ProxyFactoryBean"
            p:interceptorNames="transactionManager"
            p:target-ref="target"
            p:proxyTargetClass="true"
        />
        
    </beans>

    【测试类:TestTransactionManager.java】

    package com.Higgin.part2.Test;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import com.Higgin.part2.PersonDao;
    
    public class TestTransactionManager {
        public static void main(String[] args) throws Exception {
            ApplicationContext context=new ClassPathXmlApplicationContext("part2.xml");
            PersonDao personDao=(PersonDao) context.getBean("personDao");
            
            //分别执行下面两条
            personDao.deleteAllPerson();
            personDao.getAllPerson();
        }
    }

    【运行personDao.deleteAllPerson() 结果】

    【运行personDao.getAllPerson() 结果】

     【分析】

    关于标识接口(比如ThrowsAdvice抛出异常增强接口)

      标识接口是没有任何方法和属性的接口。标识接口不对实现者有任何语义上的要求,仅仅表明它的实现类是属于一个特定的类型。JAVA使用标识接口来标识某一类对象,第一,通过标识接口标识同一类型的类,这些类本身可能并没有具有相同的方法。第二,通过标识接口是程序或JVM采取一些特殊处理,如java.io.Serilizable,告诉JVM对象可以被序列化。

    【引介增强】

      引介增强是一种特殊的增强,他不是在在目标方法周围织入增强,而是为目标方法创创建新的方法和属性,所以引介增强的连接点是类级别的,而非方法级别的。通过引介增强,我们可以为目标类添加一个接口的实现(即原来目标类未实现某个接口,通过引介增强可以为目标类创建实现某接口的代理)。

      Spring定义了引介增强接口IntroductionInterceptor,该接口没有定义任何方法,Spring为该接口提供DelegatingIntroductionInterceptor实现类,一般我们通过实现该类定义自己的引介增强类。

    【引介增强 例子】

     【模拟数据库操作 PersonDao.java】

    package com.Higgin.part3;
    
    /**
     * 模拟数据库操作类
     */
    public class PersonDao {
        public void getAllPerson(){
            System.out.println("查询数据库得到所有Person...");
        }
    }

    【模拟性能监视类 PersonDaoMonitor.java】

    package com.Higgin.part3;
    
    /**
     * 模拟性能检测类
     */
    public class PersonDaoMonitor {
        public static void begin(){
            System.out.println("【操作数据库前】开始监测...");
        }
        
        public static void end(){
            System.out.println("【操作数据库后】结束检测,得到检测数据...");
        }
    }

    【标识目标类是否支持性能监视的接口 Monitor.java】

    package com.Higgin.part3;
    /**
     * 标识目标类是否支持性能监视的接口
     */
    public interface Monitor {
        /**
         * 控制业务方法的性能监视功能 激活 or 关闭
         */
        public void setMonitorActive(boolean active); 
    }

    【为目标类引入性能可控功能 ControllerPersonDaoMonitor.java】

    package com.Higgin.part3;
    
    import org.aopalliance.intercept.MethodInvocation;
    import org.springframework.aop.support.DelegatingIntroductionInterceptor;
    
    
    /**
     * ControllerPersonDaoMonitor类
     * 为目标类引入性能可控功能
     * 
     */
    public class ControllerPersonDaoMonitor extends DelegatingIntroductionInterceptor
                        implements Monitor{
        /**
         * ThreadLocal类型的成员变量 monitorStatusMap,用于保存性能监视开关状态
         */
        private ThreadLocal<Boolean> monitorStatusMap =new ThreadLocal<>();
        
        @Override
        public void setMonitorActive(boolean active) {
            monitorStatusMap.set(active);
        }
        
        /**
         * 拦截方法
         */
        public Object invoke(MethodInvocation mi)throws Throwable{
            Object obj=null;
            //对于支持性能监视可控代理,通过判断其状态来决定是否开启性能监视
            if(monitorStatusMap.get()!=null&&monitorStatusMap.get()){
                PersonDaoMonitor.begin();   //调用PersonDaoMonitor的性能检测方法
                obj=super.invoke(mi);
                PersonDaoMonitor.end();     //调用PersonDaoMonitor的性能检测方法
            }else{
                obj=super.invoke(mi);
            }
            return obj;
        }
    
    }

    【Spring的xml配置方法 part3.xml】

    <?xml version="1.0" encoding="UTF-8"?>  
    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"  
        xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xmlns:jdbc="http://www.springframework.org/schema/jdbc"  
        xmlns:cache="http://www.springframework.org/schema/cache"  
        xsi:schemaLocation="  
        http://www.springframework.org/schema/context  
        http://www.springframework.org/schema/context/spring-context.xsd  
        http://www.springframework.org/schema/beans  
        http://www.springframework.org/schema/beans/spring-beans.xsd  
        http://www.springframework.org/schema/tx  
        http://www.springframework.org/schema/tx/spring-tx.xsd  
        http://www.springframework.org/schema/jdbc  
        http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd  
        http://www.springframework.org/schema/cache  
        http://www.springframework.org/schema/cache/spring-cache-3.1.xsd  
        http://www.springframework.org/schema/aop  
        http://www.springframework.org/schema/aop/spring-aop.xsd  
        http://www.springframework.org/schema/util  
        http://www.springframework.org/schema/util/spring-util.xsd">
        
        <!-- 要增强的目标对象 -->
        <bean id="target" class="com.Higgin.part3.PersonDao"/>
    
        <!-- 引介增强类  -->
        <bean id="cpMonitor" class="com.Higgin.part3.ControllerPersonDaoMonitor"/>
        
        <!-- Spring代理工厂的成员变量配置 (引介增强实现了Monitor接口)-->
        <bean id="personDao" class="org.springframework.aop.framework.ProxyFactoryBean"
            p:proxyInterfaces="com.Higgin.part3.Monitor" 
            p:interceptorNames="cpMonitor"
            p:target-ref="target"
            p:proxyTargetClass="true"
        />
        
    </beans>

    【测试类 TestControllerPersonDaoMonitor.java】

    package com.Higgin.part3.Test;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import com.Higgin.part3.Monitor;
    import com.Higgin.part3.PersonDao;
    
    public class TestControllerPersonDaoMonitor {
        public static void main(String[] args) {
            ApplicationContext context=new ClassPathXmlApplicationContext("part3.xml");
            PersonDao personDao=(PersonDao) context.getBean("personDao");
            //默认关闭性能检测
            personDao.getAllPerson();
            
            System.out.println("===============================");
            
            //开启性能检测功能
            Monitor mp=(Monitor) personDao;
            mp.setMonitorActive(true);
            
            //再次调用业务方法
            personDao.getAllPerson();
            
        }
    }    

    【运行结果】

     【分析】

    引介增强的配置与一般的配置有较大的区别:

    1.需要指定引介增强需要实现的接口Monitor

    2.由于只能通过为目标类创建子类的方式生成引介增强的代理,所以讲proxyTargetClass设置为true

  • 相关阅读:
    递归程序设计方法
    深入理解 Entity Framework
    面向对象设计的七大原则分析与实践
    JavaScript内置对象与原型继承
    设计模式之创建型(1)-简单工厂
    设计模式之创建型(2)-工厂方法模式
    设计模式之创建型(3)-抽象工厂模式
    设计模式之创建型(4)-建造者模式(Builder)
    设计模式之创建型(5)-单例模式(Singleton)
    设计模式之创建型(6)-原型模式(Prototype)
  • 原文地址:https://www.cnblogs.com/HigginCui/p/6322283.html
Copyright © 2020-2023  润新知