面向切面编制程序,SSH框架之旅

2019-05-12 16:31 来源:未知

Spring AOP 又称 面向切面编程,要实现AOP就要有切点,增强,织入,连接点,切面...

最近在学习AOP,之前一直很不明白,什么是AOP?为什么要使用AOP,它有什么作用?学完之后有一点小小的感触和自己的理解,所以在这里呢就跟大家一起分享一下

图片 1

增强又分为:前置增强,后置增强,异常抛出增强,环绕增强,后置增强,最终增强

编写配置文件中的增强代码之前我们先创建一个增强类,用于存放增强的代码:  

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;


public class UserAdvice {
    private Logger log=Logger.getLogger(UserAdvice.class);
    //前置增强
    public void before(JoinPoint j)
    {
        String methodName=j.getSignature().getName();
        String className=j.getTarget().getClass().getName();
        log.info(className "类" methodName "方法的前置增强");
    }
    //异常抛出增强
    public void afterThrowing(JoinPoint j,Exception e)
    {
        String methodName=j.getSignature().getName();
        String className=j.getTarget().getClass().getName();
        log.info(className "类" methodName "方法异常:" e.getMessage());
    }
    //后置增强
    public void afterreturning(JoinPoint j)
    {
        String methodName=j.getSignature().getName();
        String className=j.getTarget().getClass().getName();
        log.info(className "类" methodName "方法的后置增强");
    }
    //最终增强
    public void after(JoinPoint j){
        String methodName=j.getSignature().getName();
        String className=j.getTarget().getClass().getName();
        log.info(className "类" methodName "方法的最终增强");
    }
    //环绕增强
    public Object around(ProceedingJoinPoint j)
    {
        Object resoult=null;
        log.info("环绕前");
        try {
            resoult=j.proceed();
            log.info("环绕后");
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return resoult;
    }
} 

  配置文件中:

<!--创建增强类的bean-->
<bean id="adv" class="cn.bdqn.dao.UserAdvice"></bean>
    <aop:config>
    <!--定义切点 expression允许使用的范围-->
        <aop:pointcut expression="execution(* cn.bdqn.service..*.*(..))" id="p1"/>
     <!--引用增强类-->
        <aop:aspect ref="adv">
       <!--method对应的是增强类中对应的方法,pointcut-ref对应的是切点-->
            <aop:before method="before" pointcut-ref="p1" /><!--前置增强 在方法执行前执行-->
       <!--后置增强 在方法执行完执行-->
            <aop:after-returning method="afterreturning" pointcut-ref="p1"/>
       <!--异常抛出增强 在方法执行处错误时执行-->
            <aop:after-throwing method="afterThrowing" pointcut-ref="p1" throwing="e"/>
       <!--最终增强 无论方法是否出现异常都会执行-->
            <aop:after method="after" pointcut-ref="p1"/>
       <!--环绕增强 在方法执行前和方法执行后执行-->
            <aop:around method="around" pointcut-ref="p1"/>
        </aop:aspect>
    </aop:config>

  

  

 

  

    

 

AOP(Aspect-Oriented Programming)其实是OOP(Object-Oriented Programing) 思想的补充和完善。我们知道,OOP引进"抽象"、"封装"、"继承"、"多态"等概念,对万事万物进行抽象和封装,来建立一种对象的层次结构,它强调了

spring.jpg

一种完整事物的自上而下的关系。但是具体细粒度到每个事物内部的情况,OOP就显得无能为力了。比如日志功能。日志代码往往水平地散布在所有对象层次当
中,却与它所散布到的对象的核心功能毫无关系。对于其他很多类似功能,如事务管理、权限控制等也是如此。这导致了大量代码的重复,而不利于各个模块的重
用。   而AOP技
术则恰恰相反,它利用一种称为"横切"的技术,能够剖解开封装的对象内部,并将那些影响了多个类并且与具体业务无关的公共行为 封装成一个独立的模块(称
为切面)。更重要的是,它又能以巧夺天功的妙手将这些剖开的切面复原,不留痕迹的融入核心业务逻辑中。这样,对于日后横切功能的编辑和重用都能够带来极大
的方便。    AOP技术的具体实现,无非也就是通过动态代理技术或者是在程序编译期间进行静态的"织入"方式。下面是这方面技术的几个基本术语:    

1.Spring 中的 bean 管理(注解方式)


1、join point(连接点):是程序执行中的一个精确执行点,例如类中的一个方法。它是一个抽象的概念,在实现AOP时,并不需要去定义一个join point。    

1.1 使用注解创建对象

Spring 创建对象可以使用配置 xml 文件的方式,也可以使用注解来创建对象,更加的简单。这就需要另外引入一个 spring-aop 的 jar 包,还要在配置文件中加上相对应的约束。

示例代码如下:

实体类

加上注解,@Component(value="student") 注解就相当于之前用配置 <bean id="student" class="..."/>

创建对象有四个注解,另外三个注解 @controller@Service@Repository 都是 @Component 的衍生注解,它们在功能上是一样的,都是创建对象。从名称上也可以看出注解有划分要标注的类的用途,@Component 用于一般的实体类,@controller 用于 Web 层,@Service 用于 业务逻辑层,@Repository 用于数据持久层。

另外,创建对象是单实例还是多实例也是可以使用注解,只需要在类上加上 @Scope(value="prototype") 就可以创建多实例的对象。

    package cc.wenshixin.entity;

    import org.springframework.stereotype.Component;

    @Component(value="student")
    public class Student {
        public void study(){
            System.out.println("学习中。。。");
        }
    }

配置文件

在约束配置要加上 xmlns:context="http://www.springframework.org/schema/context"http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd

开启注解扫描,可以到包中扫描类、方法、属性上是否有注解。

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

  <!-- 开启注解扫描 -->
  <context:component-scan base-package="cc.wenshixin"></context:component-scan>
</beans>

测试方法

package cc.wenshixin.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cc.wenshixin.entity.Student;

public class Test1 {

    @Test
    public void test01()
    {
        //1.加载spring的配置文件,根据配置文件来创建对象
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        //2.得到通过注解创建的对象
        Student s = (Student) context.getBean("student");
        s.study();
    }

}

2、point cut(切入点):本质上是一个捕获连接点的结构。在AOP中,可以定义一个point cut,来捕获相关方法的调用。    

1.2 使用注解注入属性

创建 service 类和创建 dao 类,在 service 中得到 dao 类的对象。

dao 类

    package cc.wenshixin.dao;

    import org.springframework.stereotype.Repository;

    @Repository(value="dao")
    public class Dao {
        public void insert()
        {
            System.out.println("插入数据。。。");
        }
    }

service 类

使用注解方式来注入属性,有两种方式,并且两种方式都不要需要在 dao 中添加 set 方法。

package cc.wenshixin.service;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cc.wenshixin.dao.Dao;

@Service(value="service")
public class StudentService {
    //第一种方式
    /*@Autowired
    private Dao dao;*/

    //第二种方式
    //name属性值写创建 dao 对象时注解中的 value 值
    @Resource(name="dao")
    private Dao dao;

    public void add()
    {
        System.out.println("添加操作。。。");
        dao.insert();
    }
}

测试方法

package cc.wenshixin.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cc.wenshixin.entity.Student;
import cc.wenshixin.service.StudentService;

public class Test1 {

    @Test
    public void test01()
    {
        //1.加载spring的配置文件,根据配置文件来创建对象
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        //2.得到通过注解创建的对象
        StudentService service = (StudentService) context.getBean("service");
        service.add();
    }
}

3、advice(通知):是point cut的执行代码,是执行“方面”的具体逻辑。 

1.3 配置方式和注解方式的混合使用

在开发中,经常 xml 配置文件方式和注解方式混合使用,创建对象使用配置文件,而属性注入使用注解方式。xml 配置方式结构清晰,注解方式方便属性注入。

Spring 中 bean 管理方式的比较

xml配置 注解配置
bean 定义 <bean id="" class=""/> @Component,@Respository,@Service,@Controller
bean 名称 通过id或者name指定 @Component("student"),单个value值,value可以省略
bean 注入 <property>或者通过p命名空间 @Autowired 按类型注入,@Resource(name="")

示例代码如下:

dao 类

package cc.wenshixin.dao;

public class TeacherDao {
    public void insert()
    {
        System.out.println("添加老师。。。");
    }
}

package cc.wenshixin.dao;

public class StudentDao {
    public void insert()
    {
        System.out.println("添加学生。。。");
    }
}

service 类

package cc.wenshixin.service;

import javax.annotation.Resource;
import cc.wenshixin.dao.StudentDao;
import cc.wenshixin.dao.TeacherDao;

public class Service {
    @Resource(name="teacherDao")
    private TeacherDao teacherDao;
    @Resource(name="studentDao")
    private StudentDao studentDao;

    public void add()
    {
        System.out.println("添加操作。。。");
        teacherDao.insert();
        studentDao.insert();
    }
}

配置文件

<?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.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
  <!-- 配置对象 -->
  <bean id="service" class="cc.wenshixin.service.Service"></bean>
  <bean id="teacherDao" class="cc.wenshixin.dao.TeacherDao"></bean>
  <bean id="studentDao" class="cc.wenshixin.dao.StudentDao"></bean>

  <!-- 开启注解扫描 -->
  <context:component-scan base-package="cc.wenshixin"></context:component-scan>
</beans>

测试方法

package cc.wenshixin.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cc.wenshixin.service.Service;

public class Test1 {
    @Test
    public void test()
    {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        Service service = (Service) context.getBean("service");
        service.add();
    }
}

4、aspect(切面):point cut和advice结合起来就是aspect,它类似于OOP中定义的一个类,但它代表的更多是对象间横向的关系。   

2.Spring 中的 AOP


 

2.1 AOP 完整概述

AOP,全名 Aspect Oriented Programming,面向切面编程,在 Struts2 的拦截器中已经提到过 AOP,时通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术,扩展功能而不修改源代码,如:权限校验、日志记录、性能监控、事务控制。AOP采取横向抽取机制,取代了传统纵向继承体系的重复代码。AOP 解决 OOP(面向对象编程) 中遇到的一些问题,是 OOP 的延续和扩展。

底层的动态代理机制有两种:

    1. 有接口,JDK的动态代理,针对实现接口的类产生代理,生成接口实现类对象。
    1. 没有接口,Cglib的动态代理,应用的是底层的字节码增强技术,生成当前类的子类对象。

说了这么多,可能我们还是对AOP有点不知所措,不知道是干什么的,那么我们就以一个例子作为讲解,来理解这个抽象的概念

2.2 AOP 的底层原理

纵向抽取机制

图片 2

传统方式.png

横向抽取机制

图片 3

有接口.png

图片 4

无接口.png

我们有一个简易的计算器,进行加减乘除的操作,有一个需求,1.需要在进行算法之前和之后进行输出一句话

2.3 AOP 操作的相关术语

  • Joinpoint(连接点):类里面可以被增强的方法,这些方法就称为是连接点。
  • Pointcut(切入点):切入点是指要对连接点进行拦截。在一个类里面可以有很多的方法被增强,比如实际操作中,只是增强了类里面的 add 方法和 update 方法,实际增强的方法就称为是切入点。
  • Advice(通知/增强):通知是指拦截到 Joinpoint 之后要做的事情就是通知,通知又分为前置通知、后置通知、异常通知,最终通知、环绕通知(切面要完成的功能)。要增强的逻辑功能称为是增强,比如扩展日志功能,这个日志功能就成为是通知或者是增强。前置通知:在增强的方法之前执行;后置通知:在增强的方法之后执行;异常通知:方法出现异常时;最终通知:在后置之后执行;环绕通知:在方法之前和之后执行。
  • Aspect(切面):切入点和通知(引介)的结合。把增强应用到具体方法上面的过程称为切面。把增强用到切入点过程。
  • Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下,Introduction 可以在运行期为类动态地添加一些方法或 Field。
  • Target(目标对象):代理的目标对象(要增强的类)。
  • Weaving(织入):是把增强应用到目标的过程,也即是把 advice 应用到 target 的过程。
  • Proxy(代理):一个类被 AOP 织入增强后就产生一个结果代理类。

图片 5

2.4 AOP 的实际操作

在 Spring 中进行 AOP 操作使用 Aspectj 实现的,Aspectj 不是 Spring 的一部分,和 Spring 一起使用 AOP 操作。
使用 Aspectj 实现 AOP 也有两种方式:

  • 1.基于 Aspectj 的xml配置
  • 2.基于 Aspectj 的注解方式

除了上面的 jar 包之外,还需要导入 Aspectj 的相关 jar 包 Aspectjweaver.jar 下载地址,aopalliance.jar,这个在 Struts2 的lib中有,spring-aop.jarspring-aspects.jar

那么对于以上操作我们可能最容易想到的就是用一个实现类实现这个接口。然后在接口调用方法前后输出一句话

2.4.1 配置文件方式

实体类

package cc.wenshixin.entity;

public class Student {
    public void study()
    {
        System.out.println("学习中。。。");
    }
}

增强类

package cc.wenshixin.entity;

import org.aspectj.lang.ProceedingJoinPoint;

public class StrengthStudent {
    public void beforeStudy()
    {
        System.out.println("前置增强。。。");
    }

    public void afterStudy()
    {
        System.out.println("后置增强。。。");
    }

    //环绕通知
    public void aroundStudy(ProceedingJoinPoint proceedingJoinPoint) throws Throwable
    {
        //方法之前执行
        System.out.println("方法之前。。。");
        //执行被增强的方法
        proceedingJoinPoint.proceed();
        //方法之后执行
        System.out.println("方法之后。。。");
    }
}

配置文件

aspectj配置常用的表达式
execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)

  • 1.execution(* cc.wenshixin.entity.Student.add(..))
  • 2.execution(* cc.wenshixin.entity.Student.*(..))
  • 3.execution(* *.*(..))

*注意:第一个和后面的路径有一个空格,后面的括号中是两个点,不是三个点

<?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="student" class="cc.wenshixin.entity.Student"></bean>
  <bean id="strengthStudent" class="cc.wenshixin.entity.StrengthStudent"></bean>
  <!-- 2.配置 AOP 操作 -->
  <aop:config>
    <!-- 2.1 配置切入点 -->
    <aop:pointcut expression="execution(* cc.wenshixin.entity.Student.*(..))" id="pointCut"/>
    <!-- 2.2 配置切面把增强用到方法上面 -->
    <aop:aspect ref="strengthStudent">
      <aop:before method="beforeStudy" pointcut-ref="pointCut"/>
      <aop:after-returning method="afterStudy" pointcut-ref="pointCut"/>
      <aop:around method="aroundStudy" pointcut-ref="pointCut"/>
    </aop:aspect>
  </aop:config>
</beans>

测试方法

package cc.wenshixin.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cc.wenshixin.entity.Student;

public class Test1 {
    @Test
    public void test()
    {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        Student s = (Student) context.getBean("student");
        s.study();
    }
}

图片 6

2.4.2 注解方式

实体类同上

增强类
Aspectj 的 AOP 注解

  • @Aspect:定义切面增强类的注解
  • 通知(增强)类型
    • @Before:前置通知
    • @AfterReturing:后置通知
    • @Around:环绕通知
    • @AfterThrowing:异常抛出通知
package cc.wenshixin.entity;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class StrengthStudent {
    @Before(value="execution(* cc.wenshixin.entity.Student.*(..))")
    public void beforeStudy()
    {
        System.out.println("前置增强。。。");
    }
    @After(value="execution(* cc.wenshixin.entity.Student.*(..))")
    public void afterStudy()
    {
        System.out.println("后置增强。。。");
    }

    //环绕通知
    @Around(value="execution(* cc.wenshixin.entity.Student.*(..))")
    public void aroundStudy(ProceedingJoinPoint proceedingJoinPoint) throws Throwable
    {
        //方法之前执行
        System.out.println("方法之前。。。");
        //执行被增强的方法
        proceedingJoinPoint.proceed();
        //方法之后执行
        System.out.println("方法之后。。。");
    }
}

配置文件

<?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="student" class="cc.wenshixin.entity.Student"></bean>
  <bean id="strengthStudent" class="cc.wenshixin.entity.StrengthStudent"></bean>
  <!-- 2.开启AOP操作 -->
  <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

测试方法同上

这样确实能实现这个需求,但是可能有的同学就想到了,是不是重复代码了呢?如果我有上千个方法呢?是不是还得在每个方法里增加几行代码?我们能不能在不改变原来方法的结构上

3. 其他概念


也能实现相同的需求呢?这个时候AOP就能帮我们实现了。下面我们详细的讲解下如何使用注解的方式来实现AOP

3.1 log4j 的介绍

log4j 是一个日志包,通过 log4j 可以看到程序运行过程中更详细的信息,查看日志。使用时需要导入 log4j 的 jar 包,下载位置,并复制 log4j 的配置文件 log4j.properties 到 src 目录。

log4j.properties文件中的内容

log4j.rootLogger 用来设置日志的级别,info可以看到基本信息,debug可以看到更详细的信息。

#
# Log4J Settings for log4j 1.2.x (via jakarta-commons-logging)
#
# The five logging levels used by Log are (in order):
#
#   1. DEBUG (the least serious)
#   2. INFO
#   3. WARN
#   4. ERROR
#   5. FATAL (the most serious)


# Set root logger level to WARN and append to stdout
log4j.rootLogger=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

# Pattern to output the caller's file name and line number.
log4j.appender.stdout.layout.ConversionPattern=%d %5p (%c:%L) - %m%n

还是同样的接口和实现类,只是这时候实现类中没有了输出语句,如图

图片 7

上图就是最原始的方法了,也就是说我们在这个方法里面只需要关注我们方法执行的内容,并不需要关注一些方法之外的东西,比如说记录日志,方法前输出语句等等。。

那么,既然这个方法什么都不关注的话,那我们的输出语句又在哪儿写呢?这个时候我们就定义一个专门的类,用它来作为切面,代码如下所示

package advice;

import java.util.Arrays;
import java.util.List;

import org.aspectj.lang.JoinPoint;
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.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;


@Aspect    //声明注解
public class CalculationAnnotation {

    /**
     * 定义前置通知
     * execution(* biz.UserBiz.*(..)) 表示  所有修饰符的所有返回值类型  biz.UserBiz 包下的所有方法
     * 在方法执行之前执行
     * */
    @Before("execution(* biz.CalculationImpl.*(..))")
    public void before(JoinPoint join){
        //获取方法名
        String mathName=join.getSignature().getName();
        //获取参数列表
        List<Object> args = Arrays.asList(join.getArgs());

        System.out.println("前置通知---->before   方法名是:" mathName "t参数列表是:" args);
    }

    /**
     * 后置通知
     * 在方法返回后执行,无论是否发生异常
     * 不能访问到返回值
     * 
     * */
    @After("execution(* biz.CalculationImpl.*(..))")
    public void after(){
        System.out.println("后置通知---->after....");
    }
}

 

@Aspect ----->表示声明这个类是一个切面,

图片 8

这样呢,咱们这个切面就声明完毕了,那么,我们可以想到,这个时候我们只是声明了一个切面而已,并没有在那个地方用到这个切面对不对?也就是说我们配置的切面还跟我们程序还没有任何的关联关系

这样的话呢,就引出了我们的配置文件了也就是我们Spring的配置文件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-3.0.xsd
        ">



      <!-- 配置Bean -->
     <bean id ="CalculationImpl" class="biz.CalculationImpl"></bean>


     <!-- 将切面类交与Spring容器管理 -->
     <bean class="advice.CalculationAnnotation"></bean>


      <!-- 使用注解自动生成代理对象 -->
      <aop:aspectj-autoproxy/>


</beans>  

 

这个时候我们可以看看配置文件里到底写了什么,写这些是干啥的,有什么用。

图片 9

这个大家肯定都懂是吧,这没话说,也就是将CalculationImpl类交给Spring容器来管理,如果有不懂的童鞋可以看看我的另一篇关于Spring  IOC 的文章

图片 10

那么这行代码呢?这行代码的意思就是将我们的CalculationAnnotation类交给Spring容器管理,因为我们在CalculationAnnotation类中不是声明了一个@Aspect切面注解吗对不对

当Spring容器初始化的时候它会找有没有图片 11这个节点,如果有的话呢,容器就会根据你的Bean配置,找看那个类中配置了@Aspect切面注解

如果找到了的话那么就根据你的注解来执行相应的代码,什么意思呢?比如说如图所示

图片 12

好,那么我们就来看看执行之后结果会是怎样的呢?

图片 13

这样我们是不是就完成了之前的需求呢?在执行代码前输出一行语句,如果我们想要做到日志的记录的话,是不是只需要把输出语句修改为记录日志的代码就可以了呢。而且我还没有影响任何的功能性代码

也就是对源代码并没有做任何的修改,那么既然有前置增强的话肯定也有后置增强和其他增强操作下面我就讲讲后置增强,

其实对于其他的增强类型的话呢,既然知道前置增强是怎么一回事了,那么其他四种就轻而易举了

后置增强,其实我们只需要在切面类也就是我们写前置增强的类中直接添加后置 增强代码即可,如图

图片 14

只是将注解标签给进行了一道修改,其他的任何操作我们都不需要在进行修改,示例结果如图所示

图片 15

这样是不是就完成了在方法前后执行与方法无关的代码呢?可能有些童鞋有疑问,为什么输出语句是在最后输出的,不应该是夹在中间吗?但是我们看测试代码,我是执行了add方法,接收了一个返回值,然后在方法的外面输出的我接收的返回值变量,那么这样的话,可不就是我们看到的结果嘛。

由于时间的关系呢,我今天就先给大家分享下前置增强和后置增强。至于返回,异常和环绕的话呢,我就下次在跟大家分享吧!希望大家能够学到点东西吧!

 

TAG标签: 韦德娱乐1946
版权声明:本文由韦德娱乐1946_韦德娱乐1946网页版|韦德国际1946官网发布于韦德娱乐1946网页版,转载请注明出处:面向切面编制程序,SSH框架之旅