什么是AOP?

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,提高代码的灵活性和可扩展性,AOP可以说也是这种目标的一种实现。

把切面应用到目标对象来创建新的代理对象的过程,织入一般发生在如下几个时机:
(1)编译时:当一个类文件被编译时进行织入,这需要特殊的编译器才可以做的到,例如AspectJ的织入编译器
(2)类加载时:使用特殊的ClassLoader在目标类被加载到程序之前增强类的字节代码
(3)运行时:切面在运行的某个时刻被织入,SpringAOP就是以这种方式织入切面的,原理是使用了JDK的动态代理技术

AspectJ的使用

AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。

在Eclipse上创建AspectJ项目

STS(Spring Tool Suite)中自带AJDT插件,可以直接创建项目。一般先较新版本的IDE工具都带有AJDT插件,如果没有需要自行安装。

AJDT安装方法如下

1、打开Eclipse“Help”-->"Eclipse Marketplace..."
2、搜索AJDT,出现搜索结果
3、选择安装的版本,点击“Install”(我这里安装过了,所以是Installed)

创建AspectJ项目

1、“New”-->"Project..."
2、找到“AspectJ Project”
3、点击“Next”,然后在弹出的创建项目窗口中输入项目名称,点击“Finish”即可

AspectJ Project的结构如下

第一个AspectJ Project

首先实现一个简单的切面,由一个业务类和一个切面类组成
业务类的代码如下

package com.codestd.aspectj.test;
public class People {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public void sleep(){System.out.println(this.name+"睡着了");}public static void main(String[] args){People p = new People();p.setName("Jaune");p.sleep();}}

接下来定义一个切面类,用于捕获sleep方法,在调用sleep方法前打印”xxx要睡觉了”

package com.codestd.aspectj.test;
import java.lang.reflect.Field;
import java.util.Date;
public aspect PeopleInterceptor {pointcut callSleep():call(void com.codestd.aspectj.test.People.sleep());before() : callSleep(){Object obj = thisJoinPoint.getTarget();try {Field field = obj.getClass().getDeclaredField("name");field.setAccessible(true);String name = (String)field.get(obj);System.out.println(name+"要睡觉了。"+(new Date()));} catch (Exception e) {e.printStackTrace();}}}

pointcut:定义切面,语法 pointcut

AspectJ的秘密

用反编译工具查看编译后的People类,代码如下

//people类
package com.codestd.aspectj.test;
import java.io.PrintStream;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.JoinPoint.StaticPart;
import org.aspectj.runtime.reflect.Factory;
public class People
{private String name;private static final JoinPoint.StaticPart ajc$tjp_0;private static void ajc$preClinit(){Factory localFactory = new Factory("People.java", People.class);ajc$tjp_0 = localFactory.makeSJP("method-call", localFactory.makeMethodSig("1", "sleep", "com.codestd.aspectj.test.People", "", "", "", "void"), 22);}public String getName(){return this.name;}public void setName(String name){this.name = name;}public void sleep(){System.out.println(this.name + "睡着了");}public static void main(String[] args){People p = new People();p.setName("Jaune");People localPeople1 = p;JoinPoint localJoinPoint = Factory.makeJP(ajc$tjp_0, null, localPeople1);PeopleInterceptor.aspectOf().ajc$before$com_codestd_aspectj_test_PeopleInterceptor$1$68d231da(localJoinPoint);localPeople1.sleep();}static {}
}//切面类
package com.codestd.aspectj.test;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.util.Date;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.NoAspectBoundException;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class PeopleInterceptor
{public static PeopleInterceptor aspectOf(){if (ajc$perSingletonInstance == null) {throw new NoAspectBoundException("com_codestd_aspectj_test_PeopleInterceptor", ajc$initFailureCause);}return ajc$perSingletonInstance;}public static boolean hasAspect(){return ajc$perSingletonInstance != null;}static{try{}catch (Throwable localThrowable){ajc$initFailureCause = localThrowable;}}@Before(value="callSleep()", argNames="")public void ajc$before$com_codestd_aspectj_test_PeopleInterceptor$1$68d231da(JoinPoint thisJoinPoint){Object obj = thisJoinPoint.getTarget();try{Field field = obj.getClass().getDeclaredField("name");field.setAccessible(true);String name = (String)field.get(obj);System.out.println(name + "要睡觉了。" + new Date());}catch (Exception e){e.printStackTrace();}}
}

通过代码可以看到sleep方法之前多了一些代码,但是这些代码并不是我们写的。这些代码是aspectJ编译器添加的,aspectJ是编译期的AOP框架,所以aspectJ项目在编译的时候aspectJ编译器会将横切代码自动加入到业务代码中,从而实现AOP编程。

AspectJ的使用不再深入讲解,这里我们重点讲解的是Spring的AOP,所以下面我们把重心放到Spring AOP中。

Spring AOP

Spring AOP是运行时的AOP框架,采用的是JDK动态代理技术

SpringAOP配置方式

1、添加AOP依赖

<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.7</version>
</dependency>
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.1</version>
</dependency>

2、Spring AOP Schema

xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.1.xsd"

3、AOP配置

<aop:aspectj-autoproxy />

有一个proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强,
当配为时,表示使用CGLib动态代理技术织入增强。
不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。

使用Spring AOP

创建一个业务类,这里我们采用注解的方式。如非特殊需求,后面的Spring讲解中将一律用Spring注解的方式配置Bean


package com.codestd.springstudy.lesson03;
import org.springframework.stereotype.Component;
@Component
public class People {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public void sleep(){System.out.println(this.name+"睡着了");}}

创建切面


