浅析Spring Aop源码

本文通过分析Spring AOP的源码,探讨AopService的test方法如何实现增强,详细介绍了从getBean方法开始的调试过程,揭示了bean在Spring初始化阶段如何转化为代理对象。在分析过程中,发现了关键步骤如applyBeanPostProcessorsAfterInitialization方法在实现AOP增强中的作用。

        Aop作为Spring的一个重要组成部分,有着举足轻重的位置,因此有必要去深入了解实现原理。

        在现在的面试或者同事之间聊天的时候,我们都习惯去这样回答Aop:Aop就是面向切面编程,实现原理就是动态代理(jdk代理或者cglib代理),应用于Spring的事务和日志打印等场景。

        不知道你发现问题没有,上述的回答很虚(评论性见解,并非工程学见解),谁都可以说出来这就几句话,失去了其独到的意义。作为爱折腾的我们,需要去探究、去实践,掌握根本才能决胜于千里。

        下面我们开始进行Aop的源码分析:

        为了方便进行源码分析,我们先使用一下Spring为我们提供的Aop功能,这样也为我们进行Debug调试提供入口。

AopMain .java

public class AopMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        annotationConfigApplicationContext.getBean(AopService.class).test();
    }
}

AppConfig.java

@Configuration
@ComponentScan({"com.dflm"})
@EnableAspectJAutoProxy
public class AppConfig {
}

AopService.java

@Component
public class AopService implements  Service{

    public void test(){
        System.out.println("AopService 的 test方法被执行");
    }
}

解释:上述的AopMain就是入口类,AppConfig就是取代xml的配置类,AopService就是需要增强的类。

开始分析源码(下面的源码都是idea进行反编译的源码):

我们关注点是Aop,那么我们就需要关注AopService的test方法是如何实现增强的。那么对下属代码的getBean方法进行Debug.

annotationConfigApplicationContext.getBean(Service.class).test();

1、进入方法后的截图

2、继续进入到getBean方法

3、根据上述的结果可知,beanNames的长为1,那么直接进入到getBean方法。

4、进入到一个空壳方法

5、继续进入到具体的实现方法

6、由于装入的bean太多,上述设置了条件断点,因此再关闭应用,再调试进入到这个端点。观察取出的结果。

发现这个时候获取的aopService对象根本不存在。那么这个可以猜想:这一步是再spring初始化进行得操作,所以这个时候我们再最开始入口类得getBean下个断点;

居然这个时候进入到了入口类得断点处。

7、由于我们开始再getBean已经下过断点,此时只是需要下一步,进入到获取aopService得代码处。

8、这个时候能够从中取出aopService对象,而且是代理对象。那么这个时候需要先去getSingleTon中查看如何获取得aopService代理对象。

9、可以知道aopService是从一个ConcurrentHashMap中取出来的,而且取出来的时候,就已经是代理对象了。那么我们现在需要考虑两个问题:一是这个ConcurrentHashMap是什么时候放入的数据呢?二是我们的原生service去哪里了呢?那么带着这个问题,再进行分析,使用idea得全局查找this.singletonObjects.put,因为这是缓存保存的地方。

10、点击进入到上述查询的位置,并打上断点,此时去除其余的断点,重新启动应用。

11、查看左下侧的调用栈

12、逐个进行分析调用栈的方法,可以定位到如下代码,因为这个方法传入的参数是后面取出对象的关键。

13、由于ObjectFacory是一个接口类,因此我们关注他的实现方法createBean,进入实现代码中。

14、继续进入到doCreateBean方法中,发现我们的initializeBean方法是关键,居然把原生的bean转为了代理bean.

15、那么现在的重要的方法就是initializeBean方法,继续进入,发现方法里面主要的aop的代码就是applyBeanPostProcessorsAfterInitialization方法实现的。

16、继续进入到applyBeanPostProcessorsAfterInitialization方法实现.

17、再次断点进入到beanProcessor.postProcessAfterInitialization的方法实现。

断点完毕;

那么为了更好的去理解上述的bean后处理器,所以我们来写一个案例去辅助理解。

AopMain.java

public class AopMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        annotationConfigApplicationContext.getBean(Service.class).test();
    }
}

AppConfig.java

@Configuration
@ComponentScan({"com.dflm"})
@EnableAspectJ
public class AppConfig {
}

AopService.java

@Component
public class AopService implements  Service{

    public void test(){
        System.out.println("AopService 的 test方法被执行");
    }
}

Service.java

public interface Service {
    public void test();
}

EurekaAspectJ.java

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import(MyBenaPostprossor.class)
public @interface EurekaAspectJ {
}

MyBenaPostprossor.java

public class MyBenaPostprossor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }


    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if(beanName.equals("aopService")){
            return Proxy.newProxyInstance(MyBenaPostprossor.class.getClassLoader(),new Class[]{Service.class}, new MyInvocationHandler(bean));
        }
        return bean;
    }
}

MyInvocationHandler.java

public class MyInvocationHandler implements InvocationHandler {
    Object object;

    public MyInvocationHandler(Object object){
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理方法进来了");
        return method.invoke(object,args);
    }
}

 

本指南详细阐述基于Python编程语言结合OpenCV计算机视觉库构建实时眼部状态分析系统的技术流程。该系统能够准确识别眼部区域,并对眨眼动作与持续闭眼状态进行判别。OpenCV作为功能强大的图像处理工具库,配合Python简洁的语法特性与丰富的第三方模块支持,为开发此类视觉应用提供了理想环境。 在环境配置阶段,除基础Python运行环境外,还需安装OpenCV核心模块与dlib机器学习库。dlib库内置的HOG(方向梯度直方图)特征检测算法在面部特征定位方面表现卓越。 技术实现包含以下关键环节: - 面部区域检测:采用预训练的Haar级联分类器或HOG特征检测器完成初始人脸定位,为后续眼部分析建立基础坐标系 - 眼部精确定位:基于已识别的人脸区域,运用dlib提供的面部特征点预测模型准确标定双眼位置坐标 - 眼睑轮廓分析:通过OpenCV的轮廓提取算法精确勾勒眼睑边缘形态,为状态判别提供几何特征依据 - 眨眼动作识别:通过连续帧序列分析眼睑开合度变化,建立动态阈值模型判断瞬时闭合动作 - 持续闭眼检测:设定更严格的状态持续时间与闭合程度双重标准,准确识别长时间闭眼行为 - 实时处理架构:构建视频流处理管线,通过帧捕获、特征分析、状态判断的循环流程实现实时监控 完整的技术文档应包含模块化代码实现、依赖库安装指引、参数调优指南及常见问题解决方案。示例代码需具备完整的错误处理机制与性能优化建议,涵盖图像预处理、光照补偿等实际应用中的关键技术点。 掌握该技术体系不仅有助于深入理解计算机视觉原理,更为疲劳驾驶预警、医疗监护等实际应用场景提供了可靠的技术基础。后续优化方向可包括多模态特征融合、深度学习模型集成等进阶研究领域。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值