Spring-AOP 使用@AspectJ

举报
小工匠 发表于 2021/09/10 01:38:58 2021/09/10
【摘要】 概述准备工作实例 通过编码的方式使用AspectJ切面通过配置的方式使用AspectJ切面 自动生成代理的方式基于Schema的aop命名空间配置的方式 概述 我们...

概述

我们之前一个系列的文章,分别使用Pointcut和Advice接口描述切点和增强,并用Advisor整合二者描述切面,@AspectJ则采用注解来描述切点、增强,二者只是表述方式不同,描述内容的本质是完全相同的。


准备工作

  • 在使用@AspectJ之前,必须确保使用的Java5.0以及以上的版本,否则无法使用注解。

  • Spring在处理@AspectJ注解表达式时,需要将Spring的asm模块添加到类路径中。asm是轻量级的字节码处理框架,因为Java的反射机制无法获取入参名,Spring就利用asm处理@AQspectJ中所描述的方法入参名

  • 如果是maven工程,需要在pom.xml添加aspectj.weaver和aspectj.tools类包的依赖。

<!-- asm/cglib依赖(spring依赖) -->
        <dependency>
            <groupId>org.ow2.asm</groupId>
            <artifactId>asm</artifactId>
            <version>${asm.version}</version>
        </dependency>
        <dependency>
            <groupId>org.ow2.asm</groupId>
            <artifactId>asm-util</artifactId>
            <version>${asm.version}</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>${cglib.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>asm</artifactId>
                    <groupId>org.ow2.asm</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>${aspectj.version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>${aspectj.version}</version>
        </dependency>
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>${aopalliance.version}</version>
        </dependency>
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>${commons-codec.version}</version>
        </dependency>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

实例

代码已托管到Github—> https://github.com/yangshangwei/SpringMaster

通过编码的方式使用@AspectJ切面

@AspectJ采用不同的方式对AOP进行描述。

我们依旧采用我们一直使用的服务生的例子

这里写图片描述

package com.xgj.aop.spring.advisor.aspectJ.aspectJByCode;

public class NaiveWaiter implements Waiter {

    @Override
    public void greetTo(String name) {
        System.out.println("NaiveWaiter Greet To " + name);
    }

    @Override
    public void serverTo(String name) {
        System.out.println("NaiveWaiter Server To " + name);
    }

}
  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

下面使用@AspectJ注解定义一个切面

package com.xgj.aop.spring.advisor.aspectJ.aspectJByCode;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

/**
 * 
 * 
 * @ClassName: PreGreetingAspect
 * 
 * @Description: 切面类
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年8月24日 下午3:21:15
 */

// 通过@Aspect将PreGreetingAspect标注为一个切面
@Aspect
public class PreGreetingAspect {

    // 定义切点和增强类型
    @Before("execution(* greetTo(..))")
    public void beforeGreeting() {// 增强的横切逻辑
        System.out.println("How are you ?");
    }
}
  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

从上述代码中,我们可以看到这个切面没有实现任何特殊的接口,它只是一个普通的POJO,特殊之处在于使用了@AspectJ注解。

首先,在PreGreetingAspect类定义出标注了@AspectJ注解,这样,第三方处理程序就可以通过类是否拥有@AspectJ注解来判断其是否是一个切面。

其次,在beforeGreeting()方法处标注了@Before注解,并未改注解提供了成员值“execution(* greetTo(..))”

@Before(“execution(* greetTo(..))”)注解提供了两个信息: @Before注解白该增强是前置增强,而成员值是一个@AspectJ切点表达式。 意思为:在目标类的greetTo方法上织入增强,greetTo()方法可以带带任意的入参和任意的返回值。

最后beforeGreeting()方法是增强说是所使用的横切逻辑,该横切逻辑在目标方法前调用。

我们通过下图来先看下这种关系 《切面的信息构成》

这里写图片描述

PreGreetingAspect类通过注解和代码,将切点、增强类型和增强的横切逻辑柔和到一个类中,使切面的定义浑然天成。 其实相当于我们之前说的BeforeAdivce、NameMatchMethodPoincut和DefaultPointcutAdvisor三者联合表达的信息。

下面我们通过AspectProxyFactory为NaiverWaiter生成织入PreGreetingAspect切面的代码

package com.xgj.aop.spring.advisor.aspectJ.aspectJByCode;

import org.junit.Test;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;

/**
 * 
 * 
 * @ClassName: PreGreetingAspectTest
 * 
 * @Description:
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年8月24日 下午3:21:29
 */
public class PreGreetingAspectTest {

    @Test
    public void test() {
        // 目标类
        Waiter target = new NaiveWaiter();
        // 实例化切面代理工厂
        AspectJProxyFactory aspectJProxyFactory = new AspectJProxyFactory();
        // 设置目标对象
        aspectJProxyFactory.setTarget(target);
        // 添加切面类
        aspectJProxyFactory.addAspect(PreGreetingAspect.class);
        // 生成织入切面的代理对象
        Waiter proxy = aspectJProxyFactory.getProxy();
        // 调用业务方法
        proxy.greetTo("XiaoGongJiang");
        proxy.serverTo("XiaoGongJiang");
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

运行结果

How are you ?
NaiveWaiter Greet To XiaoGongJiang
NaiveWaiter Server To XiaoGongJiang
  
 
  • 1
  • 2
  • 3

从输出结果,我们可以知道代理对象的greetTo()方法已经被织入了切面类所定义的增强逻辑。


通过配置的方式使用@AspectJ切面

虽然可以通过编程的方式织入切面,但是一般情况下,我们都是通过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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- 通过配置使用@AspectJ -->

<!-- 目标Bean -->
<bean id="waiter" class="com.xgj.aop.spring.advisor.aspectJ.aspectJByConf.NaiveWaiter"/>
<!-- 使用了@AspectJ注解的切面类 -->
<bean class="com.xgj.aop.spring.advisor.aspectJ.aspectJByConf.PreGreetingAspect"/>
<!-- 自动代理创建器,自动将@AspectJ注解切面类织入目标Bean中 -->
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>

</beans>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

测试:

package com.xgj.aop.spring.advisor.aspectJ.aspectJByConf;

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

/**
 * 
 * 
 * @ClassName: PreGreetingAspectTest
 * 
 * @Description:
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年8月24日 下午3:21:29
 */
public class PreGreetingAspectTest {

    @Test
    public void test() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext(
                "classpath:com/xgj/aop/spring/advisor/aspectJ/aspectJByConf/conf-aspectJ.xml");

        Waiter naiveWaiter = ctx.getBean("waiter", Waiter.class);

        naiveWaiter.greetTo("XiaoGongJiang");
        naiveWaiter.serverTo("XiaoGongJiang");
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

运行结果:

2017-08-24 17:29:48,644  INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@24177697: startup date [Thu Aug 24 17:29:48 BOT 2017]; root of context hierarchy
2017-08-24 17:29:48,754  INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/aop/spring/advisor/aspectJ/aspectJByConf/conf-aspectJ.xml]
How are you ?
NaiveWaiter Greet To XiaoGongJiang
NaiveWaiter Server To XiaoGongJiang

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

基于Schema的aop命名空间配置的方式

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

<!-- 使用基于Schema的aop命名空间进行配置 -->


<!-- 基于@AspectJ切面的驱动器 -->
<aop:aspectj-autoproxy/>

<!-- 目标Bean -->
<bean id="waiter" class="com.xgj.aop.spring.advisor.aspectJ.aspectJByConf.NaiveWaiter"/>
<!-- 使用了@AspectJ注解的切面类 -->
<bean class="com.xgj.aop.spring.advisor.aspectJ.aspectJByConf.PreGreetingAspect"/>

</beans>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

首先在配置文件中引入aop的命名空间;然后通过aop命名空间的<aop:aspectj-atuoproxy/>自动为Spring容器中哪些匹配@AspectJ切面的bean 创建代理,完成切面织入。

当然了,Spring在内部依旧使用AnnotationAspectJAutpProxyCreator进行自动代理的创建工作,但具体的实现细节被<aop:aspectj-atuoproxy/>隐藏起来了。

<aop:aspectj-atuoproxy/>有一个proxy-target-class属性,默认为false,标识使用JDK动态代理技术织入增强。 当配置 <aop:aspectj-autoproxy proxy-target-class="true"/>表示使用CGLib动态代理技术织入增强。

不过即使 proxy-target-class设置为false,如果目标类没有声明接口,Spring将自动使用CGLib动态代理

测试

package com.xgj.aop.spring.advisor.aspectJ.aspectJByConf;

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

public class PreGreetingAspectSchemaTest {
    @Test
    public void test() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext(
                "classpath:com/xgj/aop/spring/advisor/aspectJ/aspectJByConf/conf-aspectJ_schema.xml");

        Waiter naiveWaiter = ctx.getBean("waiter", Waiter.class);

        naiveWaiter.greetTo("XiaoGongJiang");
        naiveWaiter.serverTo("XiaoGongJiang");
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

运行结果

2017-08-24 17:30:28,141  INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@24177697: startup date [Thu Aug 24 17:30:28 BOT 2017]; root of context hierarchy
2017-08-24 17:30:28,244  INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/aop/spring/advisor/aspectJ/aspectJByConf/conf-aspectJ_schema.xml]
How are you ?
NaiveWaiter Greet To XiaoGongJiang
NaiveWaiter Server To XiaoGongJiang

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

通过输出结果,我们可以看到实现了同样的效果。

文章来源: artisan.blog.csdn.net,作者:小小工匠,版权归原作者所有,如需转载,请联系作者。

原文链接:artisan.blog.csdn.net/article/details/77519375

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。