zoukankan      html  css  js  c++  java
  • Spring AOP使用整理:各种通知类型的介绍

         2、PersonImpl类的源码

    public class PersonImpl implements Person {
        private String name;
        private int age;
        
        public void setName(String name) {
            this.name = name;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public void info() {
            System.out.println("	我叫" + name + ",今年" + age + "岁。");
        }
    
        public void show(String message) {
            System.out.println(message);
        }
    }

        3、bean的配置

    <!-- 目标对象 -->
    <bean id="personTarget" class="com.cjm.aop.PersonImpl">
        <property name="name" value="Raymond.chen"/>
        <property name="age" value="30"/>
    </bean>

    二、Spring AOP支持的通知类型

         一)环绕通知(Around advice)

              实现环绕通知需要实现org.aopalliance.intercept.MethodInterceptor接口。

                   1、PersonAroundAdvice类的源码

    public class PersonAroundAdvice implements MethodInterceptor {
        public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("AroundAdvice:方法调用前");
            
            //不要忘记调用invocation的proceed方法哦
            Object result = invocation.proceed(); 
            
            System.out.println("AroundAdvice:方法调用后");
            return result;
        }
    }

                   2、bean配置

    <bean id="personAroundAdvice" class="com.cjm.aop.PersonAroundAdvice"/>
    
    <!-- 代理工厂bean -->
    <bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="proxyInterfaces" value="com.cjm.aop.Person"/>
        <property name="target" ref="personTarget"/>
        <property name="interceptorNames">
            <list>
                <value>personAroundAdvice</value>
            </list>
        </property>
    </bean>

                   3、测试代码

    ApplicationContext context = new FileSystemXmlApplicationContext("classpath:com/cjm/aop/beans.xml");
    Person p = (Person)context.getBean("person");  //注意这里是代理工厂Bean的ID
    p.info();

         二)前置通知(Before advice)

              实现前置通知需要实现org.springframework.aop.MethodBeforeAdvice接口。

                   1、PersonBeforeAdvice类的源码

    public class PersonBeforeAdvice implements MethodBeforeAdvice {
        public void before(Method method, Object[] args, Object target) throws Throwable {
            System.out.println("BeforeAdvice:方法调用前");
        }
    }

                   2、bean配置

    <bean id="personBeforeAdvice" class="com.cjm.aop.PersonBeforeAdvice"/>
    
    <bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="proxyInterfaces" value="com.cjm.aop.Person"/>
        <property name="target" ref="personTarget"/>
        <property name="interceptorNames">
            <list>
                <value>personBeforeAdvice</value>
            </list>
        </property>
    </bean>

         三)返回后通知(After Returning advice)

              实现返回后通知需要实现org.springframework.aop.AfterReturningAdvice接口。

                   1、PersonAfterReturningAdvice类的源码

    public class PersonAfterReturningAdvice implements AfterReturningAdvice {
        public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
            System.out.println("AfterReturningAdvice:方法调用后");
        }
    }

                   2、bean配置

    <bean id="personAfterReturningAdvice" class="com.cjm.aop.PersonAfterReturningAdvice"/>
    
    <bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="proxyInterfaces" value="com.cjm.aop.Person"/>
        <property name="target" ref="personTarget"/>
        <property name="interceptorNames">
            <list>
                <value>personAfterReturningAdvice</value>
            </list>
        </property>
    </bean>

                   3、以上的配置中,通知对目标对象的所有方法都会起作用。如果需要过滤掉一部分方法,可以用正则表达式切入点配置器或者方法名匹配切入点配置器实现。

    <!-- 通知与正则表达式切入点一起配置 -->
    <!-- Advisor等于切入点加通知 -->
    <!-- 方法名匹配切入点配置器:org.springframework.aop.support.NameMatchMethodPointcutAdvisor -->
    <bean id="personPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="advice" ref="personAfterReturningAdvice"/>
        <property name="patterns">
            <list>
                <value>.*info.*</value>
            </list>
        </property>
    </bean>
    
    <bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="proxyInterfaces" value="com.cjm.aop.Person"/>
        <property name="target" ref="personTarget"/>
        <property name="interceptorNames">
            <list>
                <value>personPointcutAdvisor</value>
            </list>
        </property>
    </bean>

         四)异常通知(Throws advice)

              当连接点抛出异常时,异常通知被调用。实现异常通知需要实现org.springframework.aop.ThrowsAdvice接口,该接口不包含任何方法,但在实现该接口时必须实现如下形式的方法:                  afterThrowing([Method], [args], [target], Throwable subclass)           可以实现一个或多个这样的方法。在这些方法中,只有第四个参数是必需的,前三个参数可选。

              1、PersonThrowsAdvice类的源码

    public class PersonThrowsAdvice implements ThrowsAdvice {
        public void afterThrowing(FileNotFoundException ex){
            System.out.println("ThrowsAdvice >> FileNotFoundException:" + ex.toString());
        }
    
        public void afterThrowing(Object[] args, Exception ex){
            System.out.println("ThrowsAdvice >> Exception:" + ex.getMessage());
        }
    
        public void afterThrowing(Method method, Object[] args, Object target, Throwable ex){
            System.out.println("ThrowsAdvice >> Throwable:" + ex.getMessage());
        }
    }

              2、bean配置

    <bean id="personThrowsAdvice" class="com.cjm.aop.PersonThrowsAdvice"/>
    
    <bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="proxyInterfaces" value="com.cjm.aop.Person"/>
        <property name="target" ref="personTarget"/>
        <property name="interceptorNames">
            <list>
                <value>personThrowsAdvice</value>
            </list>
        </property>
    </bean>

         五)引入通知(Introduction advice)

               引入通知是一种特殊的通知,它能将新的成员变量、成员方法引入到目标类中。它不能作用于任何切入点,因为它只作用于类层次,而不是方法层次。实现引入通知需要实现IntroductionAdvisor和IntroductionInterceptor接口。

               引入通知不能调用proceed方法。Advisor必须针对每个实例,并且是有状态的。

               引入通知的效果类似于设计模式中的访问者模式(Visitor Pattern)。

               1、Lockable接口的源码

    public interface Lockable {
        void lock();
        void unlock();
        boolean locked();
    }

               2、LockableImpl类的源码

    public class LockableImpl extends DelegatingIntroductionInterceptor implements Lockable {
        private boolean locked;
        
        public void lock() {
            this.locked = true;
        }
    
        public void unlock() {
            this.locked = false;
        }
    
        public boolean locked() {
            return this.locked;
        }
    
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            if(this.locked){
                throw new RuntimeException("加锁,无法执行");
            }
            
            //这里不能调用invocation的proceed方法
            //通常不需要改写invoke方法,直接调用父类的该方法即可
            return super.invoke(invocation);
        }
    }

               3、PersonIntroductionAdvice类的源码

    public class PersonIntroductionAdvice extends DefaultIntroductionAdvisor {
        public PersonIntroductionAdvice(){
            super(new LockableImpl(), Lockable.class);
        }
    }

               4、bean配置

    <!-- Advice必须针对每个实例,所以scope要设为prototype -->
    <bean id="personIntroductionAdvice" class="com.cjm.aop.introduction.PersonIntroductionAdvice" scope="prototype"/>
    
    <bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="proxyInterfaces" value="com.cjm.aop.Person"/>
        <property name="target" ref="personTarget"/>
        <property name="interceptorNames">
            <list>
                <value>personIntroductionAdvice</value>
            </list>
        </property>
    </bean>

               5、测试代码

    ApplicationContext context = new FileSystemXmlApplicationContext("classpath:com/cjm/aop/beans.xml");
    
    //获得目标bean的代理bean
    Person p = (Person)context.getBean("person");
    
    //执行代理bean的方法,此时并未调用lock方法,可以执行
    p.info();
    
    Lockable lockable = (Lockable)p;
    lockable.lock();
    
    //目标bean已被锁定,此处将抛出异常
    p.info();
  • 相关阅读:
    【SQL】语句/函数汇总
    【SVN】提交报错:×××文件is not under version control
    【AnjularJS系列1】样式相关的指令
    【Javescript】DOM(文档对象模型)
    【HTML】框架集(Framesets)
    【HTML】<!DOCTYPE html>作用
    vue2.0移动端自定义性别选择提示框
    微信小程序踩坑记
    网页里如何使用js禁用F12事件
    网页里如何使用js屏蔽鼠标右击事件
  • 原文地址:https://www.cnblogs.com/damowang/p/4305148.html
Copyright © 2011-2022 走看看