Spring框架(六)SpringAOP的介绍,Aspectj方式实现,注解方式

2021-07-08 15:05:52 浏览数 (1)

目录

  • SpringAOP的Aspectj方式实现
    • 前提
    • 之前的方式有问题:
    • 解决:
    • 实现:
    • 使用
  • Acspectj和SchemaBased的异同
    • 1. 相同点:
    • 2. 不同点:
  • SpringAOP的切点的声明格式
  • 注解
    • ① @Component
    • ② @Service
    • ③ @pointcut
    • ④ @Aspect
    • ⑤ @Before
    • ⑥ @After
    • ⑦ @Around
    • ⑧ @AfterThrowing

SpringAOP的Aspectj方式实现

前提

实现功能的扩展,可以在springAop下有一个这个方式进行实现。这个就是Aspectj.

之前的前置通知那些操作,就是SchemaBase方式实现功能的扩展。 现在也是实现功能的扩展,只是用不同的方式,现在的方式是Aspectj。

之前的方式有问题:

目前我们已经能够使用SpringAOP的SchemaBased方式来实现功能扩展。在使用SchemaBased方式实现功能扩展时,发现一个扩展代码就需要声明对应的实现了指定的接口的类,这样造成代码的结构体系过于繁杂。一个通知一个类。

解决:

在一个类中声明所有的通知方法。这样又会造成Spring容器无法区分该类中的方法那些是前置,那些是后置,那些是环绕,那些是异常了,怎么办?在配置文件中的切面配置中,指明哪些方法是前置,哪些是后置即可。

实现:

SpringAOP的AspectJ方式

SpringAOP的SchemaBased方式来实现功能扩展,需要使用接口,spring容器是需要通过接口才可以知道哪些是前置通知,哪些是后置通知。

现在使用Aspectj这个方式,我们就可以直接在xml里面告诉spring容器,哪些是前置通知,哪些是后置通知。

使用

我们现在就可以将很多的通知都写在一个类里面,并且不需要继承其他的接口。

将这个类需要在xml里面进行配置,并且需要在配置规则里面告诉spring容器,哪些是前置,哪些是后置。

代码语言:javascript复制
public class MyAdvice {
    //前置通知
        public void before(String name,int age){
            System.out.println("我是前置通知" name age);
        }
    /*//后置通知
        public void after(){
            System.out.println("我是后置通知");
        }
    //环绕通知

参数必须是这样,这个是给spring看的
        public void myRound(ProceedingJoinPoint pp) throws Throwable {
            //环绕前
            System.out.println("环绕-前");
            //放行
            Object proceed = pp.proceed();
            //环绕后
            System.out.println("环绕-后");
        }
    //异常通知
        public void myThrow(Exception ex){
            System.out.println("我是异常通知:" ex.getMessage());
        }*/
代码语言:javascript复制
    <!--配置学生的bean-->
        <bean id="stu" class="com.pojo.Student"></bean>
        <!--配置通知bean-->
        <bean id="advice" class="com.advice.MyAdvice"></bean>
        <!--配置组装规则-->
        <aop:config>
ref这个属性就是告诉从哪一个类里面找方法
            <aop:aspect ref="advice"><!--声明通知bean的ID-->
                <!--声明切点-->
                <aop:pointcut id="mp" expression="execution(* com.pojo.Student.testStudent(String,int)) and args(name,age)"/>
                <!--前置通知-->
                <aop:before method="before"  pointcut-ref="mp" arg-names="name,age"></aop:before>
                <!--&lt;!&ndash;后置通知&ndash;&gt;
                <aop:after-returning method="after" pointcut-ref="mp"></aop:after-returning>
                &lt;!&ndash;环绕通知&ndash;&gt;
                <aop:around method="myRound" pointcut-ref="mp"></aop:around>
                &lt;!&ndash;异常通知&ndash;&gt;
throwing写的是异常通知的形参名字
                <aop:after-throwing method="myThrow" pointcut-ref="mp" throwing="ex"></aop:after-throwing>-->
            </aop:aspect>
        </aop:config>

<aop:aspect是新的标签,在这个标签下面就可以进行写了

Acspectj和SchemaBased的异同

1. 相同点:

在不修改源码的情况下都能实现功能的扩展。

2. 不同点:

(1) SchemaBased方式基于接口来区别前置和后置和环绕和异常通知的,而AspectJ方式是在配置文件中使用标签来区分。

(2) AspectJ方式在配置中的配置方式发现其切点的声明以及对应的通知组装中,切点只在Aop:aspect标签下有效。而SchemaBased方式声明的切点在全局有效.SchemaBased的切点的通用性比AspectJ方式要好。

SpringAOP的切点的声明格式

① 切点是某包某类的无参数的方法: 示例:

代码语言:javascript复制
execution(* com.bjsxt.service.impl.Student.test())

② 切点是某包某类带有参数的方法 示例:

代码语言:javascript复制
execution(*                 com.bjsxt.service.impl.Student.test(String,int))

③ 切点是某包某类的某个同名的所有方法 示例:… 表示任意个数任意类型的参数

代码语言:javascript复制
execution(* com.service.impl.Student.test(..))

④ 切点是某包下的某类的所有方法 示例:*表示任意的类名,方法名,包名

代码语言:javascript复制
execution(* com.service.impl.Student.*(..))

⑤ 切点是某包下的所有类的所有方法 示例:* 表示任意的类名,方法名,包名

代码语言:javascript复制
execution(* com.service.impl.*.*(..))

注解

注意:

SpringAOP的注解方式实现是基于AspectJ方式的。

SchemaBased方式是没有的。

使用:

① 必须在applicationcontext.xml文件中声明注解的使用路径,方便Spring容器对象的扫描,提升扫描效率。

代码语言:javascript复制
<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属性是  哪一个包下面的文件需要走注解   多个包用逗号隔开
        <context:component-scan base-package="com.advice,com.pojo"></context:component-scan>
 


<!--配置AOP注解生效-->

        <aop:aspectj-autoproxy expose-proxy="true"></aop:aspectj-autoproxy>

① @Component

作用:

相当于配置文件的bean标签,将某个类的对象扫描到Spring容器中。此注解一般在普通Java类上用。

注意:

默认类名的首字母小写即为bean对象的ID,也可以使用注解

的value属性声明自定义的ID,value可以省略不写。

使用:

声明在类上。

② @Service

作用:

相当于配置文件的bean标签,将某个类的对象扫描到Spring容器 中。此注解专门在业务层实体类上使用来表明该类为业务类

注意:

默认类名的首字母小写即为bean对象的ID,也可以使用注解的 value属性声明自定义的ID,value可以省略不写。

③ @pointcut

作用:声明切点

使用:在切点方法上使用

④ @Aspect

作用:声明该类为通知类

使用:结合@Component在通知类上使用

⑤ @Before

作用:声明方法为前置通知方法

使用:在前置通知方法上声明

注意:需要在其中声明对应的切点的全限定路径

⑥ @After

作用:声明方法为后置通知方法

使用:在后置通知方法上声明

注意:需要在其中声明对应的切点的全限定路径

⑦ @Around

作用:声明方法为环绕通知方法

使用:在环绕通知方法上声明

注意:需要在其中声明对应的切点的全限定路径

⑧ @AfterThrowing

作用:声明方法为异常通知方法

使用:在异常通知方法上声明

注意:需要在其中声明对应的切点的全限定路径

注意:

需要在Spring的配置文件中声明AOP注解生效

0 人点赞