当前位置: 首页 > 后端技术 > Java

AOP基本概念之一详解

时间:2023-04-02 09:08:19 Java

AOP基本概念之一详解WhatisAOPAOPorAspectOrientedProgramming,意为:面向切面编程,一种通过预编译实现程序功能统一维护的技术和运行时动态代理。AOP是OOP的延续,是软件开发的热点,是Spring框架中的重要内容,是函数式编程的衍生范式。AOP可以用来隔离业务逻辑的各个部分,从而降低业务逻辑各个部分之间的耦合度,提高程序的复用性,同时提高开发效率。说人话:我们需要在不直接修改源代码的情况下,在我们的函数中添加一些功能。为了降低耦合,我们使用AOP来实现。如:日志。AOP使用的技术原理主要是jdk的动态代理和cglib对字节码的修改。AOP中有六个概念:Joinpoint(连接点):在系统运行之前,需要将AOP的功能模块编织成具体的功能模块。要执行这个织入过程,我们需要知道系统的哪些执行点执行织入过程。这些将执行编织操作的系统执行点称为连接点。最常见的连接点是方法调用。.Pointcut:用来指定一组Joinpoints,代表我们的逻辑要织入到这组Joinpoints中,它定义了对应的Advice会出现在哪里。通常使用正则表达式表示。对于上面的例子,切入点是一个“表达式”,代表“所有要记录的接口”。例如:“执行(com.joonwheel.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来实现,看看我们的代码。/***@authortcy*@time2021-06-2216:43*/@Aspect@ComponentpublicclassOperationAspect{privatestaticStringCHECK_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(..))")publicvoidOperationController(){}/***预通知:在操作命令之前执行的通知**@paramjoinPoint*@throwsThrowable*/@Before("OperationController()")publicvoiddoBefore(JoinPointjoinPoint)throwsThrowable{//判断标志状态StringobjectId=SecurityUtilsWrapper.getDeptIdStr();如果(RedisUtil.get(CHECK_FLAG+objectId)!=null){if(RedisUtil.get(CHECK_FLAG+objectId).equals(1)){thrownewCustomException("库存中不允许操作");}}}}截图中的方法就是Joinpoint(连接点)通俗的说就是我们的aop和我们业务的连接点就是@Pointcut("execution)中的表达式。@Before是环绕通知,而你可以选择在业务执行之前或者之后执行,Aspect(切面)是我们定义的类,里面定义的切点围绕着通知,Weaving(编织)是我们判断逻辑的过程,也是最抽象的。Target(目标对象)就是我们的业务逻辑,如果把aop的过程比作切肉,Target就是Ourmeat,切的过程就是Weaving,切点就是刀切的地方,Advice(通知/增强)是什么时候开始切,Joinpoint是刀和肉的连接点,aspect(切面)是我们刀的大脑,记录了刀切的地方和肉什么时候切的。经过这个例子,aop的概率应该就清楚了。Spirng的IOC容器的启动过程是一个很大的过程,所以aop是其中的一部分。那么aop是什么时候开始在IOC容器中发挥作用的呢?我们继续看refresh的源码。@Overridepublicvoidrefresh()throwsBeansException,IllegalStateException{synchronized(this.startupShutdownMonitor){//准备此上下文以进行刷新。//1。刷新前准备prepareRefresh();//告诉子类刷新内部bean工厂。//2、会初始化BeanFactory,加载Bean,注册BeanConfigurableListableBeanFactorybeanFactory=obtainFreshBeanFactory();//准备在此上下文中使用的bean工厂。//3、设置BeanFactory的类加载器,添加几个BeanPostProcessor,手动注册几个特殊的beanprepareBeanFactory(beanFactory);try{//4,模板方法//允许在上下文子类中对bean工厂进行后处理。postProcessBeanFactory(beanFactory);//调用在上下文中注册为beans的工厂处理器。//执行BeanFactory后处理器invokeBeanFactoryPostProcessors(豆工厂);//5.注册拦截bean创建的bean处理器。//注册bean后处理器registerBeanPostProcessors(beanFactory);//为这个上下文初始化消息源。//国际化initMessageSource();//为此上下文初始化事件多播器。//初始化事件广播器initApplicationEventMulticaster();//初始化特定上下文子类中的其他特殊bean。//6。模板方法--springboot实现了该方法onRefresh();//检查侦听器bean并注册它们。//7。注册监听器registerListeners();//实例化所有剩余的(非惰性初始化)单例。//8。完成beanfactory的初始化**方法很重要****************************************************finishBeanFactoryInitialization(beanFactory);//9、最后一步:pub对应的事件。//完成上下文的刷新finishRefresh();}毫无疑问,aop的注入过程肯定是在单例bean实例化的时候注入的,也就是位置8,我们继续深挖这个方法。具体过程有很多很多……我都省略了。我在IOC源码中分析过。需要了解的可以移步历史文章。让我们开门见山。@OverrideprotectedObjectcreateBean(StringbeanName,RootBeanDefinitionmbd,@NullableObject[]args)throwsBeanCreationException{if(logger.isTraceEnabled()){logger.trace("Creatinginstanceofbean'"+beanName+"'");}RootBeanDefinitionmbdToUse=mbd;//确保此时实际解析了bean类,并且//在动态解析类的情况下克隆bean定义//不能存储在共享的合并bean定义中。//确保BeanDefinition中的Class被加载ClassresolvedClass=resolveBeanClass(mbd,beanName);if(resolvedClass!=null&&!mbd.hasBeanClass()&&mbd.getBeanClassName()!=null){mbdToUse=newRootBeanDefinition(mbd);mbdToUse.setBeanClass(resolvedClass);}//准备方法覆盖。//准备方法封装,这里又浸及到一个概念:MethodOverrides,它从bean定义中的//和,读者有兴趣可以回到解析bean的地方看这两个标签的解析尝试{mbdToUse.prepareMethodOverrides();}catch(BeanDefinitionValidationExceptionex){thrownewBeanDefinitionStoreException(mbdToUse.getResourceDescription(),beanName,“方法覆盖验证失败”,ex);}try{//让BeanPostProcessors有机会返回代理而不是目标bean实例。//在这一步让InstantiationAwareBeanPostProcessor有机会返回代理,//在《Spring AOP 源码分析》一文中有说明,先跳过aop入口************************************************************//AOP核心方法,用于处理通过@Aspect注解标识的切面bean,读取切面bean中的信息,添加到advisorsCache缓存中,从而生成一个动态代理Objectbean=resolveBeforeInstantiation(beanName,mbdToUse);如果(bean!=null){返回bean;}}catch(Throwableex){thrownewBeanCreationException(mbdToUse.getResourceDescription(),beanName,"BeanPostProcessorbeforeinstantiationofbeanfailed",ex);}try{//高亮,创建实例化的beanObjectbeanInstance=doCreateBean(beanName,mbdToUse,args);if(logger.isTraceEnabled()){logger.trace("Finishedcreatinginstanceofbean'"+beanName+"'");}returnbeanInstance;}catch(BeanCreationException|ImplicitlyAppearedSingletonExceptionex){//先前检测到的异常已经具有正确的bean创建上下文,//或非法单例状态传达至DefaultSingletonBeanRegistry.throwex;}catch(Throwableex){thrownewBeanCreationException(mbdToUse.getResourceDescription(),beanName,"Unexpectedexceptionduringbeancreation",ex);}}AOP在该方法中执行对象bean=resolveBeforeInstantiation(beanName,mbdToUse);今天就先说到这里吧,下一篇文章将开始深入分析这个方法。

最新推荐
猜你喜欢