spring注解驱动系列--AOP探究二

上篇中记录了AnnotationAwareAspectJAutoProxyCreator的创建以及注册,主要是

1、@EnableAspectJAutoProxy 注解会开启AOP功能

2、然后这个注解会往容器中注册一个AnnotationAwareAspectJAutoProxyCreator组件。

3、之后在容器创建过程中,注册后置处理器,创建AnnotationAwareAspectJAutoProxyCreator对象,这个也是一个后置处理器。

目录

一、finishBeanFactoryInitialization详解 

一、遍历获取容器中所有的Bean,依次创建对象getBean(beanName);

二、创建bean 

一、先从缓存中获取当前bean,如果能获取到,说明bean是之前被创建过的,直接使用,否则再创建;另外只要创建好的Bean都会被缓存起来

二、createBean();创建bean;

1、resolveBeforeInstantiation(beanName, mbdToUse);

二、resolveBeforeInstantiation详解

一、applyBeanPostProcessorsBeforeInstantiation

二、applyBeanPostProcessorsAfterInitialization

三、创建代理对象

一、每一个bean创建之前,都会调用postProcessBeforeInstantiation() 

一、 postProcessBeforeInstantiation源码讲解

二、isInfrastructureClass,判断是否是基础类型Advice、Pointcut、Advisor、AopInfrastructureBean,  或者是否是切面(@Aspect)

三、this.shouldSkip(beanClass, beanName)是否需要跳过

四、findCandidateAdvisors(获取所有的增强器)

 五、buildAspectJAdvisors

六、getAdvisors获取所有增强器

二、postProcessAfterInitialization

一 、postProcessAfterInitialization源码

一、wrapIfNecessary(包装目标类,如果需要的话),返回代理对象

getAdvicesAndAdvisorsForBean:获取当前Bean 的所有增强器(通知方法)

findEligibleAdvisors(找到合适的增强器)

findAdvisorsThatCanApply(找到能够应用的增强器)

静态方法findAdvisorsThatCanApply(找到能够应用的增强器)

canApply(能够应用的增强器) 

静态方法canApply(能够应用的增强器)

getClassFilter(获取切点表达式)

obtainPointcutExpression(获取切入点表达式)

buildPointcutExpression,解析表达式

matches(匹配当前类)

couldMatchJoinPointsInType(判断当前类是否可以匹配切入点),仅仅是去匹配当前类是否符合规则

 二、createProxy,创建代理对象

getProxy:取决于 createAopProxy 返回的是 CGlib 还是JDK 代理

createAopProxy

四、目标方法的执行

​ 一、CglibAopProxy.intercept();拦截目标方法的执行

二、根据ProxyFactory对象获取将要执行的目标方法拦截器链 

 一、ListinterceptorList保存所有拦截器,长度为5,遍历所有的增强器,将其转为Interceptor

二、getInterceptors获取所有的MethodInterceptor[]数组,也就是Interceptor拦截器数组,也就是最后的拦截器链

三、adapter.getInterceptor(advisor),转化MethodInterceptor逻辑​​​​​​​

三、如果没有拦截器链,直接执行目标方法

四、如果有拦截器链,把需要执行的目标对象,目标方法,拦截器链等信息传入创建一个 CglibMethodInvocation 对象,并调用 Object retVal =  mi.proceed();

五、执行拦截器链

一、proceed()

二、 proceed()里面的dm.interceptor.invoke(this)方法

五、最后做一个总结


一、finishBeanFactoryInitialization详解 

finishBeanFactoryInitialization(beanFactory)主要是完成BeanFactory初始化工作;创建剩下的单实例bean。之前有一部分bean在this.registerBeanPostProcessors(beanFactory);中就已经提前创建了。

一、遍历获取容器中所有的Bean,依次创建对象getBean(beanName);

一、代码进入流程:

1、finishBeanFactoryInitialization

2、beanFactory.preInstantiateSingletons();-》

3、if (isEagerInit) { this.getBean(beanName); }

二、创建对象流程:

getBean->doGetBean()->getSingleton()->
 

二、创建bean 

一、先从缓存中获取当前bean,如果能获取到,说明bean是之前被创建过的,直接使用,否则再创建;另外只要创建好的Bean都会被缓存起来

二、createBean();创建bean;

1、resolveBeforeInstantiation(beanName, mbdToUse);

解析BeforeInstantiation ,希望后置处理器在此能返回一个代理对象;如果能返回代理对象就使用,如果不能就继续

2、执行doCreateBean(beanName, mbdToUse, args)方法去真正的去创建一个bean实例

二、resolveBeforeInstantiation详解

创建bean之前,会从后置处理器中尝试获取一个代理对象,如果获取到了,就不会去创建bean对象了。

一、applyBeanPostProcessorsBeforeInstantiation

首先会去执行applyBeanPostProcessorsBeforeInstantiation这个方法

    protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {// 拿到所有后置处理器,如果是InstantiationAwareBeanPostProcessor;// 就执行postProcessBeforeInstantiationIterator var3 = this.getBeanPostProcessors().iterator();while(var3.hasNext()) {BeanPostProcessor bp = (BeanPostProcessor)var3.next();if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);if (result != null) {return result;}}}return null;}

 applyBeanPostProcessorsBeforeInstantiation:

遍历所有的后置处理器,如果对象是InstantiationAwareBeanPostProcessor,那么执行这个对象的postProcessBeforeInstantiation(beanClass, beanName)方法。

注意:InstantiationAwareBeanPostProcessor也是一个后置处理器,但是他与BeanPostProcessor不一样。

BeanPostProcessor:是在Bean对象创建完成初始化前后调用的

InstantiationAwareBeanPostProcessor:是在创建Bean实例之前先尝试用后置处理器返回对象的

也就是说AnnotationAwareAspectJAutoProxyCreator在所有bean创建之前会有一个拦截,InstantiationAwareBeanPostProcessor,会调用postProcessBeforeInstantiation()

1、SmartInstantiationAwareBeanPostProcessor继承了

InstantiationAwareBeanPostProcessor

2、AbstractAutoProxyCreator实现了SmartInstantiationAwareBeanPostProcessor

3、AnnotationAwareAspectJAutoProxyCreator继承了AbstractAutoProxyCreator

二、applyBeanPostProcessorsAfterInitialization

一、执行applyBeanPostProcessorsBeforeInstantiation,里面会执行一个postProcessBeforeInstantiation,这个方法会在第三大项AnnotationAwareAspectJAutoProxyCreator中讲解

二、之后会执行applyBeanPostProcessorsAfterInitialization方法,里面会执行postProcessAfterInitialization方法,这个方法也会在第三大项AnnotationAwareAspectJAutoProxyCreator中讲解

三、创建代理对象

AnnotationAwareAspectJAutoProxyCreator其实就是一个实现InstantiationAwareBeanPostProcessor接口的后置处理器

一、每一个bean创建之前,都会调用postProcessBeforeInstantiation() 

这里呢,只需要关注MathCalculator和LogAspect的创建就好,这是由于其他bean都不会产生代理对象。

1、判断当前bean是否在advisedBeans中(保存了所有需要增强bean)

2、判断当前bean是否是基础类型的Advice、Pointcut、Advisor、AopInfrastructureBean,
  或者是否是切面(@Aspect)

3、是否需要跳过

1)获取候选的增强器(切面里面的通知方法)【List<Advisor> candidateAdvisors】每一个封装的通知方法的增强器是 InstantiationModelAwarePointcutAdvisor;判断每一个增强器是否是 AspectJPointcutAdvisor 类型的;返回true

2)永远返回false

