天天看点

Spring(十一)AspectJ框架开发AOP(基于xml)

说明

AspectJ是一个基于Java语言的AOP框架

Spring2.0以后新增了对AspectJ切点表达式支持

@AspectJ 是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面,所以可以使用xml方式和注解方式来开发AOP

新版本Spring框架,建议使用AspectJ方式来开发AOP

aspectj有五种通知

before( Formals )
前置通知(在方法执行前执行,如果通知抛出异常,阻止方法运行)
after( Formals ) returning [ ( Formal ) ]
后置通知(方法正常返回后执行,如果方法中抛出异常,通知无法执行
必须在方法执行后才执行,所以可以获得方法的返回值。)
after( Formals ) throwing [ ( Formal ) ]
异常停止(方法抛出异常后执行,如果方法没有抛出异常,无法执行)
after( Formals )
最终通知(方法执行完毕后执行,无论方法中是否出现异常,类似try-catch-finally里面的finally块)
around( Formals )
环绕通知( 方法执行前后分别执行,可以阻止方法的执行,必须手动执行目标方法)
在xml中对应:
Spring(十一)AspectJ框架开发AOP(基于xml)

导入的jar包:

1.aop联盟规范

2.spring aop实现

3.aspect规范

4.spring aspect实现

Spring(十一)AspectJ框架开发AOP(基于xml)

xml小例子

编写过程:

1.目标类:实现+接口

2.切面类:编写多个通知

3.aop编程,将通知应用到目标类

4.测试

目标类:

接口

public interface UserService {
    public boolean addUser();
    public void updateUser();
    public void deleteUser();
}      

实现

public class UserServiceImpl implements UserService

    @Override
    public boolean addUser() {
        System.out.println("UserServiceDaoImpl addUser");
        return true;
    }

    @Override
    public void updateUser() {
        //测试抛出异常通知
    //  int i=1/0;
        System.out.println("UserServiceDaoImpl updateUser");
    }

    @Override
    public void deleteUser() {
        System.out.println("UserServiceDaoImpl deleteUser");
    }

}      

切面类

五种通知对方法的方法名称没有限制,但是方法的格式有限制。方法的格式会在xml配置中给出。

public class MyAspect  {
    //前置通知
    public void before(JoinPoint joinPoint){
        System.out.println("MyAspect-before");
    }
    //最终通知
    public void after(JoinPoint joinPoint){
        System.out.println("MyAspect-after");
    }
    //环绕通知
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.println("MyAspect-around-前");
        Object obj=joinPoint.proceed();//执行目标方法
        System.out.println("MyAspect-around-后");
        return obj;
    }
    //后置通知
    public void afterReturning(JoinPoint joinPoint,Object ret){
        System.out.println("MyAspect-afterReturning  "+joinPoint.getSignature().getName()+"\t"+ret);
    }
    //异常通知
    public void afterThrowing(JoinPoint joinPoint,Throwable e){
        System.out.println("MyAspect-afterThrowing "+e.getMessage());
    }
}         

spring配置

<?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.xsd
                            http://www.springframework.org/schema/aop 
                            http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 创建目标类 -->
    <bean id="userServiceId" class="com.scx.xmlproxy.test.UserServiceImpl"></bean> 
    <!-- 创建切面类(通知) -->  
    <bean id="myAspectId" class="com.scx.xmlproxy.test.MyAspect"></bean>  
    <!-- aop编程--> 
    <aop:config proxy-target-class="true">
        <aop:aspect ref="myAspectId">
            <aop:pointcut expression="execution(* com.scx.xmlproxy.test.*.*(..))" id="myPointCut"/>
            <!-- 前置通知
                <aop:before method="before" pointcut-ref="myPointCut"/>
                方法格式(参数1)
                参数1:连接点描述
                method:方法名
                pointcut:切入点表达式
                pointcut-ref:切入点引用
            -->
            <!-- 最终通知 
                <aop:after method="after" pointcut-ref="myPointCut"/>
                方法格式(参数1)
                参数1:连接点描述
            -->
            <!-- 环绕通知
                    <aop:around method="around" pointcut-ref="myPointCut"/> 
                    方法格式(参数1)
                    参数:org.aspectj.lang.ProceedingJoinPoint
             -->
             <!-- 后置通知
                    <aop:after-returning method="afterReturning" returning="ret" pointcut-ref="myPointCut"/>
                    方法格式(参数1,参数2)
                    参数1:连接点描述
                    参数2:类型Object,参数名 returning="ret" 配置的
            -->
            <!-- 
                抛出异常
                <aop:after-throwing method="afterThrowing" pointcut-ref="myPointCut" throwing="e"/>
                方法格式(参数1,参数2)
                参数1:连接点描述对象
                参数2:获得异常信息,类型Throwable ,参数名由throwing="e" 配置
             -->

        </aop:aspect>


    </aop:config>

</beans>      

测试:

测试时,最好只执行一个通知,否则结果会和想象的不一样orz.

@org.junit.Test
    public void testProxy(){
        String xmlPath="com/scx/xmlproxy/test/applicationContext.xml";
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath);
        UserService userService=(UserService) applicationContext.getBean("userServiceId");
        userService.addUser();
        userService.updateUser();
        userService.deleteUser();
    }      

测试结果:

前置通知:

Spring(十一)AspectJ框架开发AOP(基于xml)

后置通知:

Spring(十一)AspectJ框架开发AOP(基于xml)

异常通知:

为了出现异常我在实现类的updateUser方法里面里面添加了​

​int i = 1 /0;​

​ 这行代码

Spring(十一)AspectJ框架开发AOP(基于xml)

结果如图所示输出了除0的异常

这时候我们修改为最终通知。运行结果:

Spring(十一)AspectJ框架开发AOP(基于xml)

我们发现updateUser方法没有因为异常输出,但是最终通知输出了。

环绕通知: