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("\t我叫" + 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();
时间: 2024-11-15 14:55:58

Spring AOP使用整理:各种通知类型的介绍的相关文章

spring aop的五种通知类型

昨天在腾讯课堂看springboot的视频,老师随口提问,尼玛竟然回答错了.特此记录! 问题: Spring web项目如果程序启动时出现异常,调用的是aop中哪类通知? 正确答案是: 异常返回通知. 回答问题的关键是,你得知道aop有哪几种通知类型吧! spring aop通知(advice)分成五类: 前置通知[Before advice]: 在连接点前面执行,前置通知不会影响连接点的执行,除非此处抛出异常. 正常返回通知[After returning advice]: 在连接点正常执行完

7.Spring切入点的表达式和通知类型

1.切入点的表达式 表达式格式: execution([修饰符] 返回值类型 包名.类名.方法名(参数)) 其他的代替: <!-- 完全指定一个方法 --> <!-- <aop:before method="log" pointcut="execution(public void com.spring.demo1.UserServiceImpl.save())"/> --> <!-- 修饰符可以不写,不是必要出现的 --&g

Spring AOP那些学术概念—通知、增强处理连接点(JoinPoint)切面(Aspect)

1.我所知道的AOP 初看起来,上来就是一大堆的术语,而且还有个拉风的名字,面向切面编程,都说是OOP的一种有益补充等等.一下让你不知所措,心想着:管不得很多人都和我说AOP多难多难.当我看进去以后,我才行发现:他就是一些Java基础上的朴实无华的应用,包括IOC(见<Spring IOC(依赖注入.控制反转)概念理解>),包括许许多多这样的名词,都是万变不离其宗而已. 2.为什么要用AOP 1)就是为了方便,看一个国外很有名的大师说,编程的人都是“懒人”,因为他把自己做的事情都让程序去做了.

Spring AOP使用整理:使用@AspectJ风格的切面声明

要启用基于@AspectJ风格的切面声明,需要进行以下的配置: <!-- 启用@AspectJ风格的切面声明 --> <aop:aspectj-autoproxy proxy-target-class="true"/> <!-- 通过注解定义bean.默认同时也通过注解自动注入 --> <context:component-scan base-package="com.cjm"/> 基于@AspectJ风格的切面声明的

Spring AOP使用整理:自动代理以及AOP命令空间

三.自动代理的实现 1.使用BeanNameAutoProxyCreator 通过Bean的name属性自动生成代理Bean. <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames"> <list> <value>*Target</value>

5、Spring AOP的几种通知(xml)

1.前置.后置.返回.异常和环绕 1 public interface Calculator { 2 3 int add(int a, int b); 4 5 int sub(int a, int b); 6 } 7 8 public class CalculatorImpl implements Calculator { 9 10 @Override 11 public int add(int a, int b) { 12 return a + b; 13 } 14 15 @Override

Spring AOP——Spring 中面向切面编程

前面两篇文章记录了 Spring IOC 的相关知识,本文记录 Spring 中的另一特性 AOP 相关知识. 部分参考资料: <Spring实战(第4版)> <轻量级 JavaEE 企业应用实战(第四版)> Spring 官方文档 W3CSchool Spring教程 易百教程 Spring教程 一.AOP--另一种编程思想 1.1 什么是 AOP AOP (Aspect Orient Programming),直译过来就是 面向切面编程.AOP 是一种编程思想,是面向对象编程(

spring AOP和通知

1.  spring的通知 1.1.  AOP的概念 切面(Aspect):一个关注点的模块化,这个关注点可能会横切多个对象.事务管理是J2EE应用中一个关于横切关注点的很好的例子.在Spring AOP中,切面可以使用基于模式或者基于注解的方式来实现. 连接点(Joinpoint):在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候.在Spring AOP中,一个连接点总是表示一个方法的执行. 通知(Advice):在切面的某个特定的连接点上执行的动作.其中包括了"aroun

Spring AOP介绍及源码分析

一.AOP介绍 举个例子来说明一下吧!现在系统中有很多的业务方法,如上传产品信息.修改产品信息.发布公司库等:现在需要对这些方法的执行做性能监控,看每个业务方法的执行时间:在不改变原业务代码的基础上,也许我们会这么做: Offer接口: Offer实现: Offer代理: 我们要通过下面的方式来使用: 上面的例子的输出为: 上面的例子中,OfferProxy实现了IOffer,而所有的业务实现均委托给其成员offer:可以想像,这应该就是最简单的AOP的实现了:但这种方式会存在一个问题:如果有非