package com.codestd.springstudy.lesson03;
import java.lang.reflect.Field;
import java.util.Date;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class PeopleInterceptor {@Pointcut("execution(* com.codestd.springstudy.lesson03.People.sleep(..))")public void callSleep(){}@Before(value="callSleep()")  public void beforeSleep(JoinPoint joinPoint){Object obj = joinPoint.getTarget();try {Field field = obj.getClass().getDeclaredField("name");field.setAccessible(true);String name = (String)field.get(obj);System.out.println(name+"要睡觉了。"+(new Date()));} catch (Exception e) {e.printStackTrace();}}
}

这里我们使用@Aspect注解来表示这是一个横切类,使用@Pointcut注解定义切入点,@Before注解表示是在方法前执行

测试AOP


package com.codestd.springstudy.lesson03;
import javax.annotation.Resource;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:lesson03/applicationContext.xml"})
public class PeopleTest {@Resourceprivate People people;@Beforepublic void setUp(){people.setName("Jaune");}@Testpublic void testSleep() {people.sleep();}
}

输出的结果为

7、Spring AOP使用相关推荐

  1. Spring AOP + Redis解决重复提交的问题

    Spring AOP + Redis解决重复提交的问题 用户在点击操作的时候,可能会连续点击多次,虽然前端可以通过设置按钮的disable的属性来控制按钮不可连续点击,但是如果别人拿到请求进行模拟,依 ...

  2. 利用Spring AOP与JAVA注解为系统增加日志功能

    Spring AOP一直是Spring的一个比较有特色的功能,利用它可以在现有的代码的任何地方,嵌入我们所想的逻辑功能,并且不需要改变我们现有的代码结构. 鉴于此,现在的系统已经完成了所有的功能的开发 ...

  3. Spring AOP的一些概念

            切面(Aspect): 一个关注点的模块化,这个关注点可能会横切多个对象.事务管理是J2EE应用中一个关于横切关注点的很好的例子. 在Spring AOP中,切面可以使用通用类(基于模 ...

  4. Spring AOP与IOC

    Spring AOP实现日志服务 pom.xml需要的jar <dependency><groupId>org.apache.commons</groupId>&l ...

  5. Spring AOP与IOC以及自定义注解

    Spring AOP实现日志服务 pom.xml需要的jar <dependency><groupId>org.apache.commons</groupId>&l ...

  6. Spring Aop的应用

    2019独角兽企业重金招聘Python工程师标准>>> AOP的基本概念 连接点( Jointpoint) : 表示需要在程序中插入横切关注点的扩展点,连接点可能是类初始化.方法执行 ...

  7. Spring AOP详解(转载)所需要的包

    上一篇文章中,<Spring Aop详解(转载)>里的代码都可以运行,只是包比较多,中间缺少了几个相应的包,根据报错,几经百度搜索,终于补全了所有包. 截图如下: 在主测试类里面,有人怀疑 ...

  8. 关于spring aop Advisor排序问题

    关于spring aop Advisor排序问题 当我们使用多个Advisor的时候有时候需要排序,这时候可以用注解org.springframework.core.annotation.Order或 ...

  9. 利用spring aop统一处理异常和打日志

    利用spring aop统一处理异常和打日志 spring aop的概念,很早就写博客介绍了,现在在工作中真正使用. 我们很容易写出的代码 我们很容易写出带有很多try catch 和 logger. ...

  10. 我所理解的Spring AOP的基本概念

    Spring AOP中的概念晦涩难懂,读官方文档更是像读天书,看了很多例子后,写一些自己理解的一些spring的概念.要理解面向切面编程,要首先理解代理模式和动态代理模式. 假设一个OA系统中的一个功 ...

最新文章

  1. oracle bl编译,使用 PL/SQL 条件编译
  2. 牛客练习赛61 C 四个选项(并查集、DP、排列组合)难度⭐⭐⭐
  3. LeetCode 281. 锯齿迭代器(map+vector)
  4. wxPython4.0中ListCtrl入门
  5. 用的最多的正则表达式
  6. 一不小心就对未分配的内存进行访问和修改
  7. 浏览器相关功能系统调用
  8. CXF webservice完整例子
  9. 数字图像处理技术详解程序_FCA在自动驾驶和智能网联技术最近五年变革
  10. 咸鱼Maya笔记—Maya 场景操作
  11. 电脑打开网络没有WiFi列表
  12. ie浏览器js不刷新和乱码问题
  13. 什么是API Mock测试?
  14. 2001-2020年全国31省城镇居民人均可支配收入/居民实际收入水平
  15. ShowWindow(SW_SHOWNORMAL)
  16. 题目:输入一个整数a,其个位为第一位,十位为第二位,依次类推,计算a的偶数位的和奇数位的和。
  17. 功率放大芯片采用RFX2411 分集开关的2.4 GHz TX / RX增强器
  18. windows 命令提示符 修改/prompt
  19. 前端必学——用JavaScript实现电商图片放大镜效果(附代码)
  20. biba和blp安全模型都是基于格的吗

热门文章

  1. 课程设计——部门管理系统C++
  2. 简述async和await写法
  3. 火星坐标, WGS84坐标, 百度坐标
  4. 最新的AS下载地址,更新及时
  5. 第七次全国人口普查登记今日零时启动 六大释疑都在这
  6. html制作统计期末成绩,如何用Excel制作学生成绩统计表
  7. 八拜之交是指哪八拜?
  8. 电梯控制系统的实现(代码简洁优质、易懂)
  9. 但是生活总不是完美的
  10. 激光SLAM:Livox激光雷达硬件时间同步