一、 postProcessBeforeInstantiation源码讲解

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {Object cacheKey = this.getCacheKey(beanClass, beanName);if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {// 判断当前bean是否在advisedBeans中(保存了所有需要增强bean)if (this.advisedBeans.containsKey(cacheKey)) {return null;}// 判断当前bean是否是基础类型的Advice、Pointcut、Advisor、AopInfrastructureBean,或者是否是切面(@Aspect)或者 是否需要跳过if (this.isInfrastructureClass(beanClass) //判断是不是需要跳过,如果返回true则就会将 这个 name 进行缓存// 这里其实是将 切面 Bean 的BeanName 缓存起来,代表这个 Bean 不进行 增强操作|| this.shouldSkip(beanClass, beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return null;}}// 如果我们有自定义的TargetSource,请在此处创建代理。// 禁止目标Bean的不必要的默认实例化: TargetSource 将以自定义方式处理目标实例。TargetSource targetSource = this.getCustomTargetSource(beanClass, beanName);if (targetSource != null) {if (StringUtils.hasLength(beanName)) {this.targetSourcedBeans.add(beanName);}Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);//创建代理对象Object proxy = this.createProxy(beanClass, beanName, specificInterceptors, targetSource);this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;} else {return null;}}

二、isInfrastructureClass,判断是否是基础类型Advice、Pointcut、Advisor、AopInfrastructureBean,  或者是否是切面(@Aspect)

    protected boolean isInfrastructureClass(Class<?> beanClass) {boolean retVal = Advice.class.isAssignableFrom(beanClass) || Pointcut.class.isAssignableFrom(beanClass) || Advisor.class.isAssignableFrom(beanClass) || AopInfrastructureBean.class.isAssignableFrom(beanClass);if (retVal && this.logger.isTraceEnabled()) {this.logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]");}return retVal;}

三、this.shouldSkip(beanClass, beanName)是否需要跳过

   protected boolean shouldSkip(Class<?> beanClass, String beanName) {// 获取候选的增强器(切面里面的通知方法)【List<Advisor> candidateAdvisors】// 每一个封装的通知方法的增强器是 InstantiationModelAwarePointcutAdvisor类型List<Advisor> candidateAdvisors = this.findCandidateAdvisors();Iterator var4 = candidateAdvisors.iterator();Advisor advisor;// 循环所有 增强器do {if (!var4.hasNext()) {// 这里基本返回 false..return super.shouldSkip(beanClass, beanName);}advisor = (Advisor)var4.next();//判断我们的增强器是不是 AspectJPointcutAdvisor 这个类型,并且 增强的名称和我们的BeanName 是一致} while(!(advisor instanceof AspectJPointcutAdvisor) || !((AspectJPointcutAdvisor)advisor).getAspectName().equals(beanName));return true;}// 父类的方法
protected boolean shouldSkip(Class<?> beanClass, String beanName) {// 判断是不是  原始的实例,也就是说是不需要进行代理的实例return AutoProxyUtils.isOriginalInstance(beanName, beanClass);
}static boolean isOriginalInstance(String beanName, Class<?> beanClass) {// 如果 BeanName 不正常 返回 false// beanName 的长度不是  bean全限定类名+ ORIGINAL_INSTANCE_SUFFIX(原始后缀),也返回 false// 也就是说这里基本会返回 false 那什么时候返回 True 呢 当我们的Bean 是全限定类名 + ORIGINAL_INSTANCE_SUFFIX 的时候...if (!StringUtils.hasLength(beanName) || beanName.length() !=beanClass.getName().length() + AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX.length()) {return false;}return (beanName.startsWith(beanClass.getName()) &&beanName.endsWith(AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX));
}

四、findCandidateAdvisors(获取所有的增强器)

注意这里由于下面的代码都是在

TargetSource targetSource = this.getCustomTargetSource(beanClass, beanName);

if (targetSource != null) {}

这段代码里面的,所以这里只有我们有自定义的TargetSource,才会在此处创建代理。否则会在postProcessAfterInitialization中创建代理

调用AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors()

1、调用父类的findCandidateAdvisors()方法获取的是 实现了 Advisor 接口的Bean

2、获取的是注解 切面里面所有的 Advisor,

   // AnnotationAwareAspectJAutoProxyCreator类下的//  获取所有  实现  Advisor 接口的类,protected List<Advisor> findCandidateAdvisors() {List<Advisor> advisors = super.findCandidateAdvisors();if (this.aspectJAdvisorsBuilder != null) {// 建立 切面增强器advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());}return advisors;}

 五、buildAspectJAdvisors

    public List<Advisor> buildAspectJAdvisors() {// 因为解析会很消耗性能,所以 Spring 会使用 aspectBeanNames 保存解析结果List<String> aspectNames = this.aspectBeanNames;// 如果==null 代表没处理过,因为第二次肯定不为 null,在 进入这个条件后,就会创建 ArrayListif (aspectNames == null) {// 进行加锁处理,防止多线程情况下一起操作解析synchronized (this) {// 二次赋值,防治以及操作过了aspectNames = this.aspectBeanNames;//双重非空判断,避免再次解析if (aspectNames == null) {List<Advisor> advisors = new ArrayList<>();// 创建切面集合aspectNames = new ArrayList<>();// 查找所有的 BeanName 包括父类String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);for (String beanName : beanNames) {//排除不合法的ban,由子类定义规则,默认返回trueif (!isEligibleBean(beanName)) {continue;}// 根据Name获取Class类型Class<?> beanType = this.beanFactory.getType(beanName);if (beanType == null) {continue;}// 判断 是否存在 @Aspect 注解 并且判断 目标类上所有的属性不包含 "ajc$"if (this.advisorFactory.isAspect(beanType)) {// 将 切面的 BeanName 放入到集合中aspectNames.add(beanName);// 包装成 AspectMetadataAspectMetadata amd = new AspectMetadata(beanType, beanName);//检查 @Aspect 注解的value值,验证生成的增强是否是单例if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {// 创建一个工厂..MetadataAwareAspectInstanceFactory factory =new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);// 获取标记 Aspect 注解的增强方法,获取所有增强器List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);//如果bean是单例,则缓存bean的增强器if (this.beanFactory.isSingleton(beanName)) {// 将 切面 BeanName 和 增强器 进行缓存this.advisorsCache.put(beanName, classAdvisors);}// bean非单例,只缓存bean对应的增强器创建工厂else {this.aspectFactoryCache.put(beanName, factory);}// 将获取的 增强器 放入到集合中advisors.addAll(classAdvisors);}else {// 切面创建模式非单例,这里的Else 基本不会进来...// 如果切面是非单例,但是bean是单例,抛出异常if (this.beanFactory.isSingleton(beanName)) {throw new IllegalArgumentException("Bean with name '" + beanName +"' is a singleton, but aspect instantiation model is not singleton");}MetadataAwareAspectInstanceFactory factory =new PrototypeAspectInstanceFactory(this.beanFactory, beanName);this.aspectFactoryCache.put(beanName, factory);//获取所有切面advisors.addAll(this.advisorFactory.getAdvisors(factory));}}}//将已经解析过的切面 Bean 进行缓存this.aspectBeanNames = aspectNames;return advisors;}}}// 如果是 null 就会直接返回...if (aspectNames.isEmpty()) {// 如果是一个空的就返回一个空集合return Collections.emptyList();}List<Advisor> advisors = new ArrayList<>();// 循环 切面的Namefor (String aspectName : aspectNames) {// 根据切面的Name 获取 增强器List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);if (cachedAdvisors != null) {advisors.addAll(cachedAdvisors);}else {MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);advisors.addAll(this.advisorFactory.getAdvisors(factory));}}// 返回~~~~return advisors;}

六、getAdvisors获取所有增强器

public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {// 获取 切面的 ClassClass<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();// 获取 切面的 NameString aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();// 对切面进行校验validate(aspectClass);// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator// so that it will only instantiate once.MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);List<Advisor> advisors = new ArrayList<>();// 获取 切面的所有方法,排除 @Pointcutfor (Method method : getAdvisorMethods(aspectClass)) {// Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect// to getAdvisor(...) to represent the "current position" in the declared methods list.// However, since Java 7 the "current position" is not valid since the JDK no longer// returns declared methods in the order in which they are declared in the source code.// Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods// discovered via reflection in order to support reliable advice ordering across JVM launches.// Specifically, a value of 0 aligns with the default value used in// AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).// 尝试解析每个方法,找到方法对应的切点和通知Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);if (advisor != null) {// 解析完后放入集合advisors.add(advisor);}}// 这里的分支一般不会走进..所以直接略过吧,别问,问了就是我大致略了一眼就不想看了if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);advisors.add(0, instantiationAdvisor);}// 处理 @DeclareParents  注解for (Field field : aspectClass.getDeclaredFields()) {Advisor advisor = getDeclareParentsAdvisor(field);if (advisor != null) {advisors.add(advisor);}}return advisors;
}

二、postProcessAfterInitialization

一 、postProcessAfterInitialization源码

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {// 判断这个对象是否创建成功..if (bean != null) {// 获取一个 key ,用于缓存..Object cacheKey = getCacheKey(bean.getClass(), beanName);if (this.earlyProxyReferences.remove(cacheKey) != bean) {// 这里就是去搞代理去了return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;
}
一、wrapIfNecessary(包装目标类,如果需要的话),返回代理对象

一、获取当前bean的所有增强器(通知方法)  getAdvicesAndAdvisorsForBean
1、找到候选的所有的增强器(找哪些通知方法是需要切入当前bean方法的),findCandidateAdvisors()

2、获取到能在当前bean使用的增强器。findAdvisorsThatCanApply

3、给增强器排序 this.sortAdvisors(eligibleAdvisors)

二、保存当前bean在advisedBeans中;

三、如果当前bean需要增强,创建当前bean的代理对象

1、获取所有增强器(通知方法)

2、保存到proxyFactory

3、创建代理对象:Spring自动决定
 JdkDynamicAopProxy(config);jdk动态代理;如果这个类有实现接口使用jdk
ObjenesisCglibAopProxy(config);cglib的动态代理;

四、给容器中返回当前组件使用cglib增强了的代理对象

五、以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {// 判断 beanName是正常的 并且 targetSourcedBeans 已经存在则会直接返回if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {return bean;}//判断 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.// 创建代理对象// 1. 获取当前Bean 的所有增强器(通知方法)Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);// 如果不是 null 则会去生成代理对象,否则则标记当前类不需要进行代理.if (specificInterceptors != DO_NOT_PROXY) {// 将其放入到集合当中代表已经增强过了...this.advisedBeans.put(cacheKey, Boolean.TRUE);// 创建代理Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));// 将数据进行缓存this.proxyTypes.put(cacheKey, proxy.getClass());// 返回代理对象...return proxy;}// 如果不需要代理则设置为 False 当下次进来的时候会直接返回(细节)this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;
}
getAdvicesAndAdvisorsForBean:获取当前Bean 的所有增强器(通知方法)
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {//获取这个类型的所有增强器List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);// 如果是一个空的 则返回 一个空的 数组if (advisors.isEmpty()) {return DO_NOT_PROXY;}// 将其转换成数组返回return advisors.toArray();
}
findEligibleAdvisors(找到合适的增强器)
    protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {//获取所有的增强器,这里之前已经分析过了就不分析了..List<Advisor> candidateAdvisors = findCandidateAdvisors();//找到适合的增强器List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);extendAdvisors(eligibleAdvisors);if (!eligibleAdvisors.isEmpty()) {// 对增强器进行 排序eligibleAdvisors = sortAdvisors(eligibleAdvisors);}return eligibleAdvisors;}
findAdvisorsThatCanApply(找到能够应用的增强器)
protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {ProxyCreationContext.setCurrentProxiedBeanName(beanName);try {// 返回当前Bean能用的增强器return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);}finally {ProxyCreationContext.setCurrentProxiedBeanName(null);}
}
静态方法findAdvisorsThatCanApply(找到能够应用的增强器)
    public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {// 如果是空..就直接返回..if (candidateAdvisors.isEmpty()) {return candidateAdvisors;}//存放 合格的 增强器List<Advisor> eligibleAdvisors = new ArrayList<>();//循环所有的增强器for (Advisor candidate : candidateAdvisors) {//判断类型是不是整个类型的if (candidate instanceof IntroductionAdvisor// 去应用..&& canApply(candidate, clazz)) {eligibleAdvisors.add(candidate);}}boolean hasIntroductions = !eligibleAdvisors.isEmpty();// 循环所有的增强器for (Advisor candidate : candidateAdvisors) {//判断如果是这个类型的就跳过,因为上个循环已经处理过了if (candidate instanceof IntroductionAdvisor) {// already processedcontinue;}// 判断是不是能用的增强器,如果是能用的则添加到集合当中去if (canApply(candidate, clazz, hasIntroductions)) {eligibleAdvisors.add(candidate);}}return eligibleAdvisors;}
canApply(能够应用的增强器) 
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {// 判断 是不是这个类型的if (advisor instanceof IntroductionAdvisor) {return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);}// 判断 是不是这个类型的else if (advisor instanceof PointcutAdvisor) {PointcutAdvisor pca = (PointcutAdvisor) advisor;// 判断切入点表达式是否匹配return canApply(pca.getPointcut(), targetClass, hasIntroductions);}else {// 它没有切入点,因此我们假设它适用。return true;}
}
静态方法canApply(能够应用的增强器)
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {Assert.notNull(pc, "Pointcut must not be null");//  这一步会去解析 切入点表达式...if (!pc.getClassFilter().matches(targetClass)) {return false;}MethodMatcher methodMatcher = pc.getMethodMatcher();if (methodMatcher == MethodMatcher.TRUE) {// No need to iterate the methods if we're matching any method anyway...return true;}IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;if (methodMatcher instanceof IntroductionAwareMethodMatcher) {introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;}Set<Class<?>> classes = new LinkedHashSet<>();// 判断是否是 Proxy 的子类并且 proxyClassCache 存在 这个类if (!Proxy.isProxyClass(targetClass)) {classes.add(ClassUtils.getUserClass(targetClass));}// 返回当前类的所实现的所有的接口..classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));for (Class<?> clazz : classes) {// 获取当前类上包括父类的所有方法Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);// 循环所有方法for (Method method : methods) {if (introductionAwareMethodMatcher != null ?introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :methodMatcher.matches(method, targetClass)) {return true;}}}return false;
}
getClassFilter(获取切点表达式)
public ClassFilter getClassFilter() {obtainPointcutExpression();return this;
}
obtainPointcutExpression(获取切入点表达式)
private PointcutExpression obtainPointcutExpression() {// 如果表达式不存在 抛出异常...if (getExpression() == null) {throw new IllegalStateException("Must set property 'expression' before attempting to match");}// 如果 切入点表达式 是null 去进行解析,因为我们的表达式可能是 通过@Pointcut 的方式if (this.pointcutExpression == null) {this.pointcutClassLoader = determinePointcutClassLoader();this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);}return this.pointcutExpression;
}
buildPointcutExpression,解析表达式
    private PointcutExpression buildPointcutExpression(@Nullable ClassLoader classLoader) {// 初始化基础的Aspect切入点解析器PointcutParser parser = initializePointcutParser(classLoader);// 获取切入点参数...PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length];for (int i = 0; i < pointcutParameters.length; i++) {// 将参数和类型包装一下 放入到数组中pointcutParameters[i] = parser.createPointcutParameter(this.pointcutParameterNames[i], this.pointcutParameterTypes[i]);}// 这里嵌套了3个方法....而且还异常复杂我都不忍心看...return parser.parsePointcutExpression(replaceBooleanOperators(resolveExpression()),this.pointcutDeclarationScope, pointcutParameters);}
private String resolveExpression() {// 获取表达式String expression = getExpression();Assert.state(expression != null, "No expression set");// 返回表达式return expression;
}
private String replaceBooleanOperators(String pcExpr) {// 将表达式中的 and 替换String result = StringUtils.replace(pcExpr, " and ", " && ");// 将表达式中的 or 替换result = StringUtils.replace(result, " or ", " || ");// 将表达式中的 not 替换result = StringUtils.replace(result, " not ", " ! ");return result;
}
public PointcutExpression parsePointcutExpression(String expression, Class<?> inScope, PointcutParameter[] formalParameters)throws UnsupportedPointcutPrimitiveException, IllegalArgumentException {PointcutExpressionImpl pcExpr = null;try {// 这里是对表达式的进行处理,具体的可以自己深究去Pointcut pc = resolvePointcutExpression(expression, inScope, formalParameters);// 将表达式具体化,比如我使用的是 @Before("方法()") 这里是去将 "方法()" 转换成具体的 表达式pc = concretizePointcutExpression(pc, inScope, formalParameters);// again, because we have now followed any ref'd pcutsvalidateAgainstSupportedPrimitives(pc, expression);// 包装成 对象返回pcExpr = new PointcutExpressionImpl(pc, expression, formalParameters, getWorld());} catch (ParserException pEx) {throw new IllegalArgumentException(buildUserMessageFromParserException(expression, pEx));} catch (ReflectionWorld.ReflectionWorldException rwEx) {throw new IllegalArgumentException(rwEx.getMessage());}return pcExpr;
}
matches(匹配当前类)
public boolean matches(Class<?> targetClass) {// 这里是去获取 切入点表达式.. 也包括了解析(这里其实在 getClassFilter) 已经解析过了~~PointcutExpression pointcutExpression = obtainPointcutExpression();try {try {//根据表达式的解析实例,验证此类是否匹配return pointcutExpression.couldMatchJoinPointsInType(targetClass);}catch (ReflectionWorldException ex) {logger.debug("PointcutExpression matching rejected target class - trying fallback expression", ex);// Actually this is still a "maybe" - treat the pointcut as dynamic if we don't know enough yetPointcutExpression fallbackExpression = getFallbackPointcutExpression(targetClass);if (fallbackExpression != null) {return fallbackExpression.couldMatchJoinPointsInType(targetClass);}}}catch (Throwable ex) {logger.debug("PointcutExpression matching rejected target class", ex);}return false;
}
couldMatchJoinPointsInType(判断当前类是否可以匹配切入点),仅仅是去匹配当前类是否符合规则
public boolean couldMatchJoinPointsInType(Class aClass) {ResolvedType matchType = world.resolve(aClass.getName());if (matchType.isMissing() && (world instanceof ReflectionWorld)) {// Class is a generated class that cannot be 'looked up' via getResource.// For example a proxy or lambda.// Use the class itself in this casematchType = ((ReflectionWorld)world).resolveUsingClass(aClass);}ReflectionFastMatchInfo info = new ReflectionFastMatchInfo(matchType, null, this.matchContext, world);//根据切入点和 目标类,判断类 package 是否匹配boolean couldMatch = pointcut.fastMatch(info).maybeTrue();return couldMatch;
}

上面主要是为了去进行匹配符合规则的类,当匹配成功的时候才会去创建代理对象

 二、createProxy,创建代理对象
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();// 将当前类的一些配置进行 复制 ,简单来说就是获取 XML 或者注解配置的属性..// 这里可以参考一下:proxyFactory.copyFrom(this);// 判断是否是通过接口 默认是 Falseif (!proxyFactory.isProxyTargetClass()) {//根据最开始@EnableAspectJAutoProxy注解中的proxyTargetClass参数判断是否应该使用cglib代理if (shouldProxyTargetClass(beanClass, beanName)) {//标识 使用cglib动态代理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());
}
getProxy:取决于 createAopProxy 返回的是 CGlib 还是JDK 代理
public Object getProxy(@Nullable ClassLoader classLoader) {// createAopProxy() 获取AOP 工厂判断 CGlib还是JDKreturn createAopProxy().getProxy(classLoader);
}protected final synchronized AopProxy createAopProxy() {if (!this.active) {activate();}// 获取到 AOP 代理工厂// 然后判断 是 Cglib 还是JDKreturn getAopProxyFactory().createAopProxy(this);
}
createAopProxy
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {if (!IN_NATIVE_IMAGE &&(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {//  optimize  默认是 false//  ProxyTargetClass 默认是 false//  hasNoUserSuppliedProxyInterfaces 被代理的类没有实现接口// 获取目标 ClassClass<?> targetClass = config.getTargetClass();// 判断当前类是不是接口if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {return new JdkDynamicAopProxy(config);}return new ObjenesisCglibAopProxy(config);}else {return new JdkDynamicAopProxy(config);}
}

四、目标方法的执行

容器中保存了组件的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如增强器,目标对象,xxx)

 一、CglibAopProxy.intercept();拦截目标方法的执行

从目标方法执行中进去是CglibAopProxy对象中的intercept()方法,拦截目标方法的执行。

二、根据ProxyFactory对象获取将要执行的目标方法拦截器链 

  List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

 一、List<Object> interceptorList保存所有拦截器,长度为5,遍历所有的增强器,将其转为Interceptor

一个默认的ExposeInvocationInterceptor 和 4个增强器;

 public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass) {AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();Advisor[] advisors = config.getAdvisors();// 保存所有拦截器,长度为5List<Object> interceptorList = new ArrayList(advisors.length);Class<?> actualClass = targetClass != null ? targetClass : method.getDeclaringClass();Boolean hasIntroductions = null;Advisor[] var9 = advisors;int var10 = advisors.length;// 循环之前获取到的所有增强方法for(int var11 = 0; var11 < var10; ++var11) {Advisor advisor = var9[var11];// 如果类型是PointcutAdvisor,进入此逻辑if (advisor instanceof PointcutAdvisor) {PointcutAdvisor pointcutAdvisor = (PointcutAdvisor)advisor;if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();boolean match;if (mm instanceof IntroductionAwareMethodMatcher) {if (hasIntroductions == null) {hasIntroductions = hasMatchingIntroductions(advisors, actualClass);}match = ((IntroductionAwareMethodMatcher)mm).matches(method, actualClass, hasIntroductions);} else {match = mm.matches(method, actualClass);}if (match) {// 将增强方法转换成MethodInterceptorMethodInterceptor[] interceptors = registry.getInterceptors(advisor);if (mm.isRuntime()) {MethodInterceptor[] var17 = interceptors;int var18 = interceptors.length;for(int var19 = 0; var19 < var18; ++var19) {MethodInterceptor interceptor = var17[var19];interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));}} else {interceptorList.addAll(Arrays.asList(interceptors));}}}// IntroductionAdvisor类型进入} else if (advisor instanceof IntroductionAdvisor) {IntroductionAdvisor ia = (IntroductionAdvisor)advisor;if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {Interceptor[] interceptors = registry.getInterceptors(advisor);interceptorList.addAll(Arrays.asList(interceptors));}} else {// 直接转换为MethodInterceptor放入拦截器数组中,然后放入拦截器链集合Interceptor[] interceptors = registry.getInterceptors(advisor);interceptorList.addAll(Arrays.asList(interceptors));}}return interceptorList;}

二、getInterceptors获取所有的MethodInterceptor[]数组,也就是Interceptor拦截器数组,也就是最后的拦截器链

 public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {List<MethodInterceptor> interceptors = new ArrayList(3);Advice advice = advisor.getAdvice();// 如果增强器实现了MethodInterceptor,也就是是MethodInterceptor类型的直接加入if (advice instanceof MethodInterceptor) {interceptors.add((MethodInterceptor)advice);}Iterator var4 = this.adapters.iterator();while(var4.hasNext()) {AdvisorAdapter adapter = (AdvisorAdapter)var4.next();// 如果是前置通知、返回通知、异常通知,则进入下面进行适配器转换成MethodInterceptorif (adapter.supportsAdvice(advice)) {interceptors.add(adapter.getInterceptor(advisor));}}if (interceptors.isEmpty()) {throw new UnknownAdviceTypeException(advisor.getAdvice());} else {return (MethodInterceptor[])interceptors.toArray(new MethodInterceptor[0]);}}

三、adapter.getInterceptor(advisor),转化MethodInterceptor逻辑

1、如果是MethodInterceptor,直接加入到集合中

2、如果不是,使用AdvisorAdapter将增强器转为MethodInterceptor, 转换完成返回MethodInterceptor数组;一般前置通知、返回通知、异常通知会走这一步,

if (adapter.supportsAdvice(advice)) {interceptors.add(adapter.getInterceptor(advisor));
}

其中adapter.getInterceptor(advisor)有三个实现类,前置通知、返回通知、异常通知实现类

前置通知转换实现类,MethodBeforeAdviceAdapter 


class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {MethodBeforeAdviceAdapter() {}public boolean supportsAdvice(Advice advice) {return advice instanceof MethodBeforeAdvice;}public MethodInterceptor getInterceptor(Advisor advisor) {// 其实就是一个强转,再封装MethodBeforeAdvice advice = (MethodBeforeAdvice)advisor.getAdvice();return new MethodBeforeAdviceInterceptor(advice);}
}

 MethodBeforeAdviceInterceptor 再次封装对象,也就是把MethodBeforeAdvice作为成员对象放进去,然后在执行目标方法前调用。其他返回通知则是在执行完方法返回时执行。

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {private final MethodBeforeAdvice advice;public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {Assert.notNull(advice, "Advice must not be null");this.advice = advice;}public Object invoke(MethodInvocation mi) throws Throwable {this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());return mi.proceed();}
}

三、如果没有拦截器链,直接执行目标方法

拦截器链(每一个通知方法又被包装为方法拦截器,利用MethodInterceptor机制),

retVal = methodProxy.invoke(target, argsToUse);

直接执行目标方法

四、如果有拦截器链,把需要执行的目标对象,目标方法,拦截器链等信息传入创建一个 CglibMethodInvocation 对象,并调用 Object retVal =  mi.proceed();

    if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);// 直接执行拦截的目标方发生retVal = methodProxy.invoke(target, argsToUse);} else {// 如果有有拦截器链,把需要执行的目标对象,目标方法,拦截器链等信息传入创建一个 CglibMethodInvocation 对象,并调用 proceed(),逐个执行拦截器,这里其实就是触发拦截器链的执行retVal = (new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed();}

五、执行拦截器链

一、proceed()

public Object proceed() throws Throwable {/**currentInterceptorIndex 默认为-1,this.interceptorsAndDynamicMethodMatchers就是增强方法的数量,也就是拦截器连的长度这里意思就是当拦截器链执行到最后一个时,也就是0 - 1 等于currentInterceptorIndex时,也就是如果没有拦截器执行执行目标方法,或者拦截器的索引和拦截器数组-1大小一样(指定到了最后一个拦截器)执行目标方法**/if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {return this.invokeJoinpoint();} else {// 拿到第++this.currentInterceptorIndex 个拦截器,-1,0,1,2这种顺序Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;/* 上面进行一系列类型判断,然后调用拦截器的invoke方法,传入this然后点击dm.interceptor.invoke(this),发现回去执行MethodBeforeAdviceInterceptor对象里面的invoke方法*/Class<?> targetClass = this.targetClass != null ? this.targetClass : this.method.getDeclaringClass();return dm.methodMatcher.matches(this.method, targetClass, this.arguments) ? dm.interceptor.invoke(this) : this.proceed();} else {return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);}}
}

二、 proceed()里面的dm.interceptor.invoke(this)方法

dm.interceptor.invoke(this)有多个实现类,

 

会按照这个顺序去执行拦截器

 1、首先会去执行ExposeInvocationInterceptor对象的invoke方法,执行mi.proceed();会发现,又再一次进入了一里面的proceed()方法里,只不过这个时候,索引变了。currentInterceptorIndex变为了0,interceptorsAndDynamicMethodMatchers将少了一个,再次调用invoke方法,进入2

public Object invoke(MethodInvocation mi) throws Throwable {MethodInvocation oldInvocation = (MethodInvocation)invocation.get();invocation.set(mi);Object var3;try {var3 = mi.proceed();} finally {invocation.set(oldInvocation);}return var3;
}

2、执行AspectJAfterThrowingAdvice拦截器里面的invoke方法,然后进入mi.proceed(),currentInterceptorIndex变为了1,interceptorsAndDynamicMethodMatchers将少了一个,再次调用invoke方法,进入3

public Object invoke(MethodInvocation mi) throws Throwable {try {return mi.proceed();} catch (Throwable var3) {if (this.shouldInvokeOnThrowing(var3)) {this.invokeAdviceMethod(this.getJoinPointMatch(), (Object)null, var3);}throw var3;}
}

3、然后 AfterReturningAdviceInterceptor里面的invoke方法,再次进入mi.proceed()里面,currentInterceptorIndex变为了2,interceptorsAndDynamicMethodMatchers将少了一个,再次调用invoke方法,进入4

public Object invoke(MethodInvocation mi) throws Throwable {Object retVal = mi.proceed();this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());return retVal;
}

4、然后在AspectJAfterAdvice中的invoke方法执行mi.proceed(),然后currentInterceptorIndex变为了3,interceptorsAndDynamicMethodMatchers将少了一个,再次调用一个拦截器

public Object invoke(MethodInvocation mi) throws Throwable {Object var2;try {var2 = mi.proceed();} finally {this.invokeAdviceMethod(this.getJoinPointMatch(), (Object)null, (Throwable)null);}return var2;
}

5、然后拿到最后一个拦截器MethodBeforeAdviceInterceptor,执行里面的invoke方法,会先执行 this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());,currentInterceptorIndex变为了4,interceptorsAndDynamicMethodMatchers将少了一个也就是5-1,再次调用invoke方法

1、执行前置通知方法

2、然后调用mi.proceed();,进去发现currentInterceptorIndex = interceptorsAndDynamicMethodMatchers的大小了,然后直接执行proceed()里面的this.invokeJoinpoint();方法,这个方法是利用反射执行目标方法。

3、然后执行完以后,会返回上一个拦截器,AspectJAfterAdvice继续执行剩下逻辑,也就是finally里面的方法,意思就是不管有没有异常都执行invokeAdviceMethod方法,也就是后置通知。

4、再返回到AfterReturningAdviceInterceptor继续执行剩下的逻辑,但是如果mi.proceed()执行抛出异常,AfterReturningAdviceInterceptor并没有进行catch处理,而是直接抛出给上一层AspectJAfterThrowingAdvice处理。如果没有出现异常,AfterReturningAdviceInterceptor将会在mi.proceed()执行后执行afterReturning方法,也就是返回通知。

5、也就是说出现异常AspectJAfterThrowingAdvice处理,没有出现异常AfterReturningAdviceInterceptor处理。这是由于AfterReturningAdviceInterceptor有进行catch处理,执行里面的invokeAdviceMethod异常通知

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {private final MethodBeforeAdvice advice;public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {Assert.notNull(advice, "Advice must not be null");this.advice = advice;}public Object invoke(MethodInvocation mi) throws Throwable {this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());return mi.proceed();}
}

6、整个调用链执行也就是,链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行;拦截器链的机制,保证通知方法与目标方法的执行顺序; 

五、最后做一个总结

 一、@EnableAspectJAutoProxy 开启AOP功能

二、@EnableAspectJAutoProxy 会给容器中注册一个组件 AnnotationAwareAspectJAutoProxyCreator

三、AnnotationAwareAspectJAutoProxyCreator是一个后置处理器;

四、容器的创建流程:

        1、registerBeanPostProcessors()注册后置处理器;创建AnnotationAwareAspectJAutoProxyCreator对象
        2、finishBeanFactoryInitialization()初始化剩下的单实例bean
                1)、创建业务逻辑组件和切面组件
                2)、AnnotationAwareAspectJAutoProxyCreator拦截组件的创建过程
                3)、组件创建完之后,判断组件是否需要增强
                     是:切面的通知方法,包装成增强器(Advisor);给业务逻辑组件创建一个代理对象(cglib);

五、执行目标方法:

        1、代理对象执行目标方法
        2、CglibAopProxy.intercept();

                1)、得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)
                2)、利用拦截器的链式机制,依次进入每一个拦截器进行执行;
                3)、执行顺序:
                        正常执行:前置通知-》目标方法-》后置通知-》返回通知
                        出现异常:前置通知-》目标方法-》后置通知-》异常通知
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/768047.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于四篇GNN论文的阅读笔记PPT:包括GATNE,AM-GCN,HGSL和coGSL

关于四篇GNN论文的阅读笔记PPT&#xff1a;包括GATNE&#xff0c;AM-GCN&#xff0c;HGSL和coGSL 前言GATNEAM-GCNHGSLcoGSL 前言 这里的PPT主要是在跟Graph Transformer一起的&#xff1a; 【图-注意力笔记&#xff0c;篇章1】Graph Transformer&#xff1a;包括Graph Trans…

mysql基础3索引

存储引擎 存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现方式 。存储引擎是基于表的&#xff0c;而不是 基于库的&#xff0c;所以存储引擎也可被称为表类型。 1). 建表时指定存储引擎 CREATE TABLE 表名(字段1 字段1类型 [ COMMENT 字段1注释 ] ,......字段n…

JAVA的学习日记DAY4

算术运算符 关系运算符&#xff08;比较运算符&#xff09; 关系运算符的结果都是boolean型&#xff0c;也就是要么是true&#xff0c;要么是false 关系表达式 经常用在if结构的条件中或循环结构的条件中 逻辑运算符 && 和 & 使用区别 &&短路与&#xff…

python学习9:python的代码中的数据类型转换

python中数据类型的转换 1.为什么需要转换类型呢&#xff1f; 数据类型之间&#xff0c;在特定的场景下&#xff0c;是可以相互转换的&#xff0c;如字符串转数字&#xff0c;数字转字符串等&#xff1b;数据类型转换&#xff0c;在以后是我们经常使用到的功能&#xff0c;例如…

五、分布式锁-redission

源码仓库地址&#xff1a;gitgitee.com:chuangchuang-liu/hm-dingping.git 1、redission介绍 目前基于redis的setnx特性实现的自定义分布式锁仍存在的问题&#xff1a; 问题描述重入问题同一个线程无法多次获取统一把锁。当方法A成功获取锁后&#xff0c;调用方法B&#xff0…

腾讯云服务器价格查询系统,2024年1年、3年和5年活动价格表

腾讯云服务器多少钱一年&#xff1f;61元一年起。2024年最新腾讯云服务器优惠价格表&#xff0c;腾讯云轻量2核2G3M服务器61元一年、2核2G4M服务器99元一年可买三年、2核4G5M服务器165元一年、3年756元、轻量4核8M12M服务器646元15个月、4核16G10M配置32元1个月、312元一年、8核…

Java生成动态图形验证码

dome /*** ClassName : VerifyCodeController* Description : 图片验证码* Author : llh* Date: 2024-03-22 10:48*/ Controller RequestMapping("/verifycode") public class VerifyCodeController {Resourceprivate StringRedisTemplate stringRedisTemplate;Get…

YOLOv8:Roboflow公开数据集训练模型

Roboflow公开数据集 Roboflow是一个提供计算机视觉数据集管理和处理工具的平台。虽然Roboflow本身并不创建或策划公开数据集&#xff0c;但它提供了一系列功能&#xff0c;帮助用户组织、预处理、增强和导出计算机视觉数据集。 官方网站&#xff1a;https://universe.roboflow…

求解完全背包问题

10.求解完全背包问题 - 蓝桥云课 (lanqiao.cn) import os import sys# 请在此输入您的代码 taotal_w,nmap(int,input().split()) w[] v[] dp[0]*(taotal_w1) #物品无限使用不用考虑 for i in range(n):wi,vimap(int,input().split())w.append(wi)v.append(vi)for i in range(n…

C++String类

1. 前言 String是C中操作字符串的类&#xff0c;它是在比较早的时候设计的STL模板&#xff0c;因此在某些地方设计的有些冗余 对于String类&#xff0c;不仅仅是学会使用它&#xff0c;更重要的是要从底层去理解它&#xff1b;本篇文章将从底层出发&#xff0c;模拟实现常用的S…

2024年阿里云服务器价格查询系统,最新报价

2024年腾讯云服务器优惠价格表&#xff0c;一张表整理阿里云服务器最新报价&#xff0c;阿里云服务器网整理云服务器ECS和轻量应用服务器详细CPU内存、公网带宽和系统盘详细配置报价单&#xff0c;大家也可以直接移步到阿里云CLUB中心查看 aliyun.club 当前最新的云服务器优惠券…

反激电源进阶及充电器基础认知

前言 反激开关电源核心工作原理&#xff0c;学会了这个原理&#xff0c;就代表着你的双脚已经全部跨入了开关电源世界的大门了。_哔哩哔哩_bilibili 最近不小心看了上面这个视频&#xff0c;有点感觉。 本文是 从开关电源&#xff08;BMS充电器&#xff09;入门硬件之——开…

代码随想录|Day26|贪心01|455.分发饼干、376.摆动序列、53.最大子数组和

455.分发饼干 大尺寸的饼干既可以满足胃口大的孩子也可以满足胃口小的孩子。 局部最优&#xff1a;尽量确保每块饼干被充分利用 全局最优&#xff1a;手上的饼干可以满足尽可能多的孩子 思路&#xff1a;大饼干 尽量分给 大胃口孩子 将小孩和饼干数组排序&#xff0c;我们从大到…

洛谷day3

B2053 求一元二次方程 - 洛谷 掌握printf用法&#xff1b; #include <iostream> #include <cmath> using namespace std; double a,b,c; double delta; double x1,x2;int main() {cin>>a>>b>>c;delta b*b-4*a*c;if(delta>0){x1 (-bsqrt…

ensp ppp验证实验(二)

实验拓扑&#xff1a; 1、R1和R2使用PPP链路直连&#xff0c;R2和R3把2条PPP链路捆绑为PPP MP直连 2、按照图示配置IP地址 3、R2对R1的PPP进行单向chap验证 4、R2和R3的PPP进行双向chap验证 实验内容&#xff1a; R1配置&#xff1a; #修改名称 <Huawei>sys Enter …

一些规律、现象

图文部分由COPILOT生成。 规律详情 墨菲定律 墨菲定律(Murphys Law) 一件事可能出错时就一定会出错。 图&#xff1a;AI生成 破窗效应 破窗效应(Broken windows theory&#xff09;是犯罪心理学理论。以一幢有少许破窗的建筑为例&#xff0c;如果那些窗没修理好&#xff0…

ShardingSphere水平分表——开发经验(2)

1. 什么场景下分表&#xff1f; 数据量过大或者数据库表对应的磁盘文件过大。 Q&#xff1a;多少数据分表&#xff1f; A&#xff1a;网上有人说1kw&#xff0c;2kw&#xff1f;不准确。 1、一般看字段的数量&#xff0c;有没有包含text类型的字段。我们的主表里面是不允许有t…

从零开始学HCIA之网络基础知识02

1、TCP/IP&#xff08;Transmission Control Protocol/Internet Protocol&#xff09;参考模型&#xff0c;它是当下实际的业界标准。 2、TCP/IP这个名字来自该协议簇中两个非常重要的协议&#xff0c;一个是IP&#xff08;Internet Protocol&#xff09;&#xff0c;另一个是T…

Go 限流器-漏桶 VS 令牌桶 常用包原理解析

本文主要介绍两个包Uber漏桶&#xff0c;time/rate令牌桶 可以了解到&#xff1a; 使用方法漏桶/令牌桶 两种限流思想 and 实现原理区别及适用场景应用Case 背景 我们为了保护系统资源&#xff0c;防止过载&#xff0c;常常会使用限流器。 使用场景&#xff1a; API速率限制…

带3090显卡的Linux服务器上部署SDWebui

背景 一直在研究文生图&#xff0c;之前一直是用原始模型和diffuser跑SD模型&#xff0c;近来看到不少比较博主在用 SDWebui&#xff0c;于是想着在Linux服务器上部署体验一下&#xff0c;谁知道并没有想象的那么顺利&#xff0c;还是踩了不少坑。记录一下过程&#xff0c;也许…