AOP_面向切面编程

简介:

什么是面向切面编程?

在软件开发中,分布于应用中多处的功能被成为横切关注点。

切面提供了取代继承和委托的另一种选择,而且在很多场景下更清晰简洁。在使用面向切面编程时,我们仍然在一个地方定义通用功能,但是我们可以通过声明的方式定义这个功能以及何种方式在何处应用,而无需修改受影响的类。横切关注点可以被模块化为特殊的类,这些类被成为切面。这样做有两个好处:首先,每个关注点现在都只集中于一处,而不是分散到多处代码中;其次,服务模块更简洁,因为它们只包含主要关注点(或核心功能)的代码,而次要关注点的代码被转移到切面中去了。


AOP常见的术语有通知(advice)、切点(pointcut)和连接点(join point)。


通知(Advice)

在AOP术语中,切面的工作被称为通知。

spring切面可以应用5种类型的通知:

1、Before:在方法被调用之前调用通知

2、After:在方法完成之后调用通知,无论方法执行是否成功。

3、After-returing:在方法成功执行之后调用通知。

4、After-throwing:在方法抛出异常后调用通知。

5、Around:通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。


连接(Joinpoint):我们的应用可能需要对数以千计的时机应用通知,这些时机被称为连接点。


切点(Pointcut):如果通知定义了切面的“什么”和“何时”,那么切点就定义了“何处”。切点的定义会匹配通知索要织入的一个或多个连接点。我们通常使用明确的类和方法名称来指定这些切点,或是利用正则表达式定义匹配的类和方法名称模式来指定这些切点。有些AOP框架允许我们创建动态的切点,可以根据运行时的决策(比如方法的参数值)来决定是否应用通知。


切面(Aspect):切面是通知和切点的结合。通知和切点共同定义了关于切面的全部内容--它是什么,在何时和何处完成其功能。


引入(Introduction):引入允许我们向现有的类添加新方法或属性。例如,我们可以创建一个Auditable通知类,该类记录了对象最后一次修改时的状态。这很简单,只需一种方法,setLastModified(Date),和一个实例变量来保存这个状态。然后,这个新方法和实例变量就可以被引入到现有的类中。从而可以在无需修改这些现有的类的情况下,让它们具有新的行为和状态。


织入(Weaving):织入是将切面应用到目标对象来创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。在目标对象的声明周期里有多个点可以进行织入。


Spring对AOP的支持有哪些?


Spring提供了4种各具特色的AOP支持:

1、基于代理的经典AOP;

2、@AspectJ注解驱动的切面;

3、纯POJO切面;

4、注入式AspectJ切面(适合Spring各版本)


Spring在运行期通知对象

通过在代理类中包裹切面,Spring在运行期将切面织入到Spring管理的Bean中,如图所示,代理类封装了目标类,并拦截被通知的方法的调用,再将调用转发给真正的目标Bean


当拦截到方法调用时,在调用Bean方法之前,代理会执行切面逻辑。

直到应用需要被代理的Bean时,Spring才会创建代理对象。如果使用的是ApplicationContext,在ApplicationContext从BeanFactory中加载所有Bean时,Spring创建被代理的对象。因为Spring运行时才创建代理对象,所以我们不需要特殊的编译器来织入Spring AOP的切面。


Spring只支持方法连接点

正如前面所探讨过的,通过各种AOP实现可以支持多种连接点模型。因为Spring基于动态代理,所以Spring只支持方法连接点。这与其他一些AOP框架是不通的,例如AspectJ和JBoss,除了方法切点,它们还提供了字段和构造器接入点。Spring缺少对字段连接点的支持,无法让我们创建细粒度的通知,例如拦截对象字段的修改。而且Spring也不支持构造器连接点,我们无法在Bean创建时应用通知。

但是方法拦截可以满足绝大部分的需求。如果需要方法拦截之外的连接点拦截,我们可以利用Aspect来协助Spring AOP。


Spring AOP所支持的AspectJ切点指示器有:

1、arg():限制连接点匹配参数为指定类型的执行方法。

2、@arg():限制连接点匹配参数由指定注解标注的执行方法。

3、execution():用于匹配是连接点的执行方法。

4、this():限制连接点匹配AOP代理的Bean引用为指定类型的类

5、target():限制连接点匹配目标对象为指定类型的类

