4

AOP详解之一基本概念

 3 years ago
source link: https://blog.51cto.com/u_15476035/5112431
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

AOP详解之一基本概念

什么是AOP

AOP 即 Aspect Oriented Programming,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

AOP 是 OOP 的延续,是软件开发中的一个热点,也是 Spring 框架中的一个重要内容,是函数式编程的一种衍生范型。

利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

说人话:要在我们的功能中加一些功能,而不直接修改修改源代码的前提下,为了降低耦合性,就用AOP 的方式实现。如:日志。

AOP 使用的技术原理主要是jdk的动态代理和cglib修改字节码两种方式。

在AOP中有六个概念:

Joinpoint(连接点):在系统运行之前,AOP 的功能模块都需要织入到具体的功能模块中。要进行这种织入过程,我们需要知道在系统的哪些执行点上进行织入过程,这些将要在其之上进行织入操作的系统执行点就称之为 Joinpoint,最常见的 Joinpoint 就是方法调用。

Pointcut(切点):用于指定一组 Joinpoint,代表要在这一组 Joinpoint 中织入我们的逻辑,它定义了相应 Advice 将要发生的地方。通常使用正则表达式来表示。对于上面的例子,Pointcut 就是表示 “所有要加入日志记录的接口” 的一个 “表达式”。例如:“execution(* com.joonwhee.open.demo.service….(…))”。

Advice(通知/增强):Advice 定义了将会织入到 Joinpoint 的具体逻辑,通过 @Before、@After、@Around 来区别在 JointPoint 之前、之后还是环绕执行的代码。

Aspect(切面):Aspect 是对系统中的横切关注点逻辑进行模块化封装的 AOP 概念实体。类似于 Java 中的类声明,在 Aspect 中可以包含多个 Pointcut 以及相关的 Advice 定义。

Weaving(织入):织入指的是将 Advice 连接到 Pointcut 指定的 Joinpoint 处的过程,也称为:将 Advice 织入到 Pointcut 指定的 Joinpoint 处。

Target(目标对象):符合 Pointcut 所指定的条件,被织入 Advice 的对象。

宽泛的说概念很枯燥,读者也不能很好的理解,我们举一个实战中的一个例子。

业务中有个需求,需要在操作一个按钮之前去判断一下,当前按钮是否可以操作。直接修改源代码判断这种方式确实可以,但是耦合性太高了。

我们就采用aop+redis的方式去实现,看一下我们的代码。

/**
 * @author tcy
 * @time 2021-06-22 16:43
 */
@Aspect
@Component
public class OperationAspect {

  private static String CHECK_FLAG = "CHECK_FLAG:";

  /**
   * 定义切入点,切入点为com.ruoyi.project.medicinemanager.operate.controller下的所有函数
   */
  @Pointcut("execution(public * com.ruoyi.project.medicinemanager.operate.controller.OperateController.insert(..))||" +
    "execution(public * com.ruoyi.project.medicinemanager.operate.controller.OperateController.save(..))" +
    "||execution(public * com.ruoyi.project.medicinemanager.operate.controller.OperateController.approve(..))")
  public void OperationController() {
  }

  /**
   * 前置通知:在操作单之前执行的通知
   *
   * @param joinPoint
   * @throws Throwable
   */
  @Before("OperationController()")
  public void doBefore(JoinPoint joinPoint) throws Throwable {
    // 判断标志位状态
    String objectId = SecurityUtilsWrapper.getDeptIdStr();
    if (RedisUtil.get(CHECK_FLAG + objectId) != null) {
      if (RedisUtil.get(CHECK_FLAG + objectId).equals(1)) {
        throw new CustomException("盘点中不允许操作");
      }
    }
  }

}

AOP详解之一基本概念_ide

截图中的方法就是Joinpoint(连接点)通俗的说就是我们的aop和我们的业务连接的地方。

