AOP

什么是AOP

说起AOP,就让我想起了OOP。
AOP:Aspect Oriented Programming,面向切面编程
OOP:Object Oriented Programming,面向对象编程
我们都知道面向对象编程,是面向对象语言的核心。其本质是以建立模型体现出来的抽象思维过程和面向对象的方法。针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。OOP达到了软件工程的三个主要目标:重用性、灵活性和扩展性。OOP=对象+类+继承+多态+消息,其中核心概念是类和对象。
AOP,是通过预编译技术和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,它是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果,同时提高程序的可重用性和开发的效率。
简单来说,AOP就是把我们重复的代码抽取出来,在需要执行的时候,使用动态代理技术,在不修改源码的基础上,对已有的方法进行增强。说到这里,就不得不说动态代理。

动态代理

作用:不改变源码的基础上,对已有方法进行增强。它是AOP思想的实现技术
实现方式:

  1. 基于接口的动态代理
  • 要求:被代理类至少实现一个接口,implements object。
  • 提供者:JDK官方
  • 涉及的类:Proxy
  • 创建代理对象的方法:Proxy.newProxyInstance(ClassLoader, Class[], InvocationHandler)
  • 参数的含义:
    • ClassLoader:类加载器,和被代理对象使用相同的类加载器。一般都是固定写法:object.getClass().getClassLoader()
    • Class[]:字节码数组,被代理类实现的接口,要求代理对象和被代理对象具有相同的行为。一般也是固定写法:object.getClass().getInterfaces()
    • InvocationHandler:它是一个接口,就是用于提供增强代码的。一般是写一个该接口的实现类,该实现类可以是匿名内部类,也可以不是。
      • 它的含义就是:如何代理。此处的代码只能是谁用谁提供。
      • 设计模式:策略模式
      • 使用要求:数据已经存在,接口中的参数就是提供的数据;目的明确,最终的结果就是对方法的增强,至于增强的内容,并不关注达成目标的过程就是策略。在dbUtils中的ResultSetHandler就是策略模式的具体应用。
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
    * 模拟一个剧组
    * @author zhuow
    *
    */
    public class Client
    {
    	public static void main(String[] args)
    	{
        	final Actor actor = new Actor();
        	/*
         	* actor.basicAct(100); actor.dangerAct(500);
         	*/
        	IActor proxyActor = (IActor) Proxy.newProxyInstance(
                	actor.getClass().getClassLoader(),
                	actor.getClass().getInterfaces(), new InvocationHandler()
                	{
                    	/**
                     	* 执行被代理对象的任何方法都会经过该方法,该方法具有拦截的功能
                     	* 方法的参数:
                     	*     Object proxy:代理对象的引用。不一定每次都会用。
                     	*     Method method:当前执行的方法
                     	*     Object[] args:当前执行方法所需的参数
                     	*     返回值:当前执行方法的返回值
                     	*/
                    	public Object invoke(Object proxy, Method method,
                            	Object[] args) throws Throwable
                    	{
                        	Object result = null;
                        	// 1.取出方法中的参数
                        	Float money = (Float)args[0];
                        	// 2.判断当前执行的是什么方法
                        	if ("basicAct".equals(method.getName()))
                        	{
                            	if (money > 10000)
                            	{
                                	// 3.执行方法
                                	result = method.invoke(actor, money/2);
                            	}
                        	}
                        	else if ("dangerAct".equals(method.getName()))
                        	{
                            	if (money > 50000)
                            	{
                                	result = method.invoke(actor, money/2);
                            	}
                        	}
                        	return result;
                    	}
                	});
        	proxyActor.basicAct(20000);
        	proxyActor.dangerAct(60000);
    	}
    }
    
  1. 基于子类的动态代理
  • 要求:被代理类不能是最终类,不能被final修饰
  • 提供者:第三方CGLib
  • 涉及的类:Enhancer
  • 创建代理对象的方法:create(Class,Callback)
  • 参数的含义:
    • Class:被代理对象的字节码
    • Callback:如何代理。作用和InvocationHandler的作用相同。它也是一个接口,我们一般使用该接口的子接口MethodInterceptor。在使用时,创建该接口的实现类,可以是匿名接口类。
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    /**
     * 模拟一个剧组
     * @author zhuow
     *
     */
    public class Client
    {
    	public static void main(String[] args)
    	{
        	final Actor actor = new Actor();
        	/*
        	 * actor.basicAct(100); actor.dangerAct(500);
        	 */
        	Actor proxyActor = (Actor) Enhancer.create(actor.getClass(), new MethodInterceptor() {
            	/**
            	 * 执行被代理对象的任何方法,都会经过该方法。它和基于接口动态代理的invoke方法的作用相同
            	 * 
            	 * @param obj
            	 * @param method
            	 * @param args
            	 * @param proxy 当前执行方法的代理对象,一般不用。
            	 * @return
            	 * @throws Throwable
            	 */
            	public Object intercept(Object obj, Method method, Object[] args,
                    	MethodProxy proxy) throws Throwable
            	{
                	Object result = null;
                	// 1.取出方法中的参数
                	Float money = (Float)args[0];
                	// 2.判断当前执行的是什么方法
                	if ("basicAct".equals(method.getName()))
                	{
                    	if (money > 10000)
                    	{
                        	// 3.执行方法
                        	result = method.invoke(actor, money/2);
                    	}
                	}
                	else if ("dangerAct".equals(method.getName()))
                	{
                    	if (money > 50000)
                    	{
                        	result = method.invoke(actor, money/2);
                    	}
                	}
                	return result;
            	}
        	});
        	proxyActor.basicAct(20000);
        	proxyActor.dangerAct(60000);
    	}
    }
    