6、@target():限制连接点匹配特定的执行对象,这些对象对应的类要具备指定类型的注解

7、within():限制连接点匹配指定的类型。

8、@within():限制连接点匹配指定注解所标注的类型(当使用Spring AOP时,方法定义在由指定的注解所标注的类里)。

9、@annotation:限制匹配带有指定注解连接点。


在Spring中尝试使用AspectJ其他指示器时,将会抛出IllegalArgumentException异常。

execution指示器是我们在编写切点定义时最主要使用的指示器。在此基础上,我们使用其他指示器来限制所匹配的切点。


编写切点


                              使用AspectJ切点表达式来定位


                              使用within()指示器限制切点范围


使用Spring的bean()指示器

除了上图所示的指示器外,Spring2.5还引入了一个新的bean()指示器,该指示器允许我们在切点表达式中使用Bean的ID来标识Bean。bean()使用BeanID或Bean名称作为参数来限制切点只匹配特定的Bean。

例如,下面的切点希望在执行Instrument的play方法时应用通知,但限定Bean的ID为eddie。

[html]  view plain  copy
 print ?
  1. <span style="color:#009900;">execution(* com.springinaction.springdol.Instrument.play(..)) and bean(eddie)</span>  


在XML中声明切面

下面是AOP的配置元素:

1、<aop:advisor>:定义AOP通知器

2、<aop:after>:定义AOP后置通知(不管被通知的方法是否执行成功)

3、<aop:after-returning>:定义AOP after-returing通知

4、<aop:after-throwing>:定义after-throwing通知

5、<aop:around>:定义AOP环绕通知

6、<aop:aspect>:定义切面

7、<aop:aspectj-autoproxy>:启用@AspectJ注解驱动的切面

8、<aop:before>:定义AOP前置通知

9、<aop:config>:顶层AOP配置元素,大多数的<aop:*>元素必须包含在这个元素内

10、<aop:declare-parents>:为被通知的对象引入额外的接口,并透明地实现

11、<aop:pointcut>:定义切点


下面让我们具体的阐述Spring AOP。

程序Audience:定义一个观众类

[html]  view plain  copy
 print ?
  1. <span style="color:#009900;">package com.springinaction.springidol;  
  2. /**  
  3.  * 为选秀会定义观众  
  4.  * @author alone  
  5.  *  
  6.  */  
  7. public class Audience {  
  8.     public void takeSeats() {//表演之前  
  9.         System.out.println("The audience is taking their seats.");  
  10.     }  
  11.       
  12.     public void turnOffCellPhones() {//表演之前  
  13.         System.out.println("The audience is turning off their cellphones");  
  14.     }  
  15.       
  16.     public void applaud() {//表演之后  
  17.         System.out.println("CLAP CLAP CLAP CLAP CLAP");  
  18.     }  
  19.       
  20.     public void demandRefund() {//表演失败之后  
  21.         System.out.println("Boo! We want our money back!");  
  22.     }  
  23. }  
  24. </span>  


声明前置和后置通知

[html]  view plain  copy
 print ?
  1. <span style="color:#009900;"><bean id="audience" class="com.springinaction.springidol.Audience" />  
  2.       
  3.     <aop:config>  
  4.         <aop:aspect ref="audience">  
  5.             <aop:before method="takeSeats" pointcut="execution(* com.springinaction.springidol.Performer.perform(..))"/>  
  6.             <aop:before method="turnOffCellPhones" pointcut="execution(* com.springinaction.springidol.Performer.perform(..))"/>  
  7.             <aop:after-returning method="applaud" pointcut="execution(* com.springinaction.springidol.Performer.perform(..))"/>  
  8.             <aop:after-throwing method="demandRefund" pointcut="execution(* com.springinaction.springidol.Performer.perform(..))"/>  
  9.         </aop:aspect>  
  10.     </aop:config></span>  

这个的流程就如同调用了performer.perform()后这样执行:

[html]  view plain  copy
 print ?
  1. <span style="color:#009900;">try {  
  2.             audience.takeSeats() ;  
  3.             audience.turnOffCellPhones() ;  
  4.             audience.applaud() ;  
  5.         } catch (Exception e) {  
  6.             audience.demandRefund() ;  
  7.         }</span>  

你或许注意到所有通知元素中的pointcut属性的值都是一样的,这是因为所有的通知都是应用到相同的切点上。这似乎违反了DRY(不要重复自己)原则。如果将来想修改这个切点,那么需要同时修改4个地方。

为了避免重复定义切点,可以使用<aop:pointcut>元素定义一个命名切点。

[html]  view plain  copy
 print ?
  1. <span style="color:#009900;"><bean id="audience" class="com.springinaction.springidol.Audience" />  
  2.       
  3.     <aop:config>  
  4.         <aop:aspect ref="audience">  
  5.             <aop:pointcut expression="execution(* com.springinaction.springidol.Performer.perform(..))" id="performance"/>  
  6.             <aop:before method="takeSeats" pointcut-ref="performance"/>  
  7.             <aop:before method="turnOffCellPhones" pointcut-ref="performance"/>  
  8.             <aop:after-returning method="applaud" pointcut-ref="performance"/>  
  9.             <aop:after-throwing method="demandRefund" pointcut-ref="performance"/>  
  10.         </aop:aspect>  
  11.     </aop:config></span>  

声明环绕通知

前置通知和后置有一些限制。具体来说,如果不使用成员变量存储信息,那么在前置通知和后置通知之间共享信息非常麻烦。例如我们要在前置通知中记录开始时间并在某个后置通知中报告表演耗费的时长。但这样的话,我们必须在一个成员变量中保存开始时间。因为Audience是单例,如果像这样保存状态,它将存在线程安全问题。

下面是一个新的watchPerformance()方法。

[html]  view plain  copy
 print ?
  1. <span style="color:#009900;">public void watchPerformance(ProceedingJoinPoint joinpoint) {  
  2.         try {  
  3.             System.out.println("The audience is taking their seats.");  
  4.             System.out.println("The audience is turning off their cellphones");  
  5.             long start = System.currentTimeMillis() ;  
  6.               
  7.             joinpoint.proceed() ;  
  8.               
  9.             long end = System.currentTimeMillis() ;  
  10.             System.out.println("CLAP CLAP CLAP CLAP CLAP");  
  11.             System.out.println("The performance took " + (end - start) + "millseconds.");  
  12.         } catch (Throwable e) {  
  13.             System.out.println("Boo! We want our money back!");  
  14.         }  
  15.     }</span>  

[html]  view plain  copy
 print ?
  1. <span style="color:#009900;"><bean id="audience" class="com.springinaction.springidol.Audience" />  
  2.       
  3.     <aop:config>  
  4.         <aop:aspect ref="audience">  
  5.             <aop:pointcut expression="execution(* com.springinaction.springidol.Performer.perform(..))" id="performance"/>  
  6.             <aop:around pointcut-ref="performance" method="watchPerformance()"/>  
  7.         </aop:aspect>  
  8.     </aop:config></span>  


为通知传递参数

[html]  view plain  copy
 print ?
  1. <span style="color:#009900;">package com.springinaction.springidol;  
  2. //读心者  
  3. public interface MindReader {  
  4.     void interceptThoughts(String thoughts) ;  
  5.     String getThoughts() ;  
  6. }</span>  

[html]  view plain  copy
 print ?
  1. <span style="color:#009900;">package com.springinaction.springidol;  
  2.   
  3. public class Magician implements MindReader {  
  4.     private String thoughts ;  
  5.     @Override  
  6.     public void interceptThoughts(String thoughts) {  
  7.         System.out.println("Intercepting volunteer's thoughts");  
  8.     }  
  9.     @Override  
  10.     public String getThoughts() {  
  11.         return thoughts;  
  12.     }  
  13.   
  14. }  
  15. </span>  

[html]  view plain  copy
 print ?
  1. <span style="color:#009900;">package com.springinaction.springidol;  
  2.   
  3. public interface Thinker {  
  4.     void thinkOfSomething(String thoughts) ;  
  5. }  
  6. </span>  

[html]  view plain  copy
 print ?
  1. <span style="color:#009900;">package com.springinaction.springidol;  
  2. //志愿者  
  3. public class Volunteer implements Thinker {  
  4.     private String thoughts ;  
  5.       
  6.     @Override  
  7.     public void thinkOfSomething(String thoughts) {  
  8.         this.thoughts = thoughts ;  
  9.     }  
  10.       
  11.     public String getThoughts() {  
  12.         return thoughts ;  
  13.     }  
  14.   
  15. }  
  16. </span>  