切点就是 @Pointcut("execution)里面的表达式。

@Before就是环绕通知,可以选择在业务执行前还是后去执行。

Aspect(切面)就是我们定义的这个类,里面定义的切点,环绕通知。

Weaving(织入)就是我们判断逻辑的过程,这个也是最抽象的。

Target(目标对象)就是我们的业务逻辑。

如果把aop的过程比喻成切肉,Target就是我们的肉,切的过程就是Weaving,切点就是下刀的地方,Advice(通知/增强)就是在什么时候开始切,Joinpoint就是刀和肉的联系,Aspect(切面)就当我们刀的大脑吧,里面记录着下刀的地方和肉在什么时候切。

经过这个例子应该对aop的概率了然于心了。

Spirng的IOC容器的启动过程是一个大的流程,那么aop就是其中的一个部分,那aop是什么时候在IOC的容器中开始发挥作用的呢?

我们继续看refresh的源码。

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			//1、刷新前的准备
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			//2、将会初始化 BeanFactory、加载 Bean、注册 Bean
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			//3、设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
			prepareBeanFactory(beanFactory);

			try {
				//4、模板方法
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				//执行BeanFactory后置处理器
				invokeBeanFactoryPostProcessors(beanFactory);

				// 5、Register bean processors that intercept bean creation.
				//注册bean后置处理器
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				//国际化
				initMessageSource();

				// Initialize event multicaster for this context.
				//初始化事件广播器
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				//6、模板方法--springboot实现了这个方法
				onRefresh();

				// Check for listener beans and register them.
				//7、注册监听器
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				//8、完成bean工厂的初始化**方法重要**********************************************
				finishBeanFactoryInitialization(beanFactory);

				//9、 Last step: publish corresponding event.
				//完成上下文的刷新工作
				finishRefresh();
			}

毫无疑问aop的注入过程一定是在实例化单例bean的时候注入的。也就是位置8,我们继续深入该方法。

具体过程很多很多…省略了,我在IOC源码中都有过解析,需要了解的可以移步历史文章。

我们直接步入正题。

@Override
	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		if (logger.isTraceEnabled()) {
			logger.trace("Creating instance of bean '" + beanName + "'");
		}
		RootBeanDefinition mbdToUse = mbd;

		// Make sure bean class is actually resolved at this point, and
		// clone the bean definition in case of a dynamically resolved Class
		// which cannot be stored in the shared merged bean definition.
		// 确保 BeanDefinition 中的 Class 被加载
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}

		// Prepare method overrides.
		// 准备方法覆写,这里又涉及到一个概念:MethodOverrides,它来自于 bean 定义中的 <lookup-method />
		// 和 <replaced-method />,如果读者感兴趣,回到 bean 解析的地方看看对这两个标签的解析。
		try {
			mbdToUse.prepareMethodOverrides();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
					beanName, "Validation of method overrides failed", ex);
		}

		try {
			// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
			// 让 InstantiationAwareBeanPostProcessor 在这一步有机会返回代理,
			// 在 《Spring AOP 源码分析》那篇文章中有解释,这里先跳过 aop入口*******************************************************
			// AOP核心方法,用来处理使用@Aspect注解标识的切面bean,读取切面bean中的信息,添加到advisorsCache缓存中,以便后面生成动态代理
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
					"BeanPostProcessor before instantiation of bean failed", ex);
		}

		try {
			// 重头戏,创建实例化 bean
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isTraceEnabled()) {
				logger.trace("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}
		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
			// A previously detected exception with proper bean creation context already,
			// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
		}
	}

AOP就是在这个方法中开始执行的。

Object bean = resolveBeforeInstantiation(beanName, mbdToUse);

今天暂时先到这里,下篇文章开始深入分析这个方法。


Recommend

  • 85

    0. 简介 这个系列开始来讲解 Java 多线程的知识,这节就先讲解多线程的基本知识。 1. 进程与线程 1.1 什么是进程? 进程就是在运行过程中的程序,就好像手机运行中的微信,QQ,这些就叫做进程。 1.2 什么是线程? 线程就是进程的执行单元,就好像一个

  • 40
    • 微信 mp.weixin.qq.com 6 years ago
    • Cache

    Spring AOP(一) AOP基本概念

  • 54
    • 微信 mp.weixin.qq.com 6 years ago
    • Cache

    Spring AOP(一):AOP 基本概念

    Spring框架自诞生之日就拯救我等程序员于水火之中,它有两大法宝,一个是IoC控制反转,另一个便是AOP面向切面编程。今日我们就来破一下它的AOP法宝,以便以后也能自由使出一手AOP大法。 AOP全名Aspect-oriented programming面...

  • 35
    • www.tuicool.com 5 years ago
    • Cache

    Spring系列(四):Spring AOP详解

    一、AOP是什么 AOP(面向切面编程),可以说是一种编程思想,其中的Spring AOP和AspectJ都是现实了这种编程思想。相对OOP(面向过程编程)来说,提供了另外一种编程方式,对于OOP过程中产生的横切性问题,这些横切性与业务无关...

  • 39

    容器是什么?镜像又是什么?容器的生命周期是怎么样的?与 VM 相比,容器的优劣势分别是什么?…本文将为大家一一解答这些问题。 一、容器与镜像 什么是容器? 在介绍容器的具体概念之前,先简单回顾一下操...

  • 9
    • www.eknown.cn 4 years ago
    • Cache

    RabbitMQ 基本概念详解

    RabbitMQ 是实现了 AMQP 协议的开源消息代理软件(又叫做面向消息的中间件)。这一节主要介绍 AMQP 协议的一些基本概念,包括:四种交换器(exchange)、队列、绑定等。这些概念在实现了 AMQP 协议的消息中间件中是通用的,RabbitMQ 则在此基...

  • 2

    C++20 四大特性之一:Module 特性详解C++20 最大的特性是什么?最大的特性是迄今为止没有哪一款编译器完全实现了所有特性。有人认为 C++20 是 C++11 以来最大的一次改动,甚...

  • 6
    • hellolyfing.github.io 3 years ago
    • Cache

    Spring AOP名词术语详解

    Spring AOP名词术语详解 Sep 8, 2018 SpringAOP的术语(其实是Java AOP)并不形象和易于理解,有时候比较容易忘记和混淆概念。再者其实AOP中的术语也有重要和次重要之分,一股脑全盘理解有点混沌,所以本篇介绍将...

  • 5

    这个实验主要用来测试大家对现代 C++ 的掌握程度,实验要求如下:

  • 6

    CMU15445 (Fall 2019) 之 Project#3 - Query Execution 详解 发表于 2022-07-11 13:50 | 分类 C++ | 阅...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK