广告
返回顶部
首页 > 资讯 > 精选 >spring aop底层原理及实现方法
  • 654
分享到

spring aop底层原理及实现方法

2023-06-14 19:06:51 654人浏览 薄情痞子
摘要

这篇文章主要介绍spring aop底层原理及实现方法,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!使用要分析spring aop的底层原理,首先要会使用,先创建一个普通Maven WEBapp项目,引入spring

这篇文章主要介绍spring aop底层原理及实现方法,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

使用

要分析spring aop的底层原理,首先要会使用,先创建一个普通Maven WEBapp项目,引入spring-context依赖,版本为5.1.1RELEASE

<dependency>      <groupId>org.springframework</groupId>      <artifactId>spring-context</artifactId>      <version>5.1.1.RELEASE</version>    </dependency>

然后我使用aspectj作为aop的语法实现,和spring整合起来

<dependency>      <groupId>org.aspectj</groupId>      <artifactId>aspectjweaver</artifactId>      <version>1.9.4</version>    </dependency>

接下来我全称用注解的形式来模拟spring aop的使用,先创建一个配置类去扫描包,开启aspectJ的自动代理支持

@Configuration@EnableAspectJAutoProxy@ComponentScan("com.ww")public class Wconfig {}

然后新建一个接口和接口的实现类

public interface Dao {    void query();}@Componentpublic class IndexDao implements Dao{    @Override    public void query() {        System.out.println("query......");    }}

创建切面

//代表是一个切面@Aspect@Componentpublic class WAspect {        @Pointcut("execution(* com.ww.dao.*.*(..))")    public void point(){    }        @Before("point()")    public void beforeAd(){        System.out.println("before-------------");    }}

创建测试方法

public class TestAspect {    public static void main(String[] args) {        AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext(Wconfig.class);        Dao dao = configApplicationContext.getBean(Dao.class);        dao.query();    }}

执行方法,可以看到在打印query...之前打印了before----------

spring aop底层原理及实现方法

这个时候我们很想知道为什么这句before会打印在query之前呢,稍微对spring aop有所了解的人应该知道,spring是通过动态代理和字节码技术来实现aop操作的,也就是经常说的jdk动态代理和cglib动态代理两种模式,那么,spring究竟是怎么创建的代理对象,又是什么时候产生的代理对象呢,下面我们来一起探究一下源码,来揭开这个谜底

源码分析

首先我们透过现象看本质,我先把断点打在测试方法的最后一行,我们来看这个时候的dao对象

spring aop底层原理及实现方法

那么接下来我们就要去找到什么时候这个dao对象变成了动态代理对象的,既然在最后一行的时候对象已经变成了代理对象,那么我门自然就猜想是在上一句代码的位置spring执行了创建代理对象的操作,我们把断点移到上一行,debug进去

spring aop底层原理及实现方法

再往下走

spring aop底层原理及实现方法

这行代码我看方法名觉得应该是有用的代码,方法意思应该是spring处理好的bean,跟进去看看