现在我们要做的是Magician如何使用Spring AOP截听Volunteer的内心感应。

[html]  view plain  copy
 print ?
  1. <span style="color:#009900;"><bean id="audience" class="com.springinaction.springidol.Audience" />  
  2.       
  3.     <aop:config>  
  4.         <aop:aspect ref="magician">  
  5.             <aop:pointcut expression="execution(* com.springinaction.springidol.Thinker.thinkOfSomething(String) and args(thoughts))" id="thinking"/>  
  6.             <aop:before method="interceptThoughts" arg-names="thoughts" pointcut-ref="thinking"/>  
  7.         </aop:aspect>  
  8.     </aop:config></span>  

通过切面引入新功能

如果切面能够为现有的方法增加额外的功能,为什么不能为一个对象增加新的方法呢?实际上,利用被称为引入的AOP概念,切面可以为Spring Bean添加新方法。

下面为示例中所有表演者引入下面的contestant接口:

[html]  view plain  copy
 print ?
  1. <span style="color:#009900;">package com.springinaction.springidol;  
  2.   
  3. public interface Contestant {  
  4.     void receiveAward() ;  
  5. }  
  6. </span>  

借助AOP引入,我们可以不需要为设计妥协或者侵入性的改变现有的实现。为了搞定它,我们需要使用<aop:declare-parents>元素:

[html]  view plain  copy
 print ?
  1. <span style="color:#009900;"><aop:aspect>  
  2.             <aop:declare-parents   
  3.                 types-matching="com.springinaction.springidol.Performer+"   
  4.                 implement-interface="com.springinaction.springidol.Contestant"  
  5.                 default-impl="com.springinaction.springidol.GraciousContestant"/>  
  6.         </aop:aspect></span>  

types-matching:类型匹配Performer接口的哪些Bean会实现implement-interface指定的Contestant接口。我们可以用default-impl属性来通过它的全限定类名来显示指定Contestant的实现。或者我们还可以使用delegate-ref属性来标识。

[html]  view plain  copy
 print ?
  1. <span style="color:#009900;"><bean id="contestantDelegate" class="com.springinaction.springidol.GraciousContestant" /></span>  

[html]  view plain  copy
 print ?
  1. <span style="color:#009900;"><aop:aspect>  
  2.             <aop:declare-parents   
  3.                 types-matching="com.springinaction.springidol.Performer+"   
  4.                 implement-interface="com.springinaction.springidol.Contestant"  
  5.                 delegate-ref="contestantDelegate"/>  
  6.         </aop:aspect></span>  


注解切面

[html]  view plain  copy
 print ?
  1. package com.springinaction.springidol;  
  2.   
  3. import org.aspectj.lang.annotation.AfterReturning;  
  4. import org.aspectj.lang.annotation.AfterThrowing;  
  5. import org.aspectj.lang.annotation.Aspect;  
  6. import org.aspectj.lang.annotation.Before;  
  7. import org.aspectj.lang.annotation.Pointcut;  
  8.   
  9. /**  
  10.  * 为选秀会定义观众  
  11.  * @author alone  
  12.  *  
  13.  */  
  14. @Aspect  
  15. public class Audience {  
  16.     @Pointcut("execution(* com.springinaction.springidol.Performer.perform(..))")  
  17.     public void performance() {  
  18.           
  19.     }  
  20.     @Before("performance()")  
  21.     public void takeSeats() {//表演之前  
  22.         System.out.println("The audience is taking their seats.");  
  23.     }  
  24.     @Before("performance()")  
  25.     public void turnOffCellPhones() {//表演之前  
  26.         System.out.println("The audience is turning off their cellphones");  
  27.     }  
  28.     @AfterReturning("performance()")  
  29.     public void applaud() {//表演之后  
  30.         System.out.println("CLAP CLAP CLAP CLAP CLAP");  
  31.     }  
  32.     @AfterThrowing("performance()")  
  33.     public void demandRefund() {//表演失败之后  
  34.         System.out.println("Boo! We want our money back!");  
  35.     }  
  36. }  

@Pointcut注解用于定义一个可以在@AspectJ切面内可重用的切点。@Pointcut注解是一个AspectJ切点表达式--这里标识该切点必须匹配Performer的perform()方法。切点的名称来源于注解所应用的方法名称。因此,该切点的名称为performance()。performance()方法的实际内容并不重要,在这里它事实上是空的。其实该方法本身只是一个标识,供@Pointcut注解依附。


