Spring框架之AOP(面向切面编程)篇

目录
  1. AOP简介
  2. 示例(一般切面)
  3. 示例(切点切面)
  4. 示例(自动代理)
  5. 示例(AspectJ xml方式)
  6. 示例(AspectJ 注解方式)

1. AOP简介

AOP(全称:Aspect Oriented Programming):在运行时动态地将代码切入到指定类的指定方法的指定位置上。

可以在不修改源码的情况下给类添加新功能(通常是一些可复用的功能,如:日志功能、事务功能、权限检查、参数检查、统计信息),降低通用功能和业务逻辑的耦合,减少代码的重复性。

AOP的动态代理机制(2种方式)
  Spring在运行期会为目标对象生成一个动态代理对象(用来对目标对象进行增强)。
  1. JDK方式(默认)
    若目标对象实现了若干接口,Spring则使用JDK的java.lang.reflect.Proxy类进行代理。
  2. CGLIB方式    
    若目标对象没有实现任何接口,Spring则使用CGLIB库生成目标对象的子类进行代理。
  注意:声明为final类型的方法无法被覆盖,所以无法增强。

AOP切入点
  将切入到指定类指定方法的代码片段称为切面,而切入到哪些类、哪些方法则叫切入点。
  SpringAOP属于简化版AOP组件,并没有像其他AOP框架(如:AspectJ)那样提供了完整的AOP功能。
  SpringAOP只支持方法调用(仅支持public类型且非static类型的方法)这一种切入点类型(最有用的切入点类型,可实现绝大多数AOP功能)。如果需要对private或protected类型的方法进行增强,或者需要使用其他类型的切入点(如:成员变量切入点),则需要组合其他AOP实现框架(如:ApectJ)来达成。

AOP通知类型
  按照通知织入到目标对象方法的连接点位置,提供了org.aopalliance.aop.Interface.Advice接口的6个子接口:
    1. 前置通知(org.springframework.aop.MethodBeforeAdvice)
      在目标方法执行前 执行通知(即进行增强)。
    2. 后置通知(org.springframework.aop.AfterReturningAdvice)
      在目标方法执行后(无论是否异常)执行通知。
    3. 后置返回通知(org.springframework.aop.AfterReturningAdvice)
      在目标方法执行后(且有返回值时)执行通知。
    4. 环绕通知(org.aopalliance.intercept.MethodInterceptor)
      在目标方法执行前后 执行通知。
    5. 异常后通知(org.springframework.aop.ThrowsAdvice)
      在目标方法抛出异常时 执行通知。
    6. 引入通知(org.springframework.aop.IntroductionInterceptor)
      在目标类中添加新的方法和属性。

AOP切面(对通知和切入点进行管理)类型(3种)
  1. 一般切面(不带切点的切面)默认
    org.springframework.aop.Advisor接口(仅有一个Advice通知类型的属性,没有定义切入点)。
    会对目标对象中的所有方法进行拦截并织入增强代码(由于太过宽泛,一般不使用)。
  2. 切点切面
    org.springframework.aop.PointcutAdvisor接口(Advisor的子接口,多了一个PointCut类型的属性)。
    可以通过包名、类名、方法名等信息,更加灵活地定义切面中的切入点(即描述需要拦截的方法)。
    常用的实现类:
      1. NameMatchMethodPointcutAdvisor类
        指定通知所要应用到的目标方法名(如:hello* 代表所有以hello开头的方法)。
      2. RegExpMethodPointcutAdvisor类
        有一个pattern属性(使用正则表达式来定义切点)。
  3. 引介切面
    org.springframework.aop.IntroductionAdvisor接口(Advisor的子接口)。
    对引介增强的特殊切面(应用于类层面上,适用ClassFilter进行定义)。

