Spring AOP

面向切面编程(Spring AOP)

为了将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,Spring提供了面向切面的编程方式,也称Spring AOP,这有效的减少了系统间的重复代码,达到了模块间的松耦合目的。

AOP,Aspect Oriented Programing,即面向切面编程。AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码,主要体现在事务处理、日志管理、权限控制、异常处理等方面。

目前流行的AOP框架有两个,分别是Spring AOP和AspectJ。AspectJ是一个基于Java语言的AOP框架。

AOP术语

  • Joinpoint(连接点):是指那些被拦截到的点,在Spring中,可以被动态代理拦截目标类的方法。
  • Pointcut(切入点):是指要对哪些Joinpoint进行拦截,即被拦截的拦截点。
  • Advice(通知):是指拦截到Joinpoint之后要做的事情,即对切入点增强的内容。
  • Target(目标):是指代理的目标对象。
  • Weaving(织入):是指把增强代码应用到目标上,生成代理对象的过程。
  • Proxy(代理):是指生成的代理对象。
  • Aspect(切面):是切入点和通知的结合。

AspectJ开发

基于XML的声明式AspectJ

导入AOP的的jar包

  • spring-aop-3.2.0.RELEASE.jar:是Spring为AOP提供的实现。
  • com.springsource.org.aopalliance-1.0.0.jar:是AOP联盟提供的规范。

导入AsprctJ相关的jar包

  • spring-aspects-3.2.0.RELEASE.jar:Spring为AspectJ提供的实现。
  • com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar:AspectJ提供的规范。

建立UserDao.java

package cn.itcast.dao;

public interface UserDao {
    void save();
    void update();
    void delete();
    void find();
}

UserDaoImpl.java

package cn.itcast.dao;

public class UserDaoImpl implements UserDao{

    @Override
    public void save() {
        System.out.println("save添加用户");
    }

    @Override
    public void update() {
        System.out.println("update修改用户");
    }

    @Override
    public void delete() {
        System.out.println("delete删除用户");
    }

    @Override
    public void find() {
        System.out.println("find查询用户");
    }

}

MyAspect.java

package cn.itcast.aspectj.xml;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

/*
 * 切面类,在此编写通知
 * 可以在XML配置文件中确定通知类型
 */
public class MyAspect {
    //前置通知
    public void myBefore(JoinPoint joinPoint){
        System.out.println("前置通知,目标:");
        System.out.println(joinPoint.getTarget()+",方法名称:");
        System.out.println(joinPoint.getSignature().getName());
    }

    //后置通知
    public void myAfterReturning(JoinPoint joinPoint){
        System.out.println("后置通知,方法名称:"+joinPoint.getSignature().getName());
    }

    //环绕通知
        //ProceedingJoinPoint是JoinPoint子接口,表示可以执行目标方法
        //1.必须返回Object类型值
        //2.必须接收一个参数,类型为ProceedingJoinPoint
        //3.必须throws Throwable
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        //开始
        System.out.println("环绕开始");
        //执行当前目标方法
        Object obj=proceedingJoinPoint.proceed();
        //结束
        System.out.println("环绕结束");
        return obj;
    }

    //异常通知
    public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
        System.out.println("异常通知,出错了"+e.getMessage());
    }

    //最终通知
    public void myAfter(){
        System.out.println("最终通知");
    }


}

applicationContext.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.xsd
                           http://www.springframework.org/schema/aop 
                           http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 1.目标类 -->
    <bean id="userDao" class="cn.itcast.dao.UserDaoImpl"></bean>
    <!-- 2.切面 -->
    <bean id="myAspect" class="cn.itcast.aspectj.xml.MyAspect"></bean>
    <!-- 3.aop编程 -->
    <aop:config>
        <aop:aspect ref="myAspect">
            <!-- 3.1 配置切入点,通知最后增强哪些方法 -->
            <aop:pointcut expression="execution(* cn.itcast.dao..*.*(..))" id="myPointCut"/>
            <!-- 3.2关联通知Advice和切入点pointCut -->
            <!-- #1前置通知 -->
            <aop:before method="myBefore" pointcut-ref="myPointCut"/>
            <!-- #2后置通知,在方法返回之后执行,就可以获得返回值
                returning属性:用于设置后置通知的第二个参数的名称,类型是Object 
             -->
             <aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="returnVal"/>
             <!-- #3环绕通知 -->
             <aop:around method="myAround" pointcut-ref="myPointCut"/>
             <!-- #4抛出通知:用于处理程序发生异常,就可以接受当前方法产生的异常
                注意:如果程序没有异常,将不会执行增强
                throwing属性:用于设置通知第二个参数的名称,类型Throwable
              -->
              <aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="e"/>
              <!-- #5最终通知:无论程序发生任何事情,都将执行 -->
              <aop:after method="myAfter" pointcut-ref="myPointCut"/>
        </aop:aspect>
    </aop:config>