@Nullableprivate <T> T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {        //这行代码最有用,处理有beanName的bean,debug进入看一下NamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull);if (namedBean != null) {return namedBean.getBeanInstance();}BeanFactory parent = getParentBeanFactory();if (parent instanceof DefaultListableBeanFactory) {return ((DefaultListableBeanFactory) parent).resolveBean(requiredType, args, nonUniqueAsNull);}else if (parent != null) {ObjectProvider<T> parentProvider = parent.getBeanProvider(requiredType);if (args != null) {return parentProvider.getObject(args);}else {return (nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable());}}return null;}
@SuppressWarnings("unchecked")@Nullableprivate <T> NamedBeanHolder<T> resolveNamedBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {Assert.notNull(requiredType, "Required type must not be null");Class<?> clazz = requiredType.getRawClass();Assert.notNull(clazz, "Required type must have a raw Class");        //候选name列表,直觉告诉我这行代码比较重要String[] candidateNames = getBeanNamesForType(requiredType);if (candidateNames.length > 1) {List<String> autowireCandidates = new ArrayList<>(candidateNames.length);for (String beanName : candidateNames) {if (!containsBeanDefinition(beanName) || getBeanDefinition(beanName).isAutowireCandidate()) {autowireCandidates.add(beanName);}}if (!autowireCandidates.isEmpty()) {candidateNames = StringUtils.toStringArray(autowireCandidates);}}        //因为我的代码里只有一个bean,所以我觉得应该会执行这里的代码if (candidateNames.length == 1) {String beanName = candidateNames[0];return new NamedBeanHolder<>(beanName, (T) getBean(beanName, clazz, args));}else if (candidateNames.length > 1) {Map<String, Object> candidates = new LinkedHashMap<>(candidateNames.length);for (String beanName : candidateNames) {if (containsSingleton(beanName) && args == null) {Object beanInstance = getBean(beanName);candidates.put(beanName, (beanInstance instanceof NullBean ? null : beanInstance));}else {candidates.put(beanName, getType(beanName));}}String candidateName = determinePrimaryCandidate(candidates, clazz);if (candidateName == null) {candidateName = determineHighestPriorityCandidate(candidates, clazz);}if (candidateName != null) {Object beanInstance = candidates.get(candidateName);if (beanInstance == null || beanInstance instanceof Class) {beanInstance = getBean(candidateName, clazz, args);}return new NamedBeanHolder<>(candidateName, (T) beanInstance);}if (!nonUniqueAsNull) {throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());}}return null;}

执行完getBeanNamesForType(requiredType)后,我们看idea的变量显示,果然有一个bean,name是IndexDao

spring aop底层原理及实现方法

那么接下来自然会进到length==1的那个代码块,这时候我再debug进入,这里还是一个getBean方法

spring aop底层原理及实现方法

spring aop底层原理及实现方法

在spring容器中还有一些没有name的其他的bean需要被创建,所以这里我用上了条件断点,当beanName等于indexDao的时候,才会进入断点,但是当我F8跑完这行代码的时候,出乎意料的事情发生了

spring aop底层原理及实现方法

惊不惊喜,意不意外,getSingleton这行代码执行结束之后,代理对象就已经被创建了,所以需要debug进入这行代码去看

protected Object getSingleton(String beanName, boolean allowEarlyReference) {        //spring所有的bean被放在ioc容器中的地方,就是这个singletonObjects,这是一个concorrentHashMap。Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {singletonObject = singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;}

但是我在这里只看到了get方法,那么这些bean是什么时候放到singletonObjects里的呢,我来找找

protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);this.reGISteredSingletons.add(beanName);}}

在DefaultSingletonBeanRegistry注册器中,我找到了singletonObjects.put方法,代表bean是这个时候被放到这个map里去的,接下来我在这行代码上进行条件断点,然后我们来看它的调用链,找出是什么时候执行的addSingleton方法,其实从这个时候我已经知道,断点打在测试方法的倒数第二行是不对的,在getBean之前其实代理对象已经产生了

spring aop底层原理及实现方法

// Create bean instance.if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, () -> {try {                            //创建bean,核心代码return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It might have been put there// eagerly by the creation process, to allow for circular reference resolution.// Also remove any beans that received a temporary reference to the bean.destroySingleton(beanName);throw ex;}});bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}

在createBean方法上,我也加上条件断点,然后debug进入

@Overrideprotected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {if (logger.isTraceEnabled()) {logger.trace("Creating instance of bean '" + beanName + "'");}RootBeanDefinition mbdToUse = mbd;// Make sure bean class is actually resolved at this point, and// clone the bean definition in case of a dynamically resolved Class// which cannot be stored in the shared merged bean definition.Class<?> resolvedClass = resolveBeanClass(mbd, beanName);if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {mbdToUse = new RootBeanDefinition(mbd);mbdToUse.setBeanClass(resolvedClass);}// Prepare method overrides.try {mbdToUse.prepareMethodOverrides();}catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),beanName, "Validation of method overrides failed", ex);}try {// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.Object bean = resolveBeforeInstantiation(beanName, mbdToUse);if (bean != null) {return bean;}}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,"BeanPostProcessor before instantiation of bean failed", ex);}try {            //核心代码,创建bean实例,需要断点进入Object beanInstance = doCreateBean(beanName, mbdToUse, args);if (logger.isTraceEnabled()) {logger.trace("Finished creating instance of bean '" + beanName + "'");}return beanInstance;}catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {// A previously detected exception with proper bean creation context already,// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.throw ex;}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);}}

接下来我debug进入doCreateBean方法

debug跟进initializeBean方法,条件断点在两个初始化处理器上,我隐约觉得代理对象就是从这两个方法中产生的,我们拭目以待

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {invokeAwareMethods(beanName, bean);}        //包装的beanObject wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {            //执行前置初始化beanPostProcessor处理器wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}if (mbd == null || !mbd.isSynthetic()) {            //执行初始化后的beanPostProcessor处理器wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;}

执行完applyBeanPostProcessorsBeforeInitialization方法,这个时候我们看到warppedBean还是indexDao,并没有产生代理对象

spring aop底层原理及实现方法

我猜想在下一个后置处理器中,代理对象将被创建,我debug进去

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {            //经过处理器处理后的bean,我先看看有多少个处理器Object current = processor.postProcessAfterInitialization(result, beanName);if (current == null) {return result;}result = current;}return result;}

spring aop底层原理及实现方法

可以看到我的猜想被证明是正确的,运行完这个后置处理器,代理对象就被创建出来了。 到了这里我们知道了代理对象是从哪里来的了,但是还是没搞清楚代理对象是怎么创建出来的,这时候我们就需要debug进入到这个处理器内部去瞧瞧了。

@Overridepublic Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {            //获取缓存key,不重要Object cacheKey = getCacheKey(bean.getClass(), beanName);if (!this.earlyProxyReferences.contains(cacheKey)) {                //重要方法,需要debug进去看return wrapifNecessary(bean, beanName, cacheKey);}}return bean;}

于是乎我又进到了wrapIfNecessary这个方法内部

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {return bean;}if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}// Create proxy if we have advice.        //看到上面这行注释,可以确定代理类就是从这里产生的,下面这个方法得到的都是一些包括切点信息,通知类型等等的信息Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);if (specificInterceptors != DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);            //顾名思义,创建代理,bebug进入看看Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,@Nullable Object[] specificInterceptors, TargetSource targetSource) {if (this.beanFactory instanceof ConfigurableListableBeanFactory) {AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);}ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.copyFrom(this);if (!proxyFactory.isProxyTargetClass()) {if (shouldProxyTargetClass(beanClass, beanName)) {proxyFactory.setProxyTargetClass(true);}else {evaluateProxyInterfaces(beanClass, proxyFactory);}}Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);proxyFactory.addAdvisors(advisors);proxyFactory.setTargetSource(targetSource);customizeProxyFactory(proxyFactory);proxyFactory.setFrozen(this.freezeProxy);if (advisorsPreFiltered()) {proxyFactory.setPreFiltered(true);}        //重要的地方在这里,代理对象是通过这个方法生成的return proxyFactory.getProxy(getProxyClassLoader());}    public Object getProxy(@Nullable ClassLoader classLoader) {        //debug进去看看return createAopProxy().getProxy(classLoader);}
protected final synchronized AopProxy createAopProxy() {if (!this.active) {activate();}        //同样需要debug进入看看return getAopProxyFactory().createAopProxy(this);}

我们看到这里有一个if语句,当config中的isOptimize和isProxyTargetClass还有hasNoUserSuppliedProxyInterfaces三个判断条件只要有一个满足的话,spring就会选择cglib的方式进行动态代理,而config中的两个boolean变量的默认值都是false,而我们的被代理对象又是实现接口的,所以spring会选择jdk动态代理的实现形式来完成动态代理,当然,我们也可以在这种情况下手动的配置config值来让spring选择cglib作为动态代理的实现方式,稍后我会演示

@Overridepublic AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {Class<?> targetClass = config.getTargetClass();if (targetClass == null) {throw new AopConfigException("TargetSource cannot determine target class: " +"Either an interface or a target is required for proxy creation.");}if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {return new JdkDynamicAopProxy(config);}return new ObjenesisCglibAopProxy(config);}else {            //现在知道为什么我们的代理类是动态代理了吗return new JdkDynamicAopProxy(config);}}

spring aop底层原理及实现方法

总结

我以spring aop实现的调用链图来结束这次的总结

spring aop底层原理及实现方法

以上是“spring aop底层原理及实现方法”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注编程网精选频道!

--结束END--

本文标题: spring aop底层原理及实现方法

本文链接: https://www.lsjlt.com/news/274385.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • spring aop底层原理及实现方法
    这篇文章主要介绍spring aop底层原理及实现方法,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!使用要分析spring aop的底层原理,首先要会使用,先创建一个普通maven webapp项目,引入spring...
    99+
    2023-06-14
  • spring aop底层原理及如何实现
    目录前言 使用 源码分析 总结 前言 相信每天工作都要用spring框架的大家一定使用过spring aop,aop的概念是面向切面编程,相对与传统的面向对象编程oop,aop更关...
    99+
    2022-11-12
  • Spring AOP底层原理及代理模式
    目录Spring AOP底层原理代理模式一、什么是 AOP二、AOP 底层原理1. 什么是代理?2. 什么是静态代理3. 什么是动态代理Spring AOP底层原理代理模式 一、什么...
    99+
    2022-11-13
  • Spring AOP底层原理及代理模式实例分析
    这篇文章主要介绍“Spring AOP底层原理及代理模式实例分析”,在日常操作中,相信很多人在Spring AOP底层原理及代理模式实例分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”S...
    99+
    2023-06-30
  • Go WaitGroup及Cond底层实现原理
    目录WaitGroup概念底层数据结构使用方法Cond概念底层数据结构使用方法WaitGroup 概念 Go标准库提供了WaitGroup原语, 可以用它来等待一批 Goroutin...
    99+
    2022-11-11
  • Spring Boot底层原理实例分析
    这篇“Spring Boot底层原理实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Spring ...
    99+
    2023-06-29
  • hashmap底层实现原理
    一、hashmap底层实现原理 HashMap是基于哈希表的Map接口的非同步实现。元素以键值对的形式存放,并且允许null键和null值,因为key值唯一(不能重复),因此,null键只有一个。另外,hashmap不保证元素存储的顺...
    99+
    2023-10-29
    底层 原理 hashmap
  • synchronized底层实现原理
    测试类: public class SynchronizedTest {     public void get() {         synchronized (this) { ...
    99+
    2022-11-13
  • Spring注解Autowired的底层实现原理详解
    目录一、Autowired注解的用法1、概述2、应用3、具体用法二、Autowired自动装配的过程一、Autowired注解的用法 1、概述 使用spring开发时,进行配置主要有...
    99+
    2022-11-13
    Spring注解Autowired原理 Spring注解Autowired Spring Autowired
  • spring注解的底层实现原理是什么
    Spring注解的底层实现原理主要依赖于Java的反射机制。在Spring中,通过使用注解来标识类、方法或字段,从而告诉Spring...
    99+
    2023-10-09
    spring
  • 【C++】多态的实现及其底层原理
    个人主页:🍝在肯德基吃麻辣烫 我的gitee:gitee仓库 分享一句喜欢的话:热烈的火焰,冰封在最沉默的火山深处。 文章目录 前言一、什么是多态?二、多态的构成条件2.1什么是虚函数?2.2虚函数的重...
    99+
    2023-08-17
    c++ 开发语言 多态
  • Javasynchronized底层的实现原理
    目录监视器底层实现执行流程总结前言: 想了解 synchronized 是如何运行的?就要先搞清楚 synchronized 是如何实现? synchronized 同步锁是通过 J...
    99+
    2022-11-13
  • HashMap的底层实现原理
    这篇文章主要介绍“HashMap的底层实现原理”,在日常操作中,相信很多人在HashMap的底层实现原理问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”HashMap的底层实现原理”的疑惑有所帮助!接下来,请跟...
    99+
    2023-06-04
  • Go底层channel实现原理及示例详解
    目录概念:使用场景:底层数据结构:操作:创建发送接收关闭案例分析:概念: Go中的channel 是一个队列,遵循先进先出的原则,负责协程之间的通信(Go 语言提倡不要通过共享内存来...
    99+
    2022-11-11
  • Java synchronized底层实现原理以及锁优化
    目录一、概述synchronized简介synchronized作用synchronized的使用二、实现原理三、理解Java对象头四、JVM对synchronized的锁优化1、偏...
    99+
    2022-11-13
  • 浅谈React底层实现原理
    目录1. props,state与render函数关系,数据和页面如何实现互相联动?2. React中的虚拟DOM常规思路改良思路(仍使用DOM)React的思路深入理解虚拟DOM3...
    99+
    2022-11-13
  • HashMap之keyset()方法底层原理解读
    目录HashMap之keyset() 方法底层原理HashMap (jdk1.8) keySet()方法详细注释keySet()注释KetSet内部类KeyIterator实现Ite...
    99+
    2023-03-22
    HashMap keyset()方法 keyset()方法底层原理 keyset()方法
  • python set()去重的底层原理及实例
    目录set是什么?set特点一、set去重简单实例二、重新set实现机制三、结论四、应用场景需求set是什么? 数学上,把set称做由不同的元素组成的集合,集合(set)的成员通常被...
    99+
    2022-11-12
  • Java LinkedHashMap 底层实现原理分析
    目录添加元素 删除元素 更新元素查找元素 其他方法 迭代器总结 在实现上,LinkedHashMap很多方法直接继承自HashMap,仅为维护双向链表覆写了部分方法。所以,要看懂 L...
    99+
    2022-11-12
  • Spring AOP实现原理以及如何进行CGLIB应用
    本篇文章给大家分享的是有关Spring AOP实现原理以及如何进行CGLIB应用,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。简介: AOP(Aspect Orien...
    99+
    2023-06-17
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作