ProxyFactoryBean
  Spring能够基于org.springframework.aop.framework.ProxyFactoryBean类,根据目标对象(是否实现了接口)自动选择使用 JDK动态代理 或 CGLIB动态代理机制,为目标对象(TargetBean)生成对应的代理对象(ProxyBean)。
  常用的属性:
    1. target   
      需要被代理的目标对象(即需要增强的对象)。
    2. proxyInterfaces  
      代理对象需要实现的接口(多个接口时使用list元素进行赋值)。
    3. proxyTargetClass     
      针对类的代理。为false(默认)表示使用JDK动态代理;为true表示使用CGlib动态代理。
    4. interceptorNames     
      拦截器的名字(拦截器、Advice、切面 对应的Bean)。
    5. singleton    
      代理对象是否为单例模式(默认为true)。
    6. optimize     
      是否对代理对象进行优化(只适用于CGLIB)。

自动代理
  在实际开发中,一个项目中往往包含非常多的Bean,如果每个Bean都通过在xml文件中使用ProxyFactoryBean创建代理对象,那么开发和维护成本会十分巨大,为此Spring提供了自动代理。
  Spring提供的自动代理方案,都是基于后处理Bean实现的(即在Bean创建的过程中完成增强),并将目标对象替换为自动生成的代理对象。在程序中直接拿到的Bean就已经是Spring自动生成的代理对象了。
  自动代理方案(3种):
    1. BeanNameAutoProxyCreator
      根据Bean名称 创建代理对象。
    2. DefaultAdvisorAutoProxyCreator
      根据Advisor信息 创建代理对象。
    3. AnnotationAwareAspectJAutoProxyCreator
      根据Bean中的AspectJ注解 创建自动代理对象。
集成AspectJ
  AspectJ是一款独立的基于Java语言的全功能AOP框架,并不是Spring组成部分。AspectJ支持通过Spring配置AspectJ切面,因此它是SpringAOP的完美补充,工作中通常将2者结合使用来简化AOP开发。
  需要导入spring-aop-xxx.jar、spring-aspects-xxx.jar(Spring提供),aspectjweaver-xxxx.jar(AspectJ提供)依赖包。
  1. 使用步骤(XML方式):
    切面信息(切面、切点、通知)定义在aop:config元素(可以有多个)中。
    1. 引入aop命名空间。
    2. 使用aop:aspect元素定义切面。
      <aop:config>
        <aop:aspect id="helloAspect" ref="aspectBean">
          ...
        </aop:aspect>
      </aop:config>    
    3. 使用aop:pointcut元素定义切点(对哪个方法进行增强)。
      <aop:config>
        <!-- 对包下的所有类中的所有方法进行增强 -->
        <aop:pointcut id="helloPointCut" expression="execution(* com.sst.cx.*.*(..))"/>
      </aop:config>
      说明:
      1. 当aop:pointcut元素定义在aop:config元素下时,表示该切点为全局切入点,可被多个切面共享;当aop:pointcut元素定义在aop:aspect元素下时,表示该切点只对当前切面有效。
      2. aop:pointcut元素的execution属性用于指定切入点所关联的切入点表达式。
        语法格式:execution([权限修饰符][返回值类型][类的完全限定名][方法名][参数列表])
        1. 返回值类型、方法名、参数列表 为必填,其他参数可选。
        2. 返回值类型:*表示任何返回值。当返回值为对象时需指定类的完整路径。
        3. 方法:*表示所有方法,hello*表示以hello开头的所有方法。
        4. 参数列表:(..)表示所有参数;(*)表示只有一个参数,参数类型任意;(*,String)表示有2个参数。
    4. 使用aop:aspect元素定义通知(5种类型)。
      <aop:aspect id="helloAspect" ref="实现下面5个方法的bean">
        <aop:before method="before" pointcut-ref="前面定义的切点id"></aop:before>
        <aop:after-returning method="afterReturning" pointcut-ref="前面定义的切点id" returning="returningValue"></aop:after-returning>
        <aop:after-throwing method="afterThrow" pointcut-ref="前面定义的切点id" throwing="exception"></aop:after-throwing>
        <aop:after method="after" pointcut-ref="前面定义的切点id"></aop:after>
        <aop:around method="around" pointcut-ref="前面定义的切点id"></aop:around>
      </aop:aspect> 
  2. 使用步骤(注解方式):
    1. 开启 @AspectJ注解。
      方式1. 在beans元素的开始处添加
        <!-- 开启注解扫描 -->
        <context:component-scan base-package="com.sst.cx"></context:component-scan>
        <!-- 开启@AspectJ注解 -->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
      方式2. 在AppConfig.java类(使用@Configuration注解标注的类)中,添加@EnableAspectJAutoProxy注解和@ComponentScan(basePackages="com.sst.cx")注解。该类用于获取容器:ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);。
    2. 在UserDaoAdvice上添加
      @Component注解:在Ioc容器中注册Bean。
      @Aspect注解:定义成切面。
    3. 在UserDaoAdvice的各个方法上添加通知注解
      方式1. 使用切入点表达式
        @Before(value="execution(* com.sst.cx.dao.UserDao.add(..))")
      方式2. 使用切入点引用
        @Before("UserDaoAdvice.pointCut1()")
        //
        定义切点
          可以使用切点表达式;也可以引用其他切点:@Pointcut(value="pointCut2"),引用其他切入点时可以使用 !、&&、|| :@Pointcut(value="!pointCut2()")。
          @Pointcut(value="execution(* com.sst.cx.dao.UserDao.add(..))")
          // 方法要求:private类型,返回值为void,没有参数
          private void pointCut1(){}
    //
    AspecjJ提供了如下注解:
      1. @Aspect    
        用于定义一个切面。
      2. @Pointcut  
        用于定义一个切入点。
      3. @Before    
        用于定义前置通知,相当于 BeforeAdvice。
      4. @AfterReturning    
        用于定义后置返回通知,相当于 AfterReturningAdvice。
      5. @Around    
        用于定义环绕通知,相当于 MethodInterceptor。
      6. @AfterThrowing 
        用于定义异常抛出通知,相当于 ThrowAdvice。
      7. @After 
        用于定义后置通知,相当于 AfterAdvice。
      8. @DeclareParents    
        用于定义引介通知,相当于 IntroductionInterceptor。

