AOP面向切面编程

本文介绍了代理模式的基本概念,包括静态代理与动态代理,并详细解析了JDK动态代理与CGLIB的工作原理及应用场景。此外,还深入探讨了面向切面编程(AOP)的基本原理及其在Java中的实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代理模式

定义一个类后,如果在不修改类的前提下,对类进行方法的扩充,譬如添加方法。可以通过继承这个类,在对这个类的方法进行重写,从而达到不修改类的前提下对类进行增强;
除此之外,还可以使用代理的方式;
代理分为:

  1. 静态代理

  2. 动态代理
    动态代理又有
    1. jdk的动态代理
    2. cglib
    jdk的动态代理中,会自动创建一个代理类对象,这个代理类对象会实现目标对象的所有接口,所以代理类对象和目标对象是同一等级的;从而得出三个结论:

    1. 目标对象至少实现一个接口
    2. 代理对象无法调用目标对象的类中有自己的方法
    3. 代理对象不能强转成目标对象类型,只能转成实现的接口类型

    cglib:
    jdk的动态代理中的目标对象必须实现至少一个接口,那如果我所需要代理的类不实现任何接口呢,那就需要用到clib动态的代理;
    cgllib是通过自动创建目标类的子类,然后在子类中修改方法,从而实现对目标对象的功能扩展;
    Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展间java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截);
    Cglib包的底层是通过使用一个小块的字节码处理框架ASM来转换字节码并生成新的类.不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
    cglib代理实现方法:

    1. 需要引入cglib的jar文件,但是Spring的核心包中已经包括了Cglib功能,直接引入spring-core-3.2.5.jar是不行的,因为这个核心包与其他包有依赖关系
    2. 引入功能包后就可以在内存中动态创建实例
    3. 代理的类不能为final,否则报错;因为final修饰的类不能被继承
    4. 目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法。
      cglib的具体使用方法:
      创建目标对象类Man.java
public class Man{
     public void eat() {
          System.out.println("喝酒");
     }
}

创建代理工厂ProxyFactory.java

public class ProxyFactory implements MethodInterceptor{
     private Object target;
     
     public ProxyFactory(Object target) {
          this.target = target;
     }

     public Object newInstance() {
         // 工具类对象
          Enhancer hancer = new Enhancer();
          // 设置父类
          hancer.setSuperclass(target.getClass());
          // 回调,其实就是调用 MethodInterceptor接口实现类的intercept方法
          hancer.setCallback(this);
          // 返回创建的代理类
          return hancer.create();      
     }
     
     @Override
     public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {       
          before();
          arg1.invoke(target, arg2);
          after();
          return null;
     }

     
     public void before() {
          System.out.println("抽烟");
     }
   
     public void after() {
          System.out.println("烫头");
     }
}

测试:

public class Test {
     public static void main(String[] args) {
          Man man = new Man();
         ProxyFactory proxyFactory = new ProxyFactory(man);
          Man newInstance = (Man)proxyFactory.newInstance();
         newInstance.eat();
     }
}

AOP面向切面编程

Aop(Aspect Oriented Programing)面向切面编程,它是一种编程思想,它采用的横向抽取机制,取代了传统的继承纵向继承体系重复性代码(性能监视、事务管理,安全检查,缓存)

普通AOP开发

  1. JoinPoint(连接点)
  2. PointCut(切入点)
  3. Advice(通知/增强)
  4. Introduction(引介)

编写目标类Man.java

public class Man{
    public void eat() {
          System.out.println("喝酒");
     }
}

1. 前置通知:

前置通知,即能够实现在目标类执行之前增加一些方法
前置通知需实现MethodBeforeAdvice接口,并实现它的before方法,在这个方法中可以定义需要在目标类执行之前的添加的功能;

public class MyBeforeAdvice implements MethodBeforeAdvice{
     @Override
     public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
          System.out.println("抽烟");
     }
}

当然,在定义了前置通知的类的后,为了能时目标类执行之前执行添加的功能,应该要搭建一个桥梁,连接这两个类;所以需要在配置文件中搭建这个这个桥梁。
首先,在applicationContext.xml文件中声明目标类对象以及前置增强类对象,然后搭建这两个对象之间的强梁;

<bean id="man" class="com.sxt.bean.Man"></bean>

<bean id="myBeforeAdvice" class="com.sxt.bean.MyBeforeAdvice"></bean>
<aop:config>
     <aop:pointcut expression="execution(* com.sxt.bean.Man.*())" id="pc"/>
    <!--advice-ref的值是前置增强对象的id,pointcut-ref的值是aop:pointcut标签的ID-->
     <aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="pc"/>
</aop:config>

2. 后置通知

与前置通知的意义是一样的,只不过后置增强是在目标类执行之后添加的功能;
后置通知需要实现AfterReturningAdvice接口,并且实现他的afterReturning类

public class MyAfterAdvice implements AfterReturningAdvice{
     @Override
     public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
          System.out.println("烫头");
     }
}

定义了后置通知的类后也需要与目标类搭建桥梁,首先,在applicationContext.xml文件中声明目标类对象以及后置通知类对象,然后搭建这两个对象之间的强梁;

<bean id="man" class="com.sxt.bean.Man"></bean>
<bean id="myAfterAdvice" class="com.sxt.bean.MyAfterAdvice"></bean>
<aop:config>
     <aop:pointcut expression="execution(* com.sxt.bean.Man.*())" id="pc"/>
     <aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="pc"/>
     <aop:advisor advice-ref="myAfterAdvice" pointcut-ref="pc"/>
</aop:config>

3. 环绕通知

环绕通知可以视为前置通知和后置通知的叠加,其效果是一样的
环绕通知类需要实现MethodInterceptor接口,并且实现它的invoke方法;
注意:此处的MethodInterceptor接口是org.aopalliance.intercept包下的

public class MyArroundAdvice implements MethodInterceptor{
/*
* arg0.proceed();的作用是执行目标对象的方法
*/
     @Override
     public Object invoke(MethodInvocation arg0) throws Throwable {
          System.out.println("抽烟");
          arg0.proceed();
          System.out.println("烫头");
          return null;      
     }
}       

环绕通知在applicationContext.xml文件中的配置如下

<bean id="man" class="com.sxt.bean.Man"></bean>
<bean id="myArroundAdvice" class="com.sxt.bean.MyArroundAdvice"></bean>

<aop:config>
     <aop:pointcut expression="execution(* com.sxt.bean.Man.*())" id="pc"/>
     <aop:advisor advice-ref="myArroundAdvice" pointcut-ref="pc"/>
</aop:config>

4. 异常通知

异常通知是在目标对象执行过程中发生了异常后,需要添加的功能;
先定义一个异常通知类,这个类需要实现ThrowsAdvice接口,这个接口是空的,没有需要实现的方法。为了 添加需要的功能,需要在这个类中写一个方法。但是,这里需要注意,虽然没有实现方法,可以写一个方法,但是这个方法的名称必须为afterThrowing,并且需要接受一个Throwable对象,否则就会报错

public class MyExceptionAdvice implements ThrowsAdvice{
     public void afterThrowing(Throwable tw) throws Throwable {
          System.out.println("====发生了异常======");
     }    
}

异常通知在applicationContext.xml文件中的配置如下

<bean id="man" class="com.sxt.bean.Man"></bean>
<bean id="myExceptionAdvice" class="com.sxt.bean.MyExceptionAdvice"></bean>

<aop:config>
     <aop:pointcut expression="execution(* com.sxt.bean.Man.*())" id="pc"/>
     <aop:advisor advice-ref="myExceptionAdvice" pointcut-ref="pc"/>
</aop:config>
总结:

由以上的各段代码可以的到一个规律,普通AOP开发的配置文件的方法,不同的通知,其配置的形式都是一样的;
每一个通知类都是实现了一个接口,并且实现了它的一个方法,在这个方法中定义功能;但异常通知是一个意外,它所实现的接口并没有需要实现的方法,所以这个方法需要自己写。

内容概要:本文深入探讨了Kotlin语言在函数式编程和跨平台开发方面的特性和优势,结合详细的代码案例,展示了Kotlin的核心技巧和应用场景。文章首先介绍了高阶函数和Lambda表达式的使用,解释了它们如何简化集合操作和回调函数处理。接着,详细讲解了Kotlin Multiplatform(KMP)的实现方式,包括共享模块的创建和平台特定模块的配置,展示了如何通过共享业务逻辑代码提高开发效率。最后,文章总结了Kotlin在Android开发、跨平台移动开发、后端开发和Web开发中的应用场景,并展望了其未来发展趋势,指出Kotlin将继续在函数式编程和跨平台开发领域不断完善和发展。; 适合人群:对函数式编程和跨平台开发感兴趣的开发者,尤其是有一定编程基础的Kotlin初学者和中级开发者。; 使用场景及目标:①理解Kotlin中高阶函数和Lambda表达式的使用方法及其在实际开发中的应用场景;②掌握Kotlin Multiplatform的实现方式,能够在多个平台上共享业务逻辑代码,提高开发效率;③了解Kotlin在不同开发领域的应用场景,为选择合适的技术栈提供参考。; 其他说明:本文不仅提供了理论知识,还结合了大量代码案例,帮助读者更好地理解和实践Kotlin的函数式编程特性和跨平台开发能力。建议读者在学习过程中动手实践代码案例,以加深理解和掌握。
内容概要:本文深入探讨了利用历史速度命令(HVC)增强仿射编队机动控制性能的方法。论文提出了HVC在仿射编队控制中的潜在价值,通过全面评估HVC对系统的影响,提出了易于测试的稳定性条件,并给出了延迟参数与跟踪误差关系的显式不等式。研究为两轮差动机器人(TWDRs)群提供了系统的协调编队机动控制方案,并通过9台TWDRs的仿真和实验验证了稳定性和综合性能改进。此外,文中还提供了详细的Python代码实现,涵盖仿射编队控制类、HVC增强、稳定性条件检查以及仿真实验。代码不仅实现了论文的核心思想,还扩展了邻居历史信息利用、动态拓扑优化和自适应控制等性能提升策略,更全面地反映了群体智能协作和性能优化思想。 适用人群:具备一定编程基础,对群体智能、机器人编队控制、时滞系统稳定性分析感兴趣的科研人员和工程师。 使用场景及目标:①理解HVC在仿射编队控制中的应用及其对系统性能的提升;②掌握仿射编队控制的具体实现方法,包括控制器设计、稳定性分析和仿真实验;③学习如何通过引入历史信息(如HVC)来优化群体智能系统的性能;④探索中性型时滞系统的稳定性条件及其在实际系统中的应用。 其他说明:此资源不仅提供了理论分析,还包括完整的Python代码实现,帮助读者从理论到实践全面掌握仿射编队控制技术。代码结构清晰,涵盖了从初始化配置、控制律设计到性能评估的各个环节,并提供了丰富的可视化工具,便于理解和分析系统性能。通过阅读和实践,读者可以深入了解HVC增强仿射编队控制的工作原理及其实际应用效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值