Spring中的AOP

在Spring中,框架会根据目标类是否实现了接口来决定采用哪种动态代理方式。

AOP相关术语

  1. Joint point(连接点):
    所谓连接点就是指那些被拦截到的点,即被代理接口类中的方法。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点。
  2. Pointcut(切入点):
    所谓切入点,就是指我们要对哪些Jointpoint进行拦截的定义,即拦截到的方法中,进行增强的方法就是切入点。
  3. Advice(通知/增强):
    所谓通知是指拦截到Jointpoint之后要做的事情,也就是相较原方法,增强的部分就是通知。而通知类型有前置通知、后置通知、异常通知、最终通知、环绕通知。按照try{}catch{}finally{}来说,在invoke原方法之前就是前置通知,invoke原方法之后就是后置通知,catch中的是异常通知,finally中的是最终通知,而整个重载的invoke方法则是环绕通知,在环绕通知中有明确的invoke切入点方法调用。
  4. Introduction(引介):
    引介是一种特殊的通知,在不修改代码的前提下,Introduction可以在运行期为类动态地添加一些方法或Field。一般不用。
  5. Target object(目标对象):
    代理的目标对象,即被代理对象。
  6. Weaving(织入):
    是指把增强应用到目标对象来创建新的代理对象的过程;spring采用动态代理织入,而Aspect采用编译期织入或类装载期织入。即加入增强代码,构成完整业务逻辑的过程。
  7. Proxy(代理):
    一个类被AOP织入增强后,就产生一个结果代理类
  8. Aspect(切面):
    是切人点和通知(引介)的结合

学习spring AOP要明确的事

  1. 开发阶段
    编写核心业务代码(开发主线):大部分程序员来做,要求熟悉业务需求
    把共用代码抽取出来,制作成通知:开发阶段最后做。
    在配置文件中,声明切入点与通知间的关系,即切面。
  2. 运行阶段
    Spring框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,在根据通知的类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。

AOP实现

这里只说注解实现,如果对xml配置感兴趣,可以查看官方文档。

  1. @EnableAspectJAutoProxy
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}
  1. @Aspect
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class NotVeryUsefulAspect {
}
  1. @Pointcut
@Pointcut("execution(* transfer(..))") // 切入点表达式
private void anyOldTransfer() {} // 切入点签名,将此签名代入下面的通知声明中,会更加方便。

Spring AOP支持在切入点中使用的以下AspectJ切入点指示符(PCD)表达式:
execute:用于匹配方法执行的连接点。这是主要切入点使用Spring AOP时要使用的标识符。
inside:限制匹配某些类型内的连接点(方法的声明类型匹配)。
this:限制匹配的连接点,其中bean的引用是给定类型的实例。
target:限制匹配连接点,其中目标对象(代理的应用程序对象)是给定类型的实例。
args:限制匹配连接点,其中参数是给定类型的实例。
@target:限制匹配连接点,其中执行对象的类具有给定类型的注解。
@args:限制匹配连接点,传递的实际参数的运行时类型具有给定类型的注解。
@within:将匹配限制为具有给定注释(执行具有给定注释的类型中声明的方法)。
@annotation:限制匹配项连接点,连接点的主题具有特定的注解。

  1. @Before
    前置通知
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
	@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
	public void doAccessCheck() {
	// ...
	}
}
  1. @AfterReturning
    后置通知
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class AfterReturningExample{
	@AfterReturning(pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()", returning="retVal")
	public void doAccessCheck(Object retVal) {
	// ...
	}
}
  1. @AfterThrowing
    异常通知
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class AfterThrowingExample{
	@AfterThrowing(pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",throwing="ex")
	public void doRecoveryActions(DataAccessException ex) {
	// ...
	}
}
  1. @After
    最终通知
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.After;
@Aspect
public class AfterFinallyExample{
	@After("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
	public void doReleaseLock() {
	// ...
	}
}
  1. @Around
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;
@Aspect
public class AroundExample {
	@Around("com.xyz.myapp.SystemArchitecture.businessService()")
	public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
	// start stopwatch
	Object retVal = pjp.proceed();  //执行原逻辑
	// stop stopwatch
	return retVal;
	}
}
标题“51单片机通过MPU6050-DMP获取姿态角例程”解析 “51单片机通过MPU6050-DMP获取姿态角例程”是一个基于51系列单片机(一种常见的8位微控制器)的程序示例,用于读取MPU6050传感器的数据,并通过其内置的数字运动处理器(DMP)计算设备的姿态角(如倾斜角度、旋转角度等)。MPU6050是一款集成三轴加速度计和三轴陀螺仪的六自由度传感器,广泛应用于运动控制和姿态检测领域。该例程利用MPU6050的DMP功能,由DMP处理复杂的运动学算法,例如姿态融合,将加速度计和陀螺仪的数据进行整合,从而提供稳定且实时的姿态估计,减轻主控MCU的计算负担。最终,姿态角数据通过LCD1602显示屏以字符形式可视化展示,为用户提供直观的反馈。 从标签“51单片机 6050”可知,该项目主要涉及51单片机和MPU6050传感器这两个关键硬件组件。51单片机基于8051内核,因编程简单、成本低而被广泛应用;MPU6050作为惯性测量单元(IMU),可测量设备的线性和角速度。文件名“51-DMP-NET”可能表示这是一个与51单片机及DMP相关的网络资源或代码库,其中可能包含C语言等适合51单片机的编程语言的源代码、配置文件、用户手册、示例程序,以及可能的调试工具或IDE项目文件。 实现该项目需以下步骤:首先是硬件连接,将51单片机与MPU6050通过I2C接口正确连接,同时将LCD1602连接到51单片机的串行数据线和控制线上;接着是初始化设置,配置51单片机的I/O端口,初始化I2C通信协议,设置MPU6050的工作模式和数据输出速率;然后是DMP配置,启用MPU6050的DMP功能,加载预编译的DMP固件,并设置DMP输出数据的中断;之后是数据读取,通过中断服务程序从DMP接收姿态角数据,数据通常以四元数或欧拉角形式呈现;再接着是数据显示,将姿态角数据转换为可读的度数格
MathorCup高校数学建模挑战赛是一项旨在提升学生数学应用、创新和团队协作能力的年度竞赛。参赛团队需在规定时间内解决实际问题,运用数学建模方法进行分析并提出解决方案。2021年第十一届比赛的D题就是一个典型例子。 MATLAB是解决这类问题的常用工具。它是一款强大的数值计算和编程软件,广泛应用于数学建模、数据分析和科学计算。MATLAB拥有丰富的函数库,涵盖线性代数、统计分析、优化算法、信号处理等多种数学操作,方便参赛者构建模型和实现算法。 在提供的文件列表中,有几个关键文件: d题论文(1).docx:这可能是参赛队伍对D题的解答报告,详细记录了他们对问题的理解、建模过程、求解方法和结果分析。 D_1.m、ratio.m、importfile.m、Untitled.m、changf.m、pailiezuhe.m、huitu.m:这些是MATLAB源代码文件,每个文件可能对应一个特定的计算步骤或功能。例如: D_1.m 可能是主要的建模代码; ratio.m 可能用于计算某种比例或比率; importfile.m 可能用于导入数据; Untitled.m 可能是未命名的脚本,包含临时或测试代码; changf.m 可能涉及函数变换; pailiezuhe.m 可能与矩阵的排列组合相关; huitu.m 可能用于绘制回路图或流程图。 matlab111.mat:这是一个MATLAB数据文件,存储了变量或矩阵等数据,可能用于后续计算或分析。 D-date.mat:这个文件可能包含与D题相关的特定日期数据,或是模拟过程中用到的时间序列数据。 从这些文件可以推测,参赛队伍可能利用MATLAB完成了数据预处理、模型构建、数值模拟和结果可视化等一系列工作。然而,具体的建模细节和解决方案需要查看解压后的文件内容才能深入了解。 在数学建模过程中,团队需深入理解问题本质,选择合适的数学模
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值