2. 示例(一般切面)

如果没有对切面进行具体定义,SpringAOP会通过Advisor接口定义一个一般切面(不带切点的切面)。

1. 导入依赖包
  4个核心jar:beans、context、core、expression
  AOP特性jar:aop
  三方jar:commons-logging.jar
2. 创建相关类

===》UserDao.java(DAO接口)
package com.sst.cx.dao;
public interface UserDao {
    public void add();
    public void delete();
    public void update();
    public void querry();
}
===》UserDaoImpl.java(DAO实现)
package com.sst.cx.dao.impl;
import com.sst.cx.dao.UserDao;
public class UserDaoImpl implements UserDao {
    @Override
    public void add() {
        System.out.println("执行add方法。。。");
    }
    @Override
    public void delete() {
        System.out.println("执行delete方法。。。");
    }
    @Override
    public void update() {
        System.out.println("执行update方法。。。");
        
    }
    @Override
    public void querry() {
        System.out.println("执行querry方法。。。");
    }
}
===》UserDaoBeforeAdvice.java(Advice通知,拦截器)
package com.sst.cx.advice;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class UserDaoBeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
        System.out.println("前置增强操作。。。");
    }
}
3. xml文件

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context-3.0.xsd">
        <!-- 目标对象(需要增强的对象) -->
        <bean id="userDaoImpl" class="com.sst.cx.dao.impl.UserDaoImpl"></bean>
        <!-- 定义增强(拦截器/通知) -->
        <bean id="beforeAdvice" class="com.sst.cx.advice.UserDaoBeforeAdvice"></bean>
        <!-- 通过配置生成代理userDaoImpl的代理对象 -->
        <bean id="userDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
            <!-- 设置 被代理的目标对象(需增强的对象) -->
            <property name="target" ref="userDaoImpl"/>
            <!-- 设置 代理对象需实现的接口(全路径) -->
            <property name="proxyInterfaces" value="com.sst.cx.dao.UserDao"/>
            <!-- 设置 拦截器(增强) -->
            <property name="interceptorNames" value="beforeAdvice"/>
    </bean>
