Spring-Aop的学习总结——1

前几天我们回顾了静态代理,jdk动态代理,cglib代理,而aop的实现就是依靠动态代理实现,如果我们仅仅去看spring的api,我们理解一些概念会很困难,但我们清楚了动态代理后,理解这些概念就会很轻松!下面我们来看一下aop中几个核心的概念:
这里写图片描述
这样来看概念,的确比去看文档轻松很多吧,我们可以去看spring的api的上的例子,一些概念就不太建议去按照spring的api上去理解。
下面我们通过例子来看aop中的一些通知:
首先创建一个接口:PersonDao:

public interface PersonDao {
    public String savePerson();
}

创建接口的实现类:

public class PersonImpl implements PersonDao{

    @Override
    public String savePerson() {
        // TODO Auto-generated method stub
        int a = 1/0;
        System.out.println("SavePerson............");
        return "yss";
    }
}

然后创建一个事务:Transcation:即一个切面:

public class Transcation {

    /**
     * 前置通知:在目标方法执行之前
     * 后置通知:在目标方法执行之后
     * 参数:连接点
     */ 
     //前置通知
    public void beginTranscation(JoinPoint joinPoint) {
        String  methodName = joinPoint.getSignature().getName();
        System.out.println("连接点的名称:"+methodName);
        System.out.println("目标类:"+joinPoint.getTarget().getClass());

        System.out.println("beginTranscation....");

    }
    /*
     *val要和returning中的参数保持一致,获取目标方法的返回值 
     */
    public void commit(JoinPoint joinPoint,Object val) {
        System.out.println("commit..........");
        System.out.println("目标方法的返回值:"+val);
    }

    /*最终通知
     *
     * */
    public void finallyMethod() {
        System.out.println("finallyMethod/..");
    }
    /*异常通知
     *  接收目标方法抛出的异常 第二个参数和配置文件中的throwing保持一致
     * */
    public void thorwingMethod(JoinPoint joinPoint,Throwable ex) {
        System.out.println(ex.getMessage());
    }

    /*环绕通知
     * processdingJoinPoint.proceed()如果在环绕通知中不写,则目标方法不再执行
     * 即环绕通知可以控制目标方法执行
     * */
    public void aroundMethod(ProceedingJoinPoint processdingJoinPoint) throws Throwable {
        System.out.println("=====环绕");
        processdingJoinPoint.proceed();  //调用目标方法
    }
}

接下来我们仔细看一下写的这些方法的作用:
前置通知: beginTranscation:,在目标方法执行之前执行
参数是JoinPoint 通过这个参数,
我们可以获取连接点(目标方法)的名称和目标类。
通过joinPoint.getSignature().getName();可以获取连接点(目标方法)的名称
通过joinPoint.getTarget().getClass()可以获取目标类的class

public void beginTranscation(JoinPoint joinPoint) {
        String  methodName = joinPoint.getSignature().getName();
        System.out.println("连接点的名称:"+methodName);
        System.out.println("目标类:"+joinPoint.getTarget().getClass());
        System.out.println("beginTranscation....");

    }

后置通知:comomit:在目标方法执行之后执行

public void commit(JoinPoint joinPoint,Object val) {
        System.out.println("commit..........");
        System.out.println("目标方法的返回值:"+val);
    }

参数是JoinPoint joinPoint和Object value。
其中参数joinPoint为连接点,参数value是目标方法的返回值。

异常通知 :接收目标方法抛出的异常 第二个参数和配置文件中的throwing保持一致

public void thorwingMethod(JoinPoint joinPoint,Throwable ex) {
        System.out.println(ex.getMessage());
    }

最终通知 finallyMethod:无论目标方法是否抛出异常,都将执行

public void finallyMethod() {
        System.out.println("finallyMethod/..");
    }

环绕通知

public void aroundMethod(ProceedingJoinPoint processdingJoinPoint) throws Throwable {
        System.out.println("=====环绕");
        processdingJoinPoint.proceed();  //调用目标方法
    }

重点: 参数为ProceedingJoinPoint processdingJoinPoint
processdingJoinPoint.proceed()如果在环绕通知中不写,则目标方法不再执行
即环绕通知可以控制目标方法执行
写完各种通知,我们来看一下在配置文件中怎么配置aop和通知:
首先修改配置文件的文件头,加入ao依赖的xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/aop 
           http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

配置Bean:

扫描二维码关注公众号,回复: 2806295 查看本文章

<bean id = "personDao" class="com.my.spring.aop.xml.PersonImpl"></bean>
<!--  切面(事务)-->
<bean id = "transcation" class="com.my.spring.aop.xml.Transcation"></bean>

然后开始配置aop:
利用<aop:config>标签进行配置;

<aop:config>
        <!-- 
            切入点表达式 作用:确定目标类 
         --> 
        <aop:pointcut expression="execution(* com.my.spring.aop.xml.PersonImpl.*(..))"
         id="perform"/>
         <!-- ref指向的就是切面 -->
         <aop:aspect ref="transcation">
            <!-- 前置通知     
                    1.在目标方法执行前执行
                    2.获取不到目标方法的返回值-->
            <aop:before method="beginTranscation" pointcut-ref="perform"/>
            <!-- 后置通知:
                    1.后置通知可以获取到目标方法的返回值
                    2.当目标方法抛出异常,后置通知将不再执行 -->

            <aop:after-returning method="commit" pointcut-ref="perform" returning="val"/>
            <!-- 最终通知 
                    无论目标方法是否抛出异常,都将执行
            -->
            <aop:after method="finallyMethod" pointcut-ref="perform"/>

            <!-- 异常通知
                    接收目标方法抛出的异常
             -->
             <aop:after-throwing method="thorwingMethod" throwing="ex" pointcut-ref="perform"/>
            <!-- 环绕通知 (把前置,后置注释了)
                控制目标方法的执行。processdingJoinPoint.proceed();
                前置通知和后置通知能在目标方法的前面和后面加一些代码,但是不能控制目标方法的执行
            -->
            <aop:around method="aroundMethod" pointcut-ref="perform"/>
         </aop:aspect>
    </aop:config>

我们可能会对

<aop:pointcut expression="execution(* com.my.spring.aop.xml.PersonImpl.*(..))"

产生疑问,这的execution的代码是怎么写的呢?)这句话的主要目的是为了明确目标类,即我们的切面对那些类起作用,那么它的书写格式是什么呢?
下面我们举一些例子来看一下书写的规范:(引用一下其他老师的例子)
这里写图片描述

测试类:

public class TranscationText {
    public void textTranscation() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        PersonDao personDao = (PersonDao) applicationContext.getBean("personDao");
        personDao.savePerson();
    }
    public static void main(String[] args) {
        TranscationText text = new TranscationText();
        text.textTranscation();
    }
}

下面我们来说一下aop的执行原理:
1.当Spring容器启动时候,加载两个bean,对两个bean进行实例化。
2.当spring容器解析配置文件到<aop:config>
3.把切入点表达式解析出来,按照切入点表达式匹配sprin容器内部的bean
4.如果匹配成功,则为该bean创建代理对象。匹配不成功报错
5.当客户端getBean获取一个对象时,如果该对象有代理对象,则返回代理对象。
如果没有代理对象,返回代理对象本身。
为了更好理解aop,我们需要写更多的例子,来深入理解,毕竟aop是spring的核心,我还有好几个关于aop的例子,大家有兴趣可以评论留下你的邮箱。我会给你发需求和例子,在这就不多啰嗦了

猜你喜欢

转载自blog.csdn.net/qq_39411208/article/details/81603851