该类仍然你可以像下面一样在Spring中进行装配:

[html]  view plain  copy
 print ?
  1. <bean id="audience" class="com.springinaction.springidol.Audience" />  

因为Audience类本身包含了所有它所需要定义的切点和通知,所以我们不再需要在XML配置中声明切点和通知。最后一件需要做的事是让Spring将Audience应用为一个切面。我们需要在Spring上下文中声明一个自动代理Bean,该Bean知道如何把@AspectJ注解所标注的Bean转变为代理通知。

Spring在aop命名空间中提供了一个自定义的配置元素:

[html]  view plain  copy
 print ?
  1. <aop:aspectj-autoproxy />  


注解环绕通知

[html]  view plain  copy
 print ?
  1. <span style="font-size:10px;">@Around("performance()")  
  2.     public void watchPerformance(ProceedingJoinPoint joinpoint) {  
  3.         try {  
  4.             System.out.println("The audience is taking their seats.");  
  5.             System.out.println("The audience is turning off their cellphones");  
  6.             long start = System.currentTimeMillis() ;  
  7.               
  8.             joinpoint.proceed() ;  
  9.               
  10.             long end = System.currentTimeMillis() ;  
  11.             System.out.println("CLAP CLAP CLAP CLAP CLAP");  
  12.             System.out.println("The performance took " + (end - start) + "millseconds.");  
  13.         } catch (Throwable e) {  
  14.             System.out.println("Boo! We want our money back!");  
  15.         }  
  16.     }</span>  


传递参数给所标注的通知

[html]  view plain  copy
 print ?
  1. package com.springinaction.springidol;  
  2.   
  3. import org.aspectj.lang.annotation.Aspect;  
  4. import org.aspectj.lang.annotation.Before;  
  5. import org.aspectj.lang.annotation.Pointcut;  
  6.   
  7. @Aspect  
  8. public class Magician implements MindReader {  
  9.     private String thoughts ;  
  10.     @Pointcut("execution(* com.springinaction.springidol.Thinker.thinkOfSomethinf(String) && args(thoughts))")  
  11.     public void thinking(String thoughts) {  
  12.     }  
  13.     @Before("thinking(thoughts)")  
  14.     public void interceptThoughts(String thoughts) {  
  15.         System.out.println("Intercepting volunteer's thoughts");  
  16.         this.thoughts = thoughts ;  
  17.     }  
  18.     @Override  
  19.     public String getThoughts() {  
  20.         return thoughts;  
  21.     }  
  22.   
  23. }  

标注引入

[html]  view plain  copy
 print ?
  1. package com.springinaction.springidol;  
  2.   
  3. import org.aspectj.lang.annotation.Aspect;  
  4. import org.aspectj.lang.annotation.DeclareParents;  
  5. @Aspect  
  6. public class ContestantIntroducer {  
  7.     @DeclareParents(  
  8.             value="com.springinaction.springidol.Performer+",  
  9.             defaultImpl=GraciousContestant.class  
  10.             )  
  11.     public static Contestant contestant ;  
  12. }  

value属性等同于<aop:declare-parents>的types-matching属性。它标识应该被引入接口的Bean的类型。

defaultImpl属性等同于<aop:declare-parents>的default-impl属性。它标识该类提供了所引入接口的实现。

由@DeclareParents注解所标注的static属性指定了将被引入的接口。


注入AspectJ切面

首先在AspectJ中创建一个裁判切面。JudgeAspect就是这样的一个切面。

[html]  view plain  copy
 print ?
  1. package com.springinaction.springidol;  
  2.   
  3. public aspect JudgeAspect {  
  4.     public JudgeAspect() {}  
  5.     pointcut performance() :execution(* perform(..)) ;  
  6.     after() returning() : performance() {  
  7.         System.out.println(criticismEngine.getCriticism()) ;  
  8.     }  
  9.     // injected  
  10.     private CriticismEngine criticismEngine ;  
  11.     public void setCriticismEngine(CrutucusnEbgube crutucusnEngine) {  
  12.         this.criticismEngine = criticismEngine ;  
  13.     }  
  14. }  

下面是JudgeAspect所使用的一个CriticismEngine的实现

[html]  view plain  copy
 print ?
  1. package com.springinaction.springidol;  
  2.   
  3. public class CriticismEngineImpl implements CriticismEngine{  
  4.     public CriticismEngineImpl() {}  
  5.     public String getCriticism() {  
  6.         int i = (int) (Math.random() * criticismPool.length) ;  
  7.         return criticismPool[i] ;  
  8.     }  
  9.     //injected  
  10.     private String[] criticismPool ;  
  11.     public void setCriticismPool(String[] criticismPool) {  
  12.         this.criticismPool = criticismPool ;  
  13.     }  
  14. }  

[html]  view plain  copy
 print ?
  1. <bean id="criticismEngine" class="com.springinaction.springidol.CriticismEngineImpl" >  
  2.         <property name="criticisms">  
  3.             <list>  
  4.                 <value>I'm not being rude,but that was appalling.</value>  
  5.                 <value>You may be the least talented person in this show.</value>  
  6.                 <value>Do everyone a favor and keep your day job.</value>                 
  7.             </list>  
  8.         </property>  
  9.     </bean>  

[html]  view plain  copy
 print ?
  1. <bean class="com.springinaction.springidol.JudgeAspect" factory-method="aspectOf">  
  2.         <property name="criticismEngine" ref="criticismEngine" />  
  3.     </bean>  

在展示如何实现注入之前,我们必须清楚AspectJ切面根本不需要Spring就可以织入进我们的应用中。但是如果想使用Spring的依赖注入为AspectJ切面注入协作者,那么就需要在Spring配置中把切面声明为一个Spring Bean。

很大程度上,<bean>的声明与我们在Spring中所看到的其他<bean>配置并没有太多的区别,但是最大的不通在于使用了factory-method属性。通常情况下,Spring Bean由Spring容器初始化,但是AspectJ切面是由AspectJ在运行期间创建的。等到Spring有几回为JudgeAspect注入CriticismEngine时,JudgeAspect已经被实例化了。

因为Spring无法负责创建JudgeAspect,那就不能在Spring中简单地将JudgeAspect声明为一个Bean。相反,我们需要一种方式为Spring获得已经由AspectJ创建的JudgeAspect实例的句柄,从而可以注入CriticismEngine。幸运的是,所有的AspectJ切面都提供了一个静态的aspectOf()方法,该方法返回切面的一个单利。所以为了获得切面的实例,我们必须使用factory-method来调用aspectOf()方法来代替调用JudgeAspect的构造器方法。

简而言之,Spring不能使用<bean>声明来创建一个JudgeAspect实例--它已经在运行时由AspectJ创建了。Spring通过aspectOf()工厂方法获得切面的引用,然后像<bean>元素规定的那样在该对象上执行依赖注入。


总结:

AOP是面向对象编程的一个强大补充。通过AspectJ,我们现在可以将之前分散在应用各处的行为放入可重用的模块中。我们显示地声明在何处如何应用该行为,这有效减少了代码冗余,并让我们的类关注自身的主要功能。

Spring提供了一个AOP框架,让我们把切面插入方法执行的周围。现在我们已经学会如何把通知织入前置、后置和环绕方法的调用中,以及为处理异常增加自定义的行为。

在Spring应用中如何使用切面,我们有几种选择。通过使用@AspectJ注解和简化的配置命名空间,在Spring中装配通知和切点变得非常简单。

最后,当SpringAOP不能满足需求时,我们必须转向更为强大的AspectJ。对于这些场景,我们了解了如何使用Spring为AspectJ切面注入依赖。

此时此刻,我们已经覆盖了Spring框架的基础知识。我们已经了解了如何配置Spring容器以及如何为Spring管理的对象应用切面。正如我们所看到的,这些核心技术为创建松散耦合的应用奠定了坚实的基础。