</beans>
4. 测试

===》MainApp.java
package com.sst.cx;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.sst.cx.dao.UserDao;
public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        // 获取代理对象
        UserDao userDao = (UserDao)context.getBean("userDaoProxy");
        userDao.add();
        userDao.delete();
        userDao.update();
        userDao.querry();
    }
}
运行结果

3. 示例(切点切面)

1. 导入依赖包
  同上
2. 创建相关类

===》UserDao.java、userDaoImpl.java
  同上
===》UserDaoAroundAdvice.java(Advice通知,拦截器)这次换一种通知类型:环绕通知
package com.sst.cx.advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class UserDaoAroundAdvice implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("前置增强操作。。。");
        // 执行目标方法(被代理对象中的逻辑)
        Object result = methodInvocation.proceed();
        System.out.println("后置增强操作。。。");
        return result;
    }
}
3. xml文件

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
        <!-- 目标对象(需要增强的对象) -->
        <bean id="userDaoImpl" class="com.sst.cx.dao.impl.UserDaoImpl"></bean>
        <!-- 定义增强 -->
        <bean id="aroundAdvice" class="com.sst.cx.advice.UserDaoAroundAdvice"></bean>
        <!-- 定义切面 -->
        <bean id="myPointCutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
            <!--拦截哪些方法。 value设为.*则表示所有方法-->
            <property name="patterns" value="com.sst.cx.dao.impl.UserDaoImpl.add.*,com.sst.cx.dao.impl.UserDaoImpl.delete.*"></property>
            <property name="advice" ref="aroundAdvice"></property>
        </bean>
        <!-- 通过配置生成代理userDaoImpl的 代理对象 -->
        <bean id="userDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
            <!-- 设置 被代理的目标对象(需增强的对象) -->
            <property name="target" ref="userDaoImpl"/>
            <!-- 设置 代理对象需实现的接口(全路径) -->
            <property name="proxyInterfaces" value="com.sst.cx.dao.UserDao"/>
            <!-- 设置 拦截器(增强) -->
            <property name="interceptorNames" value="myPointCutAdvisor"/>
        </bean>
</beans>
4. 测试
  同上
运行结果

4. 示例(自动代理)

将上面的 切点切面示例 改为自动代理。

===》方式1. BeanNameAutoProxyCreator
修改xml文件内容如下(去除切面Bean、ProxyFactoryBean,添加自动代理Bean):
        <!-- 目标对象(需要增强的对象) -->
        <bean id="userDaoImpl" class="com.sst.cx.dao.impl.UserDaoImpl"></bean>
        <!-- 定义增强 -->
        <bean id="aroundAdvice" class="com.sst.cx.advice.UserDaoAroundAdvice"></bean>
        <!-- 自动代理,对所有后缀为Impl的Bean自动创建代理对象,对所有方法进行aroundAdvice增强 -->
        <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
            <property name="beanNames" value="*Impl"></property>
            <property name="interceptorNames" value="aroundAdvice"></property>
        </bean>

===》方式2. DefaultAdvisorAutoProxyCreator
修改xml文件内容如下(去除ProxyFactoryBean,添加自动代理Bean):
        <!-- 目标对象(需要增强的对象) -->
        <bean id="userDaoImpl" class="com.sst.cx.dao.impl.UserDaoImpl"></bean>
        <!-- 定义增强 -->
        <bean id="aroundAdvice" class="com.sst.cx.advice.UserDaoAroundAdvice"></bean>
        <!-- 定义切面 -->
        <bean id="myPointCutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
            <!--拦截哪些方法。 value设为.*则表示所有方法-->
            <property name="patterns" value="com.sst.cx.dao.impl.UserDaoImpl.add.*,com.sst.cx.dao.impl.UserDaoImpl.delete.*"></property>
            <property name="advice" ref="aroundAdvice"></property>
        </bean>
        <!-- 自动代理,根据切面信息自动创建代理对象,对指定方法进行增强 -->
        <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>

