最简单的AOP程序

14 篇文章 0 订阅
12 篇文章 0 订阅

本文不涉及AOP原理,只是一些简单而完整的AOP程序的实例,包括如下几种环境:

  • AspectJ
  • Spring
  • Spring Boot

开发环境

  • 操作系统:Ubuntu 20.04
  • 开发工具:IntelliJ IDEA 2020.1.2 (Community Edition)
  • JDK:
➜  ~ java -version
openjdk version "14.0.1" 2020-04-14
OpenJDK Runtime Environment (build 14.0.1+7-Ubuntu-1ubuntu1)
OpenJDK 64-Bit Server VM (build 14.0.1+7-Ubuntu-1ubuntu1, mixed mode, sharing)

AspectJ的AOP支持

下载安装AspectJ

登录 http://www.eclipse.org/aspectj/ ,下载AspectJ,本例中下载的是 aspectj-1.9.6.jar

打开命令行,运行如下命令:

java -jar aspectj-1.9.6.jar

会显示一个安装对话框,按提示一步步往下走,直到最后安装AspectJ。

注:在对话框最后一步,会推荐为系统添加 CLASSPATH (指向 aspectjrt.jar )和 PATH (指向Aspect的 bin 目录),本例中添加了 PATH ,但是没添加 CLASSPATH ,所以要手工指定CLASSPATH。

使用AspectJ

先写一个最简单的Java程序 packageService/Test0816.java

package packageService;

public class Test0816
{
	public void doSth()
	{
		System.out.println("Test0816::doSth()");
	}
}

再写一个主程序来调用 Test0816doSth() 方法 packageMain/AspectJTest.java

package packageMain;

import packageService.Test0816;

public class AspectJTest
{
	public static void main(String[] args)
	{
		var test0816 = new Test0816();
		test0816.doSth();
	}
}

javac 命令编译:

javac packageMain/AspectJTest.java

会生成 AspectJTest.classTest0816.class 两个文件。

运行程序:

➜  temp0816 java packageMain.AspectJTest
Test0816::doSth()

可见方法被成功调用。

以上是一个入门级的Java “Hello World”程序,现在我们来添加AspectJ的AOP支持。

添加文件 packageAspect/MyAspect.java

package packageAspect;

public aspect MyAspect
{
	before(): execution(* packageService.*.*(..))
	{
		System.out.println("Hello Aspect");
	}
}

注意这不是一个Java类( aspect 不是Java的关键字,而是AspectJ的关键字)。

接下来用 ajc 命令来编译上面的几个Java文件:

➜  temp0816 ajc -cp ~/aspectj1.9/lib/aspectjrt.jar packageService/*.java packageMain/*.java packageAspect/*.java 
/home/ding/temp/temp0816/packageMain/AspectJTest.java:9 [error] var cannot be resolved to a type
var test0816 = new Test0816();


1 error

出错了, ajc 不识别 var 。可以把 var 改为 Test0816 ,或者编译时加上 -10 或者 -11 选项( var 是Java 10引入的):

ajc -11 -cp ~/aspectj1.9/lib/aspectjrt.jar packageService/*.java packageMain/*.java packageAspect/*.java

可以看到每个Java文件都各自生成了class文件。

注意,要把 aspectjrt.jar 加到 -classpath 选项里。

接下来运行程序:

➜  temp0816 java -cp ~/aspectj1.9/lib/aspectjrt.jar packageMain.AspectJTest 
Error: Could not find or load main class packageMain.AspectJTest
Caused by: java.lang.ClassNotFoundException: packageMain.AspectJTest

报错了,这是因为没有添加 .-cp 选项里。

➜  temp0816 java -cp ~/aspectj1.9/lib/aspectjrt.jar:. packageMain.AspectJTest
Hello Aspect
Test0816::doSth()

可以看到AOP的效果:在调用 Test0816doSth() 方法之前,打印出 Hello Aspect

注: . (当前目录)在编译时( javac 命令)不需要添加到 -cp 选项里,但是运行时( java 命令)则需要添加到 -cp 选项里(如果指定了 -cp 选项)。

Spring的AOP支持

本例使用IntelliJ IDEA工具来开发。

在IntelliJ IDEA新建Java项目 project0817

src 同一级创建一个libs目录,把Spring所需的21个jar文件和AOP所需的2个jar文件,复制到libs目录下:

在这里插入图片描述

  • Spring的jar文件的来源为:在浏览器打开 https://repo.spring.io/ui/native/libs-release-local ,org -> springframework -> spring,找到最新版本,本例为5.2.9.RELEASE,然后下载 spring-5.2.9.RELEASE-dist.zip ,解压,即可得到21个jar文件。

  • AOP的jar文件的来源为:前面步骤中所安装的AspectJ路径下的lib目录(只需 aspectjrt.jaraspectjweaver.jar 2个jar文件)。

最后别忘了给项目设置lib。File -> Project Structure -> Libraries,点击 + 图标,添加 libs 目录:

在这里插入图片描述
src 目录下创建 packageService package,并创建 Test0817 类:

package packageService;

import org.springframework.stereotype.Component;

@Component
public class Test0817 {
    public void doSth() {
        System.out.println("Test0817::doSth()");
    }
}

src 目录下创建 packageAspect package,并创建 MyAspect 类:

package packageAspect;

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

@Aspect
public class MyAspect {
    @Before("execution(* packageService.*.*(..))")
    public void Foo() {
        System.out.println("Foo");
    }
}

src 目录下创建 packageMain package,并创建 TestAspect 类:

package packageMain;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import packageService.Test0817;

public class TestAspect {
    public static void main(String[] args) {
        var ctx = new ClassPathXmlApplicationContext("beans.xml");
        var test0817 = ctx.getBean("test0817", Test0817.class);
        test0817.doSth();
    }
}

src 目录下创建 beans.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:context="http://www.springframework.org/schema/context"
       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/context
	http://www.springframework.org/schema/context/spring-context.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop.xsd">
    <context:component-scan base-package="packageService,
		packageAspect">
        <context:include-filter type="annotation"
                                expression="org.aspectj.lang.annotation.Aspect"/>
    </context:component-scan>
    <aop:aspectj-autoproxy/>
</beans>

运行主程序,结果如下:

Foo
Test0817::doSth()

可以看到AOP的效果:在调用 Test0817doSth() 方法之前,打印出 Foo

在这里插入图片描述
注意:本例中,对于 MyAspect 类,只有 @Aspect 注解,没有 @Component 注解,而实际上 MyAspect 也是容器里的bean,可以用 ctx.getBean("myAspect", MyAspect.class) 将其取出来。但是,对于接下来的Spring Boot程序, MyAspect 类就必须加上 @Component 注解,否则就不起作用。需要研究一下原因。

Spring Boot的AOP支持

在IntelliJ IDEA新建 Spring Assistant 项目 project0818 ,并在dependency中选择 Spring Web

在生成的pom.xml文件中,添加依赖:

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>

创建package com.example.project0818.api ,并创建 MyController 类:

package com.example.project0818.api;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {
    @RequestMapping("/hello")
    public String hello() {
        return "hello world!";
    }
}

先测试一下这个API。启动程序,在命令行里运行如下命令:

➜  ~ curl localhost:8080/hello
hello world

没有问题,一切顺利。接下来添加AOP的逻辑。

创建package com.example.project0818.aspect ,并创建 MyAspect 类:

package com.example.project0818.aspect;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MyAspect {
    @Before("execution(* com.example.project0818.api.*.*(..))")
    public void Foo() {
        System.out.println("Foo");
    }
}

注意:此处必须加上 @Component ,否则不起作用。

再次运行程序,这时AOP已经有效果了,每次运行上面的curl命令的时候,console上就会打印出 Foo

......
2021-08-17 23:04:29.466  INFO 6928 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2021-08-17 23:04:29.478  INFO 6928 --- [           main] c.e.project0818.Project0818Application   : Started Project0818Application in 3.509 seconds (JVM running for 4.437)
2021-08-17 23:04:38.907  INFO 6928 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-08-17 23:04:38.907  INFO 6928 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2021-08-17 23:04:38.909  INFO 6928 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
Foo

项目结构如下图所示:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值