目录
相关文章
|
2月前
Micronaut AOP与代理机制:实现应用功能增强,无需侵入式编程的秘诀
AOP(面向切面编程)能够帮助我们在不修改现有代码的前提下,为应用程序添加新的功能或行为。Micronaut框架中的AOP模块通过动态代理机制实现了这一目标。AOP将横切关注点(如日志记录、事务管理等)从业务逻辑中分离出来,提高模块化程度。在Micronaut中,带有特定注解的类会在启动时生成代理对象,在运行时拦截方法调用并执行额外逻辑。例如,可以通过创建切面类并在目标类上添加注解来记录方法调用信息,从而在不侵入原有代码的情况下增强应用功能,提高代码的可维护性和可扩展性。
64 1
|
18天前
|
安全 Java 编译器
什么是AOP面向切面编程?怎么简单理解?
本文介绍了面向切面编程(AOP)的基本概念和原理,解释了如何通过分离横切关注点(如日志、事务管理等)来增强代码的模块化和可维护性。AOP的核心概念包括切面、连接点、切入点、通知和织入。文章还提供了一个使用Spring AOP的简单示例,展示了如何定义和应用切面。
54 1
什么是AOP面向切面编程?怎么简单理解?
|
23天前
|
XML Java 开发者
论面向方面的编程技术及其应用(AOP)
【11月更文挑战第2天】随着软件系统的规模和复杂度不断增加,传统的面向过程编程和面向对象编程(OOP)在应对横切关注点(如日志记录、事务管理、安全性检查等)时显得力不从心。面向方面的编程(Aspect-Oriented Programming,简称AOP)作为一种新的编程范式,通过将横切关注点与业务逻辑分离,提高了代码的可维护性、可重用性和可读性。本文首先概述了AOP的基本概念和技术原理,然后结合一个实际项目,详细阐述了在项目实践中使用AOP技术开发的具体步骤,最后分析了使用AOP的原因、开发过程中存在的问题及所使用的技术带来的实际应用效果。
51 5
|
1月前
|
Java 容器
AOP面向切面编程
AOP面向切面编程
42 0
|
2月前
Micronaut AOP与代理机制:实现应用功能增强,无需侵入式编程的秘诀
【9月更文挑战第9天】AOP(面向切面编程)通过分离横切关注点提高模块化程度,如日志记录、事务管理等。Micronaut AOP基于动态代理机制,在应用启动时为带有特定注解的类生成代理对象,实现在运行时拦截方法调用并执行额外逻辑。通过简单示例展示了如何在不修改 `CalculatorService` 类的情况下记录 `add` 方法的参数和结果,仅需添加 `@Loggable` 注解即可。这不仅提高了代码的可维护性和可扩展性,还降低了引入新错误的风险。
47 13
|
3月前
|
XML Java 数据格式
Spring5入门到实战------11、使用XML方式实现AOP切面编程。具体代码+讲解
这篇文章是Spring5框架的AOP切面编程教程,通过XML配置方式,详细讲解了如何创建被增强类和增强类,如何在Spring配置文件中定义切入点和切面,以及如何将增强逻辑应用到具体方法上。文章通过具体的代码示例和测试结果,展示了使用XML配置实现AOP的过程,并强调了虽然注解开发更为便捷,但掌握XML配置也是非常重要的。
Spring5入门到实战------11、使用XML方式实现AOP切面编程。具体代码+讲解
|
3月前
|
Java Spring XML
掌握面向切面编程的秘密武器:Spring AOP 让你的代码优雅转身,横切关注点再也不是难题!
【8月更文挑战第31天】面向切面编程(AOP)通过切面封装横切关注点,如日志记录、事务管理等,使业务逻辑更清晰。Spring AOP提供强大工具,无需在业务代码中硬编码这些功能。本文将深入探讨Spring AOP的概念、工作原理及实际应用,展示如何通过基于注解的配置创建切面,优化代码结构并提高可维护性。通过示例说明如何定义切面类、通知方法及其应用时机,实现方法调用前后的日志记录,展示AOP在分离关注点和添加新功能方面的优势。
55 0
|
4月前
|
Java Spring 容器
Spring问题之Spring AOP是如何实现面向切面编程的
Spring问题之Spring AOP是如何实现面向切面编程的
|
3月前
|
监控 安全 数据库
面向方面编程(AOP)的概念
【8月更文挑战第22天】
78 0
|
3月前
|
XML Java 数据库
Spring5入门到实战------10、操作术语解释--Aspectj注解开发实例。AOP切面编程的实际应用
这篇文章是Spring5框架的实战教程,详细解释了AOP的关键术语,包括连接点、切入点、通知、切面,并展示了如何使用AspectJ注解来开发AOP实例,包括切入点表达式的编写、增强方法的配置、代理对象的创建和优先级设置,以及如何通过注解方式实现完全的AOP配置。