测试文件中直接使用userDaoImpl获取代理对象:context.getBean("userDaoImpl")

5. 示例(AspectJ)

1. 导入依赖包

  4个核心jar:beans、context、core、expression
  AOP特性jar:aop、aspects(Spring提供),aspectjweaver(aspectJ提供)
  三方jar:commons-logging.jar
2. UserDao.java、userDaoImpl.java、UserDaoAdvice.java

===》UserDao.java(DAO接口)
package com.sst.cx.dao;
public interface UserDao {
    public void add();
    public void delete();
    public int update();
    public void querry();
    public void throwException();
}
===》userDaoImpl.java(DAO实现)
package com.sst.cx.dao.impl;
import com.sst.cx.dao.UserDao;
public class UserDaoImpl implements UserDao {
    @Override
    public void add() {
        System.out.println("执行add方法。。。");
    }
    @Override
    public void delete() {
        System.out.println("执行delete方法。。。");
    }
    @Override
    public int update() {
        System.out.println("执行update方法。。。");
        return 100;
    }
    @Override
    public void querry() {
        System.out.println("执行querry方法。。。");
    }
    @Override
    public void throwException() {
        System.out.println("执行throwException方法。。。");
        int x=1/0;
    }
}
===》UserDaoAdvice.java(Advice通知,拦截器)
package com.sst.cx.advice;
import org.aspectj.lang.ProceedingJoinPoint;
public class UserDaoAdvice {
    public void before() {
        System.out.println("前置增强操作。。。");
    }
    public void after() {
        System.out.println("后置增强操作。。。");
    }
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        System.out.println("环绕前置增强操作。。。");
        proceedingJoinPoint.proceed();
        System.out.println("环绕后置增强操作。。。");
    }
    public void afterReturning(Object returnValue) {
        System.out.println("后置返回增强操作。。。"+returnValue);
    }
    public void afterThrow(Throwable exception) {
        System.out.println("异常增强操作。。。"+exception.getMessage());
    }   
}
3. xml文件

<?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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">
    <!-- 定义Bean -->
    <bean id="userDaoImpl" class="com.sst.cx.dao.impl.UserDaoImpl"></bean>
    <!-- 定义通知(增强) -->
    <bean id="myAdvice" class="com.sst.cx.advice.UserDaoAdvice"></bean>
    <aop:config>
        <aop:pointcut id="beforePointCut" expression="execution(* com.sst.cx.dao.UserDao.add(..))"/>
        <aop:pointcut id="afterPointCut" expression="execution(* com.sst.cx.dao.UserDao.delete(..))"/>
        <aop:pointcut id="afterReturnPointCut" expression="execution(* com.sst.cx.dao.UserDao.update(..))"/>
        <aop:pointcut id="aroundPointCut" expression="execution(* com.sst.cx.dao.UserDao.querry(..))"/>
        <aop:pointcut id="throwPointCut" expression="execution(* com.sst.cx.dao.UserDao.throwException(..))"/>      
        <aop:aspect ref="myAdvice">
            <aop:before method="before" pointcut-ref="beforePointCut"></aop:before>
            <aop:after-returning method="afterReturn"
                pointcut-ref="afterReturnPointCut" returning="returnValue"></aop:after-returning>
            <aop:after-throwing method="afterThrow"
                pointcut-ref="throwPointCut" throwing="exception"></aop:after-throwing>
            <aop:after method="after" pointcut-ref="afterPointCut"></aop:after>
            <aop:around method="around" pointcut-ref="aroundPointCut"></aop:around>
        </aop:aspect>
    </aop:config>
</beans>
4. 测试

===》MainApp.java
package com.sst.cx;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.sst.cx.dao.UserDao;
public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        UserDao userDao = context.getBean("userDaoImpl",UserDao.class);
        userDao.add();
        userDao.delete();
        userDao.update();
        userDao.querry();
        userDao.throwException();
    }
}
运行结果

6. 示例(AspectJ 注解方式)

1. 导入依赖包

  4个核心jar:beans、context、core、expression
  AOP特性jar:aop、aspects(Spring提供),aspectjweaver(aspectJ提供)
  三方jar:commons-logging.jar
2. UserDao.java、userDaoImpl.java、UserDaoAdvice.java

===》UserDao.java(DAO接口)
package com.sst.cx.dao;
public interface UserDao {
    public void add();
    public void delete();
    public int update();
    public void querry();
    public void throwException();
}
===》userDaoImpl.java(DAO实现)
package com.sst.cx.dao.impl;
import org.springframework.stereotype.Component;
import com.sst.cx.dao.UserDao;
@Component("userDaoImpl")
public class UserDaoImpl implements UserDao {
    @Override
    public void add() {
        System.out.println("执行add方法。。。");
    }
    @Override
    public void delete() {
        System.out.println("执行delete方法。。。");
    }
    @Override
    public int update() {
        System.out.println("执行update方法。。。");
        return 100;
    }
    @Override
    public void querry() {
        System.out.println("执行querry方法。。。");
    }
    @Override
    public void throwException() {
        System.out.println("执行throwException方法。。。");
        int x=1/0;
    }
}
===》UserDaoAdvice.java(Advice通知,拦截器)
package com.sst.cx.advice;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class UserDaoAdvice {
    @Before(value="execution(* com.sst.cx.dao.UserDao.add(..))")
    public void before() {
        System.out.println("前置增强操作。。。");
    }
    @After(value="execution(* com.sst.cx.dao.UserDao.delete(..))")
    public void after() {
        System.out.println("后置增强操作。。。");
    }
    @Around(value="execution(* com.sst.cx.dao.UserDao.querry(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        System.out.println("环绕前置增强操作。。。");
        proceedingJoinPoint.proceed();
        System.out.println("环绕后置增强操作。。。");
    }
    @AfterReturning(value="execution(* com.sst.cx.dao.UserDao.update(..))",returning="returnValue")
    public void afterReturn(Object returnValue) {
        System.out.println("后置返回增强操作。。。返回值:"+returnValue);
    }
    @AfterThrowing(value="execution(* com.sst.cx.dao.UserDao.throwException(..))",throwing="exception")
    public void afterThrow(Throwable exception) {
        System.out.println("异常增强操作。。。异常信息:"+exception.getMessage());
    }   
}
4. 测试

===》MainApp.java
package com.sst.cx;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.sst.cx.dao.UserDao;
public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        // 获取代理对象
        UserDao userDao = context.getBean("userDaoImpl",UserDao.class);
        userDao.add();
        userDao.delete();
        userDao.update();
        userDao.querry();
        userDao.throwException();
    }
}
运行结果
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,012评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,628评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,653评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,485评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,574评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,590评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,596评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,340评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,794评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,102评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,276评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,940评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,583评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,201评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,441评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,173评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,136评论 2 352

推荐阅读更多精彩内容

  • 六、基于@Aspect注解编程(重点) 1、说明 Spring 使用了和AspectJ 一样的注解并使用Aspec...
    唯老阅读 557评论 0 1
  • 导言 AOP(Aspect Orient Programming),作为面向对象编程的一种补充,广泛应用于处理一些...
    周若谷阅读 2,690评论 1 2
  • 目录 1. Web MVC发展史历程2.Spring概要3.Spring-依赖注入概要(IOC)4.属性注入的三种...
    唯老阅读 1,289评论 0 3
  • 什么是AOP AOP,顾名思义面向切面编程。要实现的是在我们原来写的代码的基础上,进行一定的包装,如在方法执行前、...
    耐得千事烦阅读 257评论 0 1
  • 1.AOP概述 1.1.AOP到底是什么 AOP只适合那些具有横切面逻辑的应用场合,如性能监测,访问控制,事务管理...
    小螺钉12138阅读 708评论 0 0