</beans>

AspectJ表达式

execution() 用于描述方法

语法:execution(修饰符 返回值 包.类.方法名(参数) throws异常)

  • 修饰符:一般省略。
    • public:公共方法
    • *:任意
  • 返回值:不能省略
    • void:无返回值
    • String:返回值为字符串
    • *:任意(一般用这个)
  • 包:可以省略
    • com.eaglezsx.crm:固定包
    • com.eaglezsx.crm.*.service:crm包下面的任意子包,但要包含service。比如com.eaglezsx.crm.staff.service
    • com.eaglezsx.crm..:crm下面的任意子包(包括孙包)
    • com.eaglezsx.crm.*.service.. :crm包下面任意子包,固定目录service,service目录任意包
  • 类:可以省略
    • UserServiceImplement:指定类
    • *Impl:以Impl结尾的类
    • User*:以User开头的类
    • *:任意类
  • 方法名:不能省略
    • addUser:固定方法
    • add*:以add开头的方法
    • *Do:以Do结尾的方法
    • *:任意方法
  • (参数)
    • ():无参
    • (int):一个整型参数
    • (int,int):两个整型参数
    • (..):任意参数
  • throws:可省略,一般不写。
* cn.itcast.dao..*.*(..)
意思是,返回值任意,cn.itcast.dao下的任意包,下的任意类,下的任意方法,方法的参数任意

TestXML.java

package cn.itcast.aspectj.xml;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.itcast.dao.UserDao;

public class TestXML {
    @Test
    public void demo01(){
        String xmlPath="applicationContext.xml";
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath);

        //1.从Spring容器获得内容
        UserDao userDao=(UserDao)applicationContext.getBean("userDao");
        //2.执行方法
        userDao.save();
    }
}

运行结果

前置通知,目标:
cn.itcast.dao.UserDaoImpl@110fcd9,方法名称:
save
环绕开始
save添加用户
后置通知,方法名称:save
环绕结束
最终通知

基于Annotation的声明式AspectJ

  • @AspectJ:用于定义一个切面
  • @Before:用于定义前置通知,相当于BeforeAdvice
  • @AfterReturning:用于定义后置通知,相当于AfterReturningAdvice
  • @Around:用于定义环绕通知,相当于MethodInterceptor
  • @AfterThrowing:用于定义抛出通知,相当于ThrowAdvice
  • @After:用于定义最终final通知,不管是否异常,该通知都会执行
@Aspect
@Component
public class MyAspect {
    /*
        用于取代<aop:pointcut expression="execution(* cn.itcast.dao..*.*(..))" id="myPointCut"/>
        要求:方法必须是private没有值 名称自定义,没有参数
    */
    @Pointcut("execution(* cn.itcast.dao..*.*(..))")
    private void myPointCut(){}

    @Before("myPointCut()")
    public void myBefore(JoinPoint joinPoint){
        ...
    }

    @AfterReturning(value="myPointCut()")
    public void myAfterReturning(JoinPoint joinPoint){
        ...
    }

    @Around("myPointCut()")
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        ...
    }

    @AfterThrowing(value="myPointCut()",throwing="e")
    public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
        ...
    }

    @After("myPointCut()")
    public void myAfter(){
        ...
    }


}
@Repository("userDao")
public class UserDaoImpl implements UserDao{
    ...
}

applicationContext.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"
       xmlns:context="http://www.springframework.org/schema/context"
       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
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd">

     <!-- 扫描包:使注解生效 -->                    
     <context:component-scan base-package="cn.itcast"></context:component-scan>                    
     <!-- 使切面开启自动代理 -->                    
     <aop:aspectj-autoproxy></aop:aspectj-autoproxy>                       

</beans>

TestAnnotation.java

public class TestAnnotation {
    @Test
    public void demo01(){
        String xmlPath="applicationContext.xml";
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath);

        //1.从Spring容器获得内容
        UserDao userDao=(UserDao)applicationContext.getBean("userDao");
        //2.执行方法
        userDao.save